/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/01/05, 14:33
!  AUTHOR(S): KOGA, Junichiro
!  File : ScriptList.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */

package ciss.phase_viewer.scripting.scriptmanipulator;

import java.awt.GridLayout;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Vector;

import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.apache.log4j.Logger;

import ciss.phase_viewer.scripting.ScriptDescriptionPanel;
import ciss.phase_viewer.scripting.ScriptUtils;
import ciss.phase_viewer.scripting.ScriptWrapper;
import ciss.phase_viewer.scripting.scripteditor.ScriptEditorCaller;
import ciss.phase_viewer.scripting.scripteditor.ScriptEditorGUI;

/**
 * スクリプト表示用のGUI;「スクリプトのリスト」とスクリプトの説明文?表示画面からなる.
 * 
 * @author
 */
public class ScriptList extends JPanel implements ListSelectionListener,
        MouseListener, KeyListener, ScriptEditorCaller {
    private Logger logger = Logger.getLogger(ScriptList.class.getName());
    private HashMap map = new HashMap();
    private JList jlist;
    private ScriptDescriptionPanel descriptionPanel;
    private String scriptType = ScriptWrapper.SH;

    /**
     * 表示するスクリプトを指定しないコンストラクター
     */
    public ScriptList() {
        // setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
        setLayout(new GridLayout());
        DefaultListModel model = new DefaultListModel();
        jlist = new JList();
        jlist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        jlist.addListSelectionListener(this);
        JScrollPane scr = new JScrollPane();
        scr.getViewport().setView(jlist);
        descriptionPanel = new ScriptDescriptionPanel();
        // add(scr);
        // add(descriptionPanel);
        pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, scr,
                descriptionPanel);
        pane.setResizeWeight(0.5);
        add(pane);
        if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
            scriptType = ScriptWrapper.BAT;
        }
        jlist.addMouseListener(this);
        jlist.addKeyListener(this);
        mousePressed(null);
    }

    /**
     * 表示したいスクリプトの配列を引数にとるコンストラクター
     * 
     * @param initScript
     *            表示したいスクリプトの配列
     */
    public ScriptList(ScriptWrapper[] initScript) {
        this();
        this.scriptType = scriptType;
        if (initScript != null) {
            for (int i = 0; i < initScript.length; i++) {
                addScriptToMap(initScript[i]);
            }
        }
        updateGUI();
        jlist.setSelectedIndex(0);
    }

    private JSplitPane pane;

    public void adjust() {
        pane.setDividerLocation(0.5);
    }

    /**
     * 表示したいスクリプトの配列と, 表示すべきスクリプト種を引数にとるコンストラクター
     * 
     * @param initScript
     *            まず表示するスクリプトの配列
     * @param scriptType
     *            スクリプト種の指定, ScriptWrapperのstatic変数を利用せよ.
     */
    public ScriptList(ScriptWrapper[] initScript, String scriptType) {
        this(initScript);
        this.scriptType = scriptType;
        updateGUI();
        jlist.setSelectedIndex(0);
    }

    private void addScriptToMap(ScriptWrapper script) {
        DefaultListModel model = (DefaultListModel) map.get(script
                .getScriptType());
        if (model == null) {
            model = new DefaultListModel();
            map.put(script.getScriptType(), model);
        }
        model.addElement(script);
    }

    private void removeScriptFromMap(ScriptWrapper script) {
        DefaultListModel model = (DefaultListModel) map.get(script
                .getScriptType());
        if (model == null) {
            return;
        }
        model.removeElement(script);
    }

    /**
     * 新たにスクリプトを足す.
     * 
     * @param script
     *            足しこみたいscript
     */
    public void addScript(ScriptWrapper script) {
        logger.debug("adding script: " + script);
        addScriptToMap(script);
        updateGUI();
    }

    /**
     * 指定のスクリプトを削除
     * 
     * @param script
     *            削除したいスクリプト.
     */
    public void removeScript(ScriptWrapper script) {
        removeScriptFromMap(script);
        updateGUI();
    }

    /**
     * スクリプト種を指定; ScriptWrapperのstatic変数を利用せよ.
     * 
     * @param scriptType
     *            スクリプト種
     */
    public void setScriptType(String scriptType) {
        this.scriptType = scriptType;
        updateGUI();
    }

    /**
     * 選択中のスクリプトを下へ.
     */
    public void shiftDownSelectedElement() {
        int index = jlist.getSelectedIndex();
        DefaultListModel model = (DefaultListModel) map.get(this.scriptType);
        if (index == model.size() - 1) {
            return;
        }
        Object orig = model.get(index);
        Object down = model.get(index + 1);
        model.set(index, down);
        model.set(index + 1, orig);
        setModelToList();
        jlist.setSelectedIndex(index + 1);
    }

    /**
     * 選択中のスクリプトを上へ.
     */
    public void shiftUpSelectedElement() {
        int index = jlist.getSelectedIndex();
        if (index == 0) {
            return;
        }
        DefaultListModel model = (DefaultListModel) map.get(this.scriptType);
        Object orig = model.get(index);
        Object up = model.get(index - 1);
        model.set(index, up);
        model.set(index - 1, orig);
        setModelToList();
        jlist.setSelectedIndex(index - 1);
    }

    /**
     * 選択中のスクリプトを削除.
     */
    public void deleteSelectedElement() {
        DefaultListModel model = (DefaultListModel) map.get(this.scriptType);
        int remind = jlist.getSelectedIndex();
        Object o = model.remove(remind);

        if (o instanceof ScriptWrapper) {
            String path = ((ScriptWrapper) o).getPath();
            ScriptUtils.removeNecessaryFiles(path, new File(path).getParent());
            new File(path).delete();
        }

        setModelToList();
        revalidate();
        if (remind >= model.size() - 1) {
            jlist.setSelectedIndex(remind - 1);
        } else {
            jlist.setSelectedIndex(remind);
        }

    }

    /**
     * 種類に限らず, 全スクリプトの配列を返す.
     * 
     * @return 登録されている全てのスクリプトを返す.
     */
    public ScriptWrapper[] getAllScripts() {
        Vector ret = new Vector();
        Collection collection = map.values();
        Object[] model = collection.toArray();
        if (model == null) {
            return null;
        }

        for (int i = 0; i < model.length; i++) {
            DefaultListModel md = (DefaultListModel) model[i];
            for (int j = 0; j < md.size(); j++) {
                ret.addElement(md.getElementAt(j));
            }
        }

        if (ret == null || ret.size() == 0) {
            return null;
        }

        ScriptWrapper[] scripts = new ScriptWrapper[ret.size()];
        ret.copyInto(scripts);

        return scripts;
    }

    /**
     * 登録されているスクリプトの数を返す.
     * 
     * @return 登録されているスクリプトの数
     */
    public int getNumScripts() {
        return ((DefaultListModel) jlist.getModel()).size();
    }

    /**
     * インデックスで指定されるスクリプトを返す.
     * 
     * @int 欲しいスクリプトのインデックス.
     * @return インデックスで指定されたスクリプト
     */
    public ScriptWrapper getScriptAt(int i) {
        DefaultListModel model = (DefaultListModel) jlist.getModel();
        ScriptWrapper ret = (ScriptWrapper) model.elementAt(i);
        return ret;
    }

    /**
     * 選択中のスクリプトを取得.
     * 
     * @return 選択中のスクリプト.
     */
    public ScriptWrapper getSelectedScript() {
        ScriptWrapper ret = (ScriptWrapper) jlist.getSelectedValue();
        return ret;
    }

    public void valueChanged(ListSelectionEvent e) {
        ScriptWrapper scr = (ScriptWrapper) jlist.getSelectedValue();
        if (scr == null) {
            return;
        }
        descriptionPanel.setScriptFile(scr.getPath());
        revalidate();
    }

    /**
     * 'description panel'に説明文を付加
     * 
     * @param scriptPath
     *            スクリプトファイルへのパス
     */
    public void setDescription(String scriptPath) {
        descriptionPanel.setScriptFile(scriptPath);
    }

    private void updateGUI() {
        setModelToList();
        revalidate();
    }

    private void setModelToList() {
        DefaultListModel model = (DefaultListModel) map.get(this.scriptType);
        if (model == null) {
            model = new DefaultListModel();
            map.put(this.scriptType, model);
        }
        jlist.setModel(model);
    }

    public void keyTyped(java.awt.event.KeyEvent e) {
    }

    public void keyReleased(java.awt.event.KeyEvent e) {
    }

    public void keyPressed(java.awt.event.KeyEvent e) {
        if (e.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER) {
            bootEditor();
        }
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
        adjust();
        if (e == null) {
            return;
        }
        if (e.getButton() == MouseEvent.BUTTON1) {
            ScriptWrapper scr = (ScriptWrapper) jlist.getSelectedValue();
            if (scr == null) {
                return;
            }
            descriptionPanel.setScriptFile(scr.getPath());
            revalidate();
        }
        if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
            bootEditor();
        }
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void bootEditor() {
        ScriptEditorGUI editor = new ScriptEditorGUI(this);
    }

    public String getScriptPath() {
        ScriptWrapper scr = getSelectedScript();
        if (scr != null) {
            return scr.getPath();
        }
        return "";
    }

    public HashMap getObjects() {
        return null;
    }
}
