package jp.co.nri.rid.search;

/* Layouts */
import java.awt.BorderLayout;
import javax.swing.BoxLayout;

/* Listeners */
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;

/* Events */
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;

/* Swing Components */
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.JTableHeader;

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

/* misc */
import java.awt.Color;
import java.awt.Dimension;
import java.io.File;

/* Rid */
import jp.co.nri.Rid;
import jp.co.nri.rid.RMenu;
import jp.co.nri.rid.doc.RidElementPage;
import jp.co.nri.rid.export.ExportCsvDialog;
import jp.co.nri.rid.generator.GenerateCSV2;
import jp.co.nri.rid.table.LineNoRowHeader;
import jp.co.nri.rid.xml.elementBooster;
import jp.co.iti.fagot.IZApp;
import jp.co.iti.fagot.ZApp;
import jp.co.iti.fagot.util.ZFileFilter;
import jp.co.iti.fagot.util.ZInstance;
import jp.co.iti.fagot.util.ZResource;


/**
 * 検索パネル:
 * instance を別のコンテナ (JFrame など) に add して使う。
 * class をそのまま実行すると、新たに JFrame を生成して、
 * その中に表示する。
 *
 * @author t3-nishimura@nri.co.jp
 */
public class SearchPanel extends JPanel {
    /** SCCS ID */
    private static final String SCCSID = "@(#)SearchPanel.java";

    /** RCS ID */
    private static final String RCSID =
	"$Id: SearchPanel.java,v 1.56 2003-07-17 18:26:56+09 nsmr Exp $";

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

    /** 各ボタンの幅 (ピクセル) */
    static final int BUTTON_WIDTH = 150;

    /** 各ボタンの高さ (ピクセル) */
    static final int BUTTON_HEIGHT = 30;

    /** 空白ラベルの高さ (ピクセル) */
    static final int SPACER_HEIGHT = 20;

    /** テーブルの各セルの高さ (ピクセル) */
    static final int TABLE_ROW_HEIGHT = 24;

    /** テーブル全体の幅 (ピクセル) */
    static final int TABLE_WIDTH = 300;

    /** 深さ入力テキストフィールド*/
    JTextField depthField;

    /** 深さ入力パネル*/
    SPFieldHolderPanel depthPanel;

    /** アイコン塗色変更チェックボックス */
    JCheckBox changeIconColorCheckBox;

    /** 塗色選択ボタン */
    JButton selectColorButton;

    /** アイコン塗色変更パネル */
    JPanel changeIconColorPanel;

    /** CSV 保存ボタン */
    JButton saveCSVButton;

    /** CSV 保存パネル */
    JPanel saveCSVPanel;

    /** 検索結果表示テーブル */
    private JTable resultTable;

    /** 検索結果表示パネル */
    JScrollPane resultScrollPanel;

    /** 検索対象表示用ラベル */
    JLabel targetLabel;

    /** 状態表示用ラベル */
    JLabel statusLabel;

    /** 検索対象に付ける識別名 */
    static final int[] SEARCH_TARGETS = {
        SPTableModel.ISOLATED, 
        SPTableModel.LARGE,
        SPTableModel.UNUSED,
        SPTableModel.FORM,
        SPTableModel.META,
        SPTableModel.SCRIPT,
        SPTableModel.STYLESHEET,
        SPTableModel.STATISTICS
    };

    /**
     * コンストラクタ
     * 
     * 各コンポーネントの初期化をする。
     */
    public SearchPanel() {
	/* カラム名ハッシュテーブルを初期化する */
	SPColumnNames.init();

	/* 文字列リソースを初期化する */
	SPResourceHash.init();

	/* 深さ入力パネルの初期化*/
        initDepthPanel();

	/* アイコン塗色変更パネルの初期化 */
        initChangeIconColorPanel();

	/* 結果表示パネルの初期化 */
        initResultScrollPanel();

	/* 検索対象選択ボタンのリスト*/
	JPanel[] searchButtonPanels = createSearchButtonPanels();

	/* CSV 保存ボタン */
        initSaveCSVPanel();

	/* 各パーツをパネルに配置する */

        /** 検索対象選択パネル */
        JPanel searchButtonsContainer = new JPanel();

	//searchButtonsContainer.setLayout(new GridLayout(0,1));
	//searchButtonsContainer.setLayout(new FlowLayout());
	searchButtonsContainer.setLayout(new BoxLayout(searchButtonsContainer,
						       BoxLayout.Y_AXIS));

	/* パネルの追加 */
	SPSpacerLabel spacerLabel;
	for (int i = 0; i < searchButtonPanels.length; i++) {
	    spacerLabel = new SPSpacerLabel(1, SPACER_HEIGHT);
	    searchButtonsContainer.add(searchButtonPanels[i]);
            // searchButtonsContainer.add(spacerLabel);
	}

        // javax.swing.ImageIcon icon = new javax.swing.ImageIcon(SearchPanel.class.getResource("button.gif"));
        // JButton but = new JButton(icon);
        // searchButtonsContainer.add(but);
        // but.setAlignmentX(RIGHT_ALIGNMENT);
        // but.setMargin(new java.awt.Insets(0, 0, 0, 0));

	// spacerLabel = new SPSpacerLabel(1, BUTTON_HEIGHT);
        // searchButtonsContainer.add(spacerLabel);
        // searchButtonsContainer.add(saveCSVPanel);

        /* 検索対象表示ラベルの生成 */
        targetLabel = createStatusLabel();

	/* 状態表示ラベルの生成 */
	statusLabel = createStatusLabel();

	/* デフォルトは FlowLayout */
	setLayout(new BorderLayout());

	JPanel panel;

	/* デフォルトは FlowLayout */
	panel = new JPanel(new BorderLayout());
	/* 左側パネルに検索対象選択パネルを追加 */
	panel.add(searchButtonsContainer, BorderLayout.NORTH);
	/* 左側パネルに CSV 保存ボタンを追加 */
        // panel.add(saveCSVPanel, BorderLayout.SOUTH);

	/* 左側パネルを追加 */
        add(panel, BorderLayout.WEST);

	/* 右側パネルに検索結果表示パネルと状態表示ラベルを追加 */
	panel = new JPanel(new BorderLayout());
        panel.add(targetLabel, BorderLayout.NORTH);
	panel.add(resultScrollPanel, BorderLayout.CENTER);
	panel.add(statusLabel, BorderLayout.SOUTH);

	/* 右側パネルを追加 */
	add(panel, BorderLayout.CENTER);
	
	init();
    } /* SearchPanel (コンストラクタ) */


    /**
     * main メソッド
     * 
     * JFrame を生成し、その中に検索パネルを表示する。
     * Ridual ではこのメソッドは使用しない。
     */
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	/* Window が閉じられた時は、プログラムを終了する */
	frame.addWindowListener(new SPWindowAdapter());
 
	frame.getContentPane().add(new SearchPanel(), BorderLayout.CENTER);
	frame.pack();
	frame.setVisible(true);
    } /* main */


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


    /**
     * 検索対象を選択するボタンを生成する
     * @return 検索対象を選択するボタンを含むパネルのリスト
     */
    private JPanel[] createSearchButtonPanels() {
	JPanel[] panels = new JPanel[0];

	/* SEARCH_TARGETS が設定されていない場合 */
	if (SEARCH_TARGETS == null) {
	    return panels;
	}
	if (SEARCH_TARGETS.length == 0) {
	    return panels;
	}

	ActionListener myListener = new ButtonLsnr();

	panels = new JPanel[SEARCH_TARGETS.length];
	for (int i = 0; i < SEARCH_TARGETS.length; i++) {
	    JButton button;

	    panels[i] = new JPanel(new BorderLayout());
	    // panels[i].setLayout(new BoxLayout(panels[i], BoxLayout.Y_AXIS));

            int target = SEARCH_TARGETS[i];
	    button = new JButton(SPTableModel.toString(target));

	    /* action command の登録 */
	    button.setActionCommand(Integer.toString(target));

	    /* リスナの登録 */
	    button.addActionListener(myListener);

	    /* サイズの設定 */
            // button.setPreferredSize(new
            //     Dimension(BUTTON_WIDTH, BUTTON_HEIGHT));
            
	    /* BoxLayout の JPanel に配置される場合 */
	    //button.setAlignmentX(CENTER_ALIGNMENT);

            /* ボタン内のテキストを左寄せ */
            button.setHorizontalAlignment(JButton.LEFT);

	    /* パネルに追加 */
	    panels[i].add(button, BorderLayout.CENTER);

	    /* アイコン塗色変更パネルの追加 */
	    if (target == SPTableModel.ISOLATED &&
                (changeIconColorPanel != null)) {
		panels[i].add(changeIconColorPanel, BorderLayout.SOUTH);
	    }

	    /* 深さ入力パネルの追加 */
	    if (target == SPTableModel.DEEPPAGE && (depthPanel != null)) {
		panels[i].add(depthPanel, BorderLayout.SOUTH);
	    }
	}
	return panels;
    } /* createSearchButtonPanels */


    /**
     * 深さ入力テキストフィールドとパネルを生成する
     */
    private void initDepthPanel() {
        depthField = new JTextField("5", 5);
        depthField.setHorizontalAlignment(JTextField.RIGHT);

        depthPanel = new SPFieldHolderPanel();
        depthPanel.addField("depth", depthField);
    } /* initDepthField */


    /**
     * アイコン塗色変更ボタンとパネルを生成する
     */
    private void initChangeIconColorPanel() {
	changeIconColorCheckBox =
            new JCheckBox(SPResourceHash.getString("changeColor"));

        selectColorButton = new JButton(" ... ");
        selectColorButton.addActionListener(new SPColorListener());

	changeIconColorPanel = new JPanel();
	changeIconColorPanel.add(changeIconColorCheckBox);
	changeIconColorPanel.add(selectColorButton);
    } /* initChangeIconColorPanel */


    /**
     * CSV 保存ボタンとパネルを生成する
     */
    private void initSaveCSVPanel() {
        saveCSVButton = new JButton(SPResourceHash.getString("saveCSV"));
        saveCSVButton.addActionListener(new CsvButtonLsnr());

        // saveCSVButton.setPreferredSize(new
        //     Dimension(BUTTON_WIDTH, BUTTON_HEIGHT));

        /* パネル内の位置を中央寄せ */
        // saveCSVButton.setAlignmentX(CENTER_ALIGNMENT);

        /* ボタン内のテキストを左寄せ */
        // saveCSVButton.setHorizontalAlignment(JButton.LEFT);

	saveCSVPanel = new JPanel(new BorderLayout());
	saveCSVPanel.add(saveCSVButton);
    } /* initSaveCSVPanel */


    /**
     * 結果表示パネルの生成
     */
    private void initResultScrollPanel() {
	resultTable = new JTable();

        /** 右クリックでコンテキストメニューを表示するためのリスナ */
	resultTable.addMouseListener(new TableListener());

        resultTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        resultTable.setRowHeight(TABLE_ROW_HEIGHT);
        resultTable.setPreferredScrollableViewportSize(new
            Dimension(TABLE_WIDTH, TABLE_ROW_HEIGHT));

        // resultTable.setCellSelectionEnabled(true);

        /* カラム名表示ヘッダ (最上行) の更新 */
        JTableHeader columnHeader = resultTable.getTableHeader();
        columnHeader.addMouseListener(new SPHeaderListener());

        resultScrollPanel = new JScrollPane(resultTable);
    } /* initResultScrollPanel */


    /**
     * 状態表示ラベルを生成する
     * 
     * @return "a"という文字列を表示するのに十分な高さを持ったラベル
     */
    public JLabel createStatusLabel() {
	JLabel label = new JLabel("a");
        label.setBorder(new javax.swing.border.EmptyBorder(1, 2, 1, 1));
	Dimension d = label.getPreferredSize();
	label.setText("");
	label.setPreferredSize(d);
	return label;
    } /* createStatusLabel */


    /**
     * 検索条件、結果表示テーブルの初期化
     */
    public int init() {
	/* 検索結果表示テーブルの初期化 */
	resultTable.setModel(new SPTableModel());

	/* CSV 保存ボタンを利用不可にする */
	saveCSVButton.setEnabled(false);

	/* アイコン塗色を未選択状態にする */
        changeIconColorCheckBox.setSelected(false);
	selectColorButton.setBackground(Color.gray);

	/** 状態表示をクリアする */
	statusLabel.setText("");

	return 1;
    } /* init */


    /** 検索結果表示テーブルを返す */
    public JComponent getTable() {
        return (JComponent)resultTable;
    }


    /**
     * 検索ボタンのアクションを監視する内部クラス。
     * 検索し、結果を表示する。
     */
    class ButtonLsnr implements ActionListener {
	public void actionPerformed(ActionEvent e){
            SPTableModel spTableModel;

	    /* action command (イベントの発生元) の取得 */
	    String targetString = e.getActionCommand();
            int target;

            try {
                target = Integer.parseInt(targetString);
            } catch (NumberFormatException ex) {
                target = -1;
            }

            if (target == SPTableModel.ISOLATED) {
                spTableModel = new
                    SPTableModelIsolated(changeIconColorCheckBox.isSelected(),
                                         selectColorButton.getBackground());
            } else if (target == SPTableModel.LARGE) {
                spTableModel = new SPTableModelLarge();
            } else if (target == SPTableModel.UNUSED) {
                spTableModel = new SPTableModelUnused();
            } else if (target == SPTableModel.STATISTICS) {
                spTableModel = new SPTableModelStatistics();
            } else if (target == SPTableModel.FORM) {
                spTableModel = new SPTableModelDetailInfo(target);
            } else if (target == SPTableModel.META) {
                spTableModel = new SPTableModelDetailInfo(target);
            } else if (target == SPTableModel.SCRIPT) {
                spTableModel = new SPTableModelDetailInfo(target);
            } else if (target == SPTableModel.STYLESHEET) {
                spTableModel = new SPTableModelDetailInfo(target);
            } else {
                spTableModel = new SPTableModel(target);
            }

            /* 検索対象表示ラベルの更新 */
            targetLabel.setText(SPTableModel.toString(target));

            /* 状態表示ラベルの更新 */
            statusLabel.setText(spTableModel.getStatusString());

            /* テーブルモデルの更新 */
	    resultTable.setModel(spTableModel);

            /* カラムモデルの更新 */
	    resultTable.setColumnModel(new SPTableColumnModel(target));

            /* 行番号表示ヘッダ (最左列) の更新 */
            JTable rowHeader = new LineNoRowHeader(resultTable);
            resultScrollPanel.setRowHeaderView(rowHeader);
            resultScrollPanel.getRowHeader().setPreferredSize(rowHeader.getPreferredSize());
            resultScrollPanel.getVerticalScrollBar().setValue(0);
            resultScrollPanel.getHorizontalScrollBar().setValue(0);

            /* CSV 保存ボタンの更新 */
            if (spTableModel.isImplemented()) {
                saveCSVButton.setEnabled(true);
            } else {
                saveCSVButton.setEnabled(false);
            }
	}
    } /* class ButtonLsnr */


    /**
     * CSV 保存ボタンのアクションを監視する内部クラス。
     * 検索結果を CSV ファイルに保存する。
     */
    class CsvButtonLsnr implements ActionListener {
	public void actionPerformed(ActionEvent e) {
            TableModel tableModel = resultTable.getModel();
            SPTableModel spTableModel;

            if (tableModel instanceof SPTableModel) {
                spTableModel = (SPTableModel)tableModel;
            } else {
                return;
            }

	    if (!spTableModel.isImplemented()) {
		return;
	    }

	    /* 以下 jp.co.nri.rid.action.RidListAction からコピー */
	    String szFile = openFileDialog("csv", "CSV File", "rid.csv.dir");
	    if ( szFile == null ) {
		return;
	    }

	    try {
		// csv出力呼び出し
		GenerateCSV2 csv2 = new GenerateCSV2();
		csv2.generateCSV(resultTable, szFile);
	    } catch (Exception evt) {
		debugOut("Write csv failed:"+evt.toString());
		evt.printStackTrace();
	    }

            // 出力ディレクトリの確認
            String szDocsDir = null;
            String szPjDir = ZInstance.prop().getProperty(Rid.PJ_DIR);
            if (szPjDir != null) {
		ZResource res = ZApp.getTheApp().getResource();
                szDocsDir = szPjDir + File.separator + res.getString("rid.docs.dir");
                String szCompare = szFile.substring(0,Math.min(szFile.length(),szDocsDir.length()));
                if ( szCompare.equalsIgnoreCase(szDocsDir) ) {
                    // コメント入力
                    ExportCsvDialog csvd = new ExportCsvDialog();
                    csvd.show(szFile);
                }
	    }
	} /* actionPerformed */


	/* jp.co.nri.rid.action.RidGobAction からコピー */
	/**
	 * ファイル選択ダイアログ
	 * @param szExt
	 * @param szExtName
	 * @param szOutDir
	 */
	public String openFileDialog(String szExt, String szExtName, String szOutDir) {
	    IZApp izapp;
	    ZResource res;

	    izapp = ZApp.getTheApp();
	    if (izapp == null) {
		debugOut("Not running within Ridual application.");
		return null;
	    } else {
		res = ZApp.getTheApp().getResource();
	    }

	    JFileChooser dlg = new JFileChooser();
	    // ファイルフィルタの設定
	    dlg.setFileFilter(new ZFileFilter( new String(szExt), szExtName));

	    // カレントディレクトリの設定
	    String szPjDir = ZInstance.prop().getProperty(Rid.PJ_DIR);
	    String szDir = res.getString("app.install.path");
	    if ( szPjDir != null ) {
		szDir = szPjDir + File.separator + res.getString(szOutDir);
	    }
	    dlg.setCurrentDirectory(new File(szDir)) ;

	    // ダイアログを開く
	    int nRet = dlg.showSaveDialog(ZApp.getTheApp().getFrame());
	    String szFile = null ;
	    if ( nRet == JFileChooser.APPROVE_OPTION) {
		// ファイル名を取得
		File fFile = dlg.getSelectedFile();
		try {
		    szFile = fFile.getCanonicalPath();
		} catch ( java.io.IOException evt) {
		    szFile = fFile.getAbsolutePath();
		}

		if( szFile != null ){
		    if ( !szFile.endsWith("."+szExt) ) {
			szFile += "."+szExt;
		    }
		}
	    }

	    // ファイル履歴の更新
	    // 履歴は更新されないが、dlg.setCurrentDirectoryを行ってディレクトリが
	    // 変更になるとメニュー表示でエラーがでるため、ここでファイル履歴を更新する
	    ZApp.getTheApp().updateRecent( null );

	    return szFile;
	} /* openFileDialog */
    } /* class CsvButtonLsnr */


    /** 右クリックでコンテキストメニューを表示するためのリスナ */
    class TableListener implements MouseListener {
	public void mouseClicked(MouseEvent e){
	}
	public void mouseEntered(MouseEvent e){
	}
	public void mouseExited(MouseEvent e){
	}
	public void mousePressed(MouseEvent e){
	}

	public void mouseReleased(MouseEvent e){
	    JTable table;

            Object eventSource = e.getSource();
            if (eventSource instanceof JTable) {
                table = (JTable)eventSource;
            } else {
                return;
            }

	    int row = table.rowAtPoint(e.getPoint());
	    int col = table.columnAtPoint(e.getPoint());

            /** セル上、かつ右クリックならば */
	    if ((row >= 0) && (col >= 0) && e.isPopupTrigger()) {
                SPTableModel tableModel = (SPTableModel)table.getModel();
		elementBooster eb = tableModel.getElementAt(row, col);

                /** XML エレメントに対応したセルであれば */
		if (eb != null) {
                    if (eb.element() instanceof RidElementPage) {
                        RMenu.createContextMenu(e, (RidElementPage)(eb.element()));
                    }
		}
	    }
	}
    } /* class TableListener */
} /* class SearchPanel */
