package jp.co.nri.rid.search;

/* misc */
import java.awt.Color;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

/* Rid */
import jp.co.nri.Rid;
import jp.co.nri.rid.RUpdateManager;
import jp.co.nri.rid.doc.RidDocumentSite;
import jp.co.nri.rid.doc.RidElementPage;
import jp.co.nri.rid.xml.elementBooster;
import jp.co.iti.fagot.util.ZInstance;

/**
 * 孤立ページ検索結果表示テーブルのデータモデル
 */
class SPTableModelIsolated extends SPTableModel{
    /** SCCS ID */
    private static final String SCCSID = "@(#)SPTableModelIsolated.java";

    /** RCS ID */
    private static final String RCSID =
	"$Id: SPTableModelIsolated.java,v 1.16 2003-07-22 20:23:03+09 nsmr Exp $";

    boolean changeIconColorCheckBoxIsSelected;
    Color selectColorButtonBackground;

    /** LinkUnit をリンク元によって分類した Vector 群を、
     *  リンク元をキーにしてハッシュテーブル化 
     */
    Hashtable linkUnitsHash;

    /**
     * コンストラクタ:
     */
    SPTableModelIsolated(boolean changeIconColorCheckBoxIsSelected,
                         Color selectColorButtonBackground) {
        target = SPTableModel.ISOLATED;

        this.changeIconColorCheckBoxIsSelected =
            changeIconColorCheckBoxIsSelected;
        this.selectColorButtonBackground = selectColorButtonBackground;

        count = searchIsolatedPages();
    } /* SPTableModelIsolated */


    /**
     * トップページからは、リンクをたどってたどり着けないページを探索する
     * @return 見つかったページ数
     */
    private int searchIsolatedPages(){
        resultVector = new Vector();

        /* DOCUMENT_SITE の取得 */
        RidDocumentSite siteDoc =
            (RidDocumentSite)ZInstance.map().get(Rid.DOCUMENT_SITE);
        if (siteDoc == null) {
            debugOut("DOCUMENT_SITE が見つかりません");
            return 0;
        }

        /* トップページの取得 */
        RidElementPage topPageElem = siteDoc.getTopPage(Rid.PANEL_SEARCH);
        if (topPageElem == null) {
            return 0;
        }

        /* トップページのファイル名を取得 */
        String topPageName = topPageElem.getAttribute("File");
        if (topPageName == null) {
            debugOut("トップページに File アトリビュートがありません");
            return 0;
        }
        debugOut("top page: " + topPageName);

        /* DOCUMENT_SITE の PaegUnit をすべて取得 */
        elementBooster[] pageUnits =
            getElementsFromDocument("PageUnit", Rid.DOCUMENT_SITE);
        /* ハッシュのキーは、ファイル名を小文字に変換したもの */
        SPElementStatusHash pageUnitHash =
            new SPElementStatusHash(pageUnits, true);

        /* DOCUMENT_SITE の LinkUnit をすべて取得 */
        elementBooster[] linkUnits =
            getElementsFromDocument("LinkUnit", Rid.DOCUMENT_SITE);
        /* ハッシュのキーは、リンク元のファイル名を小文字に変換したもの */
        linkUnitsHash = getElementVectorHash(linkUnits);

        /* リンクの探索 */
        analyzePageLink(topPageName, pageUnitHash);

        /*
         * チェック済みフラグの立っていない PageUnit (= 孤立ページ) の表示
         */
        int found = 0;
        siteDoc.beginTransaction();
        for (Enumeration e = pageUnitHash.keys(); e.hasMoreElements();) {
            String pageName = (String)e.nextElement();
            SPElementStatus es = pageUnitHash.get(pageName);
            int status = es.getStatus();
            if (status == SPElementStatus.UNCHECKED) {
                resultVector.add(new SPElementAndStrings(es.getElement()));
                changeIconColor(es.getElement());
                found++;
            }
        }
        siteDoc.commit();

        /* FILE カラム目をキーにソート */
        sort(SPColumnNames.getColumnIndex(target, SPColumnNames.FILE), false);
        return found;
    } /* searchIsolatedPages */


    /**
     * PageUnit のアイコン塗色を変更する
     @ param element 塗色を変更する PageUnit
    */
    private void changeIconColor(elementBooster element){
        if (element == null) {
            return;
        }

        /**
         * アイコン塗色変更チェックボックスが選択されていない時は
         * 何もしない
         */
        if (!changeIconColorCheckBoxIsSelected) {
            return;
        }

        String paintColor = null;
        if (selectColorButtonBackground != null) {
            int rgb = selectColorButtonBackground.getRGB() & 0xffffff;
            String rgbString = Integer.toHexString(rgb);;

            String zero = "000000";
            String pad = "";
            int padLength = zero.length() - rgbString.length();
            if (padLength > 0) {
                pad = zero.substring(0, padLength);
            }
            paintColor = "#" + pad + rgbString;
        }
        /* "PaintColor" アトリビュートを、選択された色に変更する
         * paintColor が null の場合は "PaintColor" アトリビュートが削除される
         */
        element.attribute("PaintColor", paintColor);

        if (paintColor == null) {
            return;
        }

        String newvalue = element.attribute("PaintColor");
        if (newvalue == null) {
            return;
        }
        if (newvalue.equalsIgnoreCase(paintColor)){
            RUpdateManager.update(RUpdateManager.PROPERTY_CHANGED);
            return;
        }
    } /* changeIconColor */


    /** LinkUnit の配列のうち、リンク元が一致するものをそれぞれ 1 つの Vector
     *  にし、各 Vector をリンク元をキーにしてハッシュテーブル化する
     *  @param elements LinkUnit の 配列
     *  @return Vector の Hashtable
     */
    private Hashtable getElementVectorHash(elementBooster[] elements) {
        Hashtable elementVectorHash = new Hashtable();
        Vector elementVector;

        if (elements == null) {
            return elementVectorHash;
        }
        if (elements.length == 0) {
            return elementVectorHash;
        }

        for (int i = 0; i < elements.length; i++) {
            /* 存在するエレメントのみ抽出 */
            String exist = elements[i].attribute("Exist");
            if (exist == null) {
                continue; 
            }
            if (!exist.equals("true")) {
                continue;
            }

            /* リンク元の取得 */
            elementBooster connect0 = elements[i].child("Connect0");
            String linkSource = connect0.attribute("Key");
            if (linkSource == null) {
                continue;
            }
            linkSource = linkSource.toLowerCase();

            Object o = elementVectorHash.get(linkSource);
            if (o == null) {
                elementVector = new Vector();
            } else if (o instanceof Vector) {
                elementVector = (Vector)o;
            } else {
                elementVector = new Vector();
            }

            elementVector.add(elements[i]);
            elementVectorHash.put(linkSource, elementVector);
        }
        return elementVectorHash;
    } /* getElementStatusVector */


    /**
     * ページ間リンクを深さ優先で全探索し、到達したページについて、
     * pageHash 中の該当するフラグを立てる
     * @param sourceNode 探索の起点となる PageUnit の名前
     * @param pageHash SPElementStatusHash のインスタンス
     *                 (PageUnit の Hashtable)
     */
    private void analyzePageLink(String sourceNode,
                                 SPElementStatusHash pageHash) {
        if (pageHash.size() <= 0) { 
            debugOut("存在するページがありません");
            return;
        }
        SPElementStatus es = pageHash.get(sourceNode, true);
        if (es == null) {
            debugOut(sourceNode + " が見つかりません");
            return;
        }
        es.setStatus(SPElementStatus.CHECKING);

        /* sourceNode からのリンク先を取得する */
        Object o = linkUnitsHash.get(sourceNode.toLowerCase());
        if (o == null) {
            return;
        }
        if (!(o instanceof Vector)) {
            return;
        }

        Vector linkUnitVector = (Vector)o;

        /* sourceNode からのリンク先をすべてチェックする */
        for (int i = 0; i < linkUnitVector.size(); i++) {
            Object elem = linkUnitVector.elementAt(i);
            if (!(elem instanceof elementBooster)) {
                continue;
            }
            elementBooster linkElement = (elementBooster)elem;

            /*
             * リンク元、リンク先の抽出。
             * リンク元が自エレメント以外のリンクは無視する
             */
            elementBooster connect0 = linkElement.child("Connect0");
            elementBooster connect1 = linkElement.child("Connect1");
            if (connect0 == null || connect1 == null) {
                continue;
            }
            String source      = connect0.attribute("Key");
            String destination = connect1.attribute("Key");
            if (source == null || destination == null) {
                continue;
            }

            debugOut("link: " + source + " -> " +  destination);

            SPElementStatus destElement = pageHash.get(destination, true);
            /*
             * destination の Exist が "false" ときは、
             * null が設定されている
             */
            if (destElement == null) {
                debugOut("page: " + destination + " not exist");
            } else if (destElement.getStatus() == SPElementStatus.UNCHECKED) {
                /* 再帰呼出*/
                analyzePageLink(destination, pageHash);
            } else {
                /* リンク先がチェック中か、すでにチェック済み */
                debugOut("page: " + destination + ": " +
                         destElement.getStatus());
            }
        } /* for (int i = 0; i < linkUnitVector.size(); i++) */

        es.setStatus(SPElementStatus.DONE);
        debugOut("analyzePageLink: " + sourceNode + " done");
    } /* analyzePageLink */
} /* class SPTableModelIsolated */
