package jp.co.nri.rid.search;

/* interfaces & models */
import javax.swing.table.AbstractTableModel;

/* misc */
import java.util.Arrays;
import java.util.Comparator;
import java.util.Vector;

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

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

    /** RCS ID */
    private static final String RCSID =
	"$Id: SPTableModel.java,v 1.35 2003-06-26 17:14:01+09 nsmr Exp $";

    /** 検索対象の ID */
    static final int ISOLATED   = 0;
    static final int LARGE      = 1;
    static final int UNUSED     = 2;
    static final int FORM       = 3;
    static final int META       = 4;
    static final int SCRIPT     = 5;
    static final int STYLESHEET = 6;
    static final int DEEPPAGE   = 7;
    static final int STATISTICS = 8;

    static final int NUMTARGETS = 9;

    /** ボタンに表示する文字列 */
    static final Object TARGET_ID_STRING[][] = {
        {new Integer(ISOLATED),   "isolated pages"},
        {new Integer(LARGE),      "calculated page size"},
        {new Integer(UNUSED),     "unused resources"},
        {new Integer(FORM),       "form detail"},
        {new Integer(META),       "meta information"},
        {new Integer(STYLESHEET), "stylesheet"},
        {new Integer(DEEPPAGE),   "deep page"},
        {new Integer(SCRIPT),     "script"},
        {new Integer(STATISTICS), "site report"}
    };

    /** ステータスを表示する際の単位 */
    static final Object TARGET_ID_UNIT[][] = {
        {new Integer(ISOLATED),   "file"},
        {new Integer(LARGE),      "page"},
        {new Integer(UNUSED),     "file"},
        {new Integer(FORM),       "item"},
        {new Integer(META),       "item"},
        {new Integer(STYLESHEET), "item"},
        {new Integer(DEEPPAGE),   "item"},
        {new Integer(SCRIPT),     "item"},
        {new Integer(STATISTICS), ""}
    };

    /** 検索結果を格納する Vector */
    Vector resultVector = null;

    protected boolean implemented = true;

    /** 検索対象 ID */
    int target;

    /** 検索結果の個数 */
    int count = -1;

    /** debug flag */
    static final boolean DEBUG = false;

    /** Boolean objects */
    static final Boolean BTRUE = new Boolean(true);
    static final Boolean BFALSE = new Boolean(false);

    /** ソート済みのカラムのモデル上のインデクス */
    protected int modelIndexOfSortedColumn = -1;

    protected int sortOrder = -1;

    /** ソート済みのカラムが昇順でソートされていることを示すフラグ */
    public static final int ASCENDING = 1;

    /** ソート済みのカラムが降順でソートされていることを示すフラグ */
    public static final int DESCENDING = -1;


    /**
     * コンストラクタ:
     * 
     * 何も表示しないテーブルモデル
     */
    SPTableModel() {
        target = -1;
    }


    /**
     * コンストラクタ:
     */
    SPTableModel(int target) {
        this.target = target;
        implemented = false;
    } /* SPTableModel */


    /**
     * @param errStr デバッグメッセージ
     * デバッグメッセージを出力する
     */
    public void debugOut(String errStr) {
	if (DEBUG) {
	    System.err.println(errStr);
	}
    }


    /**
     * statusLabel に表示するための文字列を返す
     */
    String getStatusString() {
        if (!implemented) {
            return "not implemented.";
        }

        String unit = getItemUnit(target);
        if (unit == "") {
            return "";
        }

        if (count == 1) {
            return count + " " + unit + " found.";
        }
        if (count == 0 || 2 <= count) {
            return count + " " + unit + "s found.";
        }

        return "";
    } /* getStatusString */


    /**
     * ドキュメントから、指定されたユニット名を持つ要素をすべて取得する
     * @param unitName 取得する要素のユニット名
     * @param docName ユニットを取得するドキュメント
     @ @return 要素を elementBooster 化した配列。
     @ ドキュメントが存在しなければ new elementBooster[0] を返す。
     @ 要素が存在しなければ new elementBooster[0] を返す。
    */
    elementBooster[] getElementsFromDocument(String unitName,
                                             String docName){
        elementBooster[] elements = new elementBooster[0];

        if (docName == null) {
            return elements;
        }

        /* ドキュメントの取得 */
        Object o = ZInstance.map().get(docName);
        if (o == null) {
            return elements;
        }
        if (!(o instanceof RidDocument)) {
            return elements;
        }
        RidDocument doc = (RidDocument)o;

        /* ドキュメントの root element を取得 */
        elementBooster rootElem = (new documentBooster(doc)).root();
        if (rootElem.isNull()) {
            return elements;
        } 

        /* ドキュメント中のユニットをすべて取得 */
        elementBooster[] resultElements = rootElem.offspring(unitName);
        if (resultElements == null) {
            return elements;
        }
        return resultElements;
    } /* getElementsFromDocument */


    public int getColumnCount() {
        if (!implemented) {
            return 0;
        }
        if (target == -1) {
            return 0;
        }
        int[] columnIDArray = SPColumnNames.get(target);
        if (columnIDArray == null) {
            return 0;
        }
        return columnIDArray.length;
    } /* getColumnCount */


    public String getColumnName(int column) {
        int columnID = SPColumnNames.getColumnID(target, column);
        if (columnID < 0) {
            return "";
        }
        return SPColumnNames.toString(columnID);
    } /* getColumnName */


    public int getRowCount() {
        if (!implemented) {
            return 0;
        }
        if (resultVector == null) {
            return 0;
        }
        return resultVector.size();
    } /* getRowCount */


    public Object getValueAt(int row, int col) {
        String columnName = getColumnName(col);

        if (!implemented) {
            return "";
        }

        /* 値が取得できれなければ "" を表示 */
        if (row < 0) {
            return "";
        }
        if (resultVector == null) {
            return "";
        }
        if (resultVector.size() <= row) {
            return "";
        }
        Object rowObject = resultVector.elementAt(row);
        if (rowObject == null) {
            return "";
        }
        if (!(rowObject instanceof SPElementAndStrings)) {
            return "";
        }

        SPElementAndStrings rowData = (SPElementAndStrings)rowObject;

        /* strings から値が取得できればそれを表示 */
        String[] rowStrings = rowData.strings;
        if (rowStrings != null) {
            if (0 <= col && col < rowStrings.length) {
                String cell = rowStrings[col];
                if (cell != null) {
                    return cell;
                }
            }
        }

        /* element から値が取得できればそれを表示 */
        elementBooster rowElement = rowData.element;
        if (rowElement != null) {
            if (columnName != null) {
                String cell = rowElement.attribute(columnName);
                if (cell != null) {
                    return cell;
                }
            }
        }

        /* 値が取得できなければ "" を表示 */
        return "";
    } /* getValueAt */


    public elementBooster getElementAt(int row, int col) {
        if (!implemented) {
            return null;
        }

        if (resultVector == null) {
            return null;
        }
        if (resultVector.size() <= row) {
            return null;
        }

        Object selectedRow = resultVector.elementAt(row);
        if (selectedRow == null) {
            return null;
        }

        if (selectedRow instanceof SPElementAndStrings) {
            return ((SPElementAndStrings)selectedRow).element;
        }

        return null;
    } /* getElementAt */


    public Class getColumnClass(int column) {
        int columnID = SPColumnNames.getColumnID(target, column);
        if (columnID < 0) {
            return Object.class;
        }

        if (SPTableColumnModel.isIntegerColumn(columnID)) {
            return Integer.class;
        }

        return Object.class;
    }


    public boolean isImplemented() {
        return implemented;
    }


    /** ソート済みのカラムの、モデル上のインデクスを返す */
    public int getModelIndexOfSortedColumn() {
        return modelIndexOfSortedColumn;
    }


    public void sort(int columnIndex, boolean updateModelIndexOfSortedColumn) {
        sort(columnIndex, updateModelIndexOfSortedColumn, 0);
    }


    /**
     * @param order ASCENDING: 昇順, DESCENDING: 降順, それ以外: 前回と反転
     *              (前回が違うカラムだった場合は昇順)
     */
    public void sort(int columnIndex, boolean updateModelIndexOfSortedColumn,
                     int order) {
        /* 結果表示がカラムをキーにソート可能でなければ無視 */
        if (!isSortableTarget(target)) {
            return;
        }

        /* 現在と同じ columnIndex ならば、ソートの順序を反転する */
        if (order == DESCENDING) {
            sortOrder = DESCENDING;
        } else if (order == ASCENDING) {
            sortOrder = ASCENDING;
        } else if (modelIndexOfSortedColumn == columnIndex) {
            sortOrder *= -1;
        } else {
            sortOrder = ASCENDING;
        }

        if (updateModelIndexOfSortedColumn) {
            modelIndexOfSortedColumn = columnIndex;
        } else {
            modelIndexOfSortedColumn = -1;
        }

        Comparator comparator;

        int columnID = SPColumnNames.getColumnID(target, columnIndex);
        if (SPColumnNames.isElementColumn(target, columnID)) {
            String attribute = getColumnName(columnIndex);
            boolean isInt = SPTableColumnModel.isIntegerColumn(columnID);
            comparator = new SPElementComparator(attribute, sortOrder, isInt);
        } else {
            boolean isInt = SPTableColumnModel.isIntegerColumn(columnID);
            comparator =
                new SPElementComparator(columnIndex, sortOrder, isInt);
        }

        Object[] elements = resultVector.toArray();
        Arrays.sort(elements, comparator);
        resultVector = new Vector(Arrays.asList(elements));
    } /* sort */


    /**
     * @param 検索対象 ID
     * @return 指定された検索対象の結果表示が、
     *         カラムをキーにソート可能かどうか
     */
    boolean isSortableTarget(int target) {
        if (target == ISOLATED) {
            return true;
        }
        if (target == LARGE) {
            return true;
        }
        if (target == UNUSED) {
            return true;
        }
        return false;
    } /* isSortableTarget */


    /**
     * 検索対象 ID をカラム名の文字列表現に変換する
     */
    static String toString(int targetID) {
        Integer targetIDInteger = new Integer(targetID);
        for (int i = 0; i < TARGET_ID_STRING.length; i++) {
            if (TARGET_ID_STRING[i] == null) {
                continue;
            }
            if (TARGET_ID_STRING[i].length < 1) {
                continue;
            }
            if (TARGET_ID_STRING[i][0].equals(targetIDInteger)) {
                if (TARGET_ID_STRING[i].length < 2) {
                    return "";
                }
                return (String)TARGET_ID_STRING[i][1];
            }
        }
        return null;
    } /* toString */


    /**
     * 検索対象を数える単位を返す
     */
    static String getItemUnit(int targetID) {
        Integer targetIDInteger = new Integer(targetID);
        for (int i = 0; i < TARGET_ID_UNIT.length; i++) {
            if (TARGET_ID_UNIT[i] == null) {
                continue;
            }
            if (TARGET_ID_UNIT[i].length < 1) {
                continue;
            }
            if (TARGET_ID_UNIT[i][0].equals(targetIDInteger)) {
                if (TARGET_ID_UNIT[i].length < 2) {
                    return "";
                }
                return (String)TARGET_ID_UNIT[i][1];
            }
        }
        return null;
    } /* getItemUnit */


    String[] addStringToRowStrings(String[] rowStrings, int target,
                                   int columnID, String value) {
        int columnIndex = SPColumnNames.getColumnIndex(target, columnID);
        if (columnIndex < 0 || rowStrings.length <= columnIndex) {
            return rowStrings;
        }
        rowStrings[columnIndex] = value;
        return rowStrings;
    } /* addStringToRowStrings */
} /* class SPTableModel */
