/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2005/12/19, 15:09
!  AUTHOR(S): KOGA, Junichiro
!  File : ScriptManipulator.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.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Properties;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.border.TitledBorder;

import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;

import ciss.phase_viewer.common.ChaseFileChooser;
import ciss.phase_viewer.common.Resources;
import ciss.phase_viewer.jdom.MyElement;
import ciss.phase_viewer.jobcontrol.DefaultScriptCreator;
import ciss.phase_viewer.jobcontrol.JobController;
import ciss.phase_viewer.jobcontrol.JobControllerElement;
import ciss.phase_viewer.projectbrowser.ProjectInfo;
import ciss.phase_viewer.scripting.ScriptUtils;
import ciss.phase_viewer.scripting.ScriptWrapper;
import ciss.phase_viewer.ssh.hosts.HostInfo;
import ciss.phase_viewer.ssh.hosts.HostSelector;

/**
 * スクリプトをbrowseしたりするクラス.
 * 
 * @author
 */
public class ScriptManipulator extends JPanel implements JobControllerElement,
        ActionListener {
    private Logger logger = Logger.getLogger(ScriptManipulator.class.getName());
    private Properties props;
    private Document document;
    private ProjectInfo projectInfo;

    /* tags */
    private final String script = "script";
    private final String init_script = "init_script";
    private final String script_type = "script_type";
    private final String exec = "exec";
    private final String bsh = "bsh";
    private final String sh = "sh";
    private final String script_exec_script = "script_exec_script";
    private final String exec_script = "exec_script";
    private final String script_path = "script_path";

    private ScriptList scriptList;
    private ScriptBrowser scriptBrowser;

    /**
     * @param projectInfo
     *            各種プロジェクト情報を格納したオブジェクト
     */
    public ScriptManipulator(ProjectInfo projectInfo) {
        this.projectInfo = projectInfo;
        props = new Properties();
        InputStream inp = null;
        try {
            inp = ScriptManipulator.class
                    .getResourceAsStream("/ciss/phase_viewer/scripting/script.properties");
            props.load(inp);
        } catch (IOException ioe) {
            logger.error("failed to load property file...");
        } finally {
            try {
                inp.close();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
        // setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
        setLayout(new GridLayout());
        createGUI();
        logger.debug("finished init of: " + ScriptManipulator.class.getName());
        this.document = ciss.phase_viewer.jobcontrol.JobController
                .getJobControlDocument(projectInfo, this);
    }

    public void adjust() {
        logger.debug("adjusting....");
        scriptList.adjust();
        scriptBrowser.adjust();
    }

    private JComboBox scriptType;
    private JButton bedit;
    private JButton bbootChooser;
    private JButton bdelete;
    private JButton bup;
    private JButton bdown;
    private JButton bclose;

    private JPanel createButtons() {
        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
        scriptType = new JComboBox(ScriptWrapper.REGISTERED_SCRIPT_TYPE);
        JPanel ptype = new JPanel();
        ptype.setBorder(new TitledBorder("script type"));
        ptype.add(scriptType);
        bedit = new JButton("edit input");
        JButton beditor = new JButton("boot editor");
        bbootChooser = new JButton("boot chooser");
        bdelete = new JButton("delete");
        bup = new JButton("up");
        bdown = new JButton("down");
        bclose = new JButton("close");

        p.add(ptype);
        p.add(bedit);
        p.add(beditor);
        p.add(bbootChooser);
        p.add(bdelete);
        p.add(bup);
        p.add(bdown);

        bedit.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                bootScriptEditor();
            }
        });

        beditor.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                ScriptWrapper scripts = scriptList.getSelectedScript();
                if (scripts != null) {
                    ciss.phase_viewer.common.Utils.bootTextViewer(scripts
                            .getPath());
                }
            }
        });

        bbootChooser.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                selectScript();
            }
        });

        bdelete.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                deleteSelectedElement();
            }
        });

        bup.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                shiftUpSelectedElement();
            }
        });

        bdown.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                shiftDownSelectedElement();
            }
        });

        scriptType.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (scriptType.getSelectedItem() == null) {
                    return;
                }
                scriptList.setScriptType(scriptType.getSelectedItem()
                        .toString());
                saveToDisk();
            }
        });

        return p;
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() instanceof HostSelector) {
            HostSelector selector = (HostSelector) e.getSource();
            HostInfo info = selector.getSelectedHost();

            Object selectedObject = scriptType.getSelectedItem();

            scriptType.removeAllItems();
            String[] selection = ScriptWrapper.getValidScriptType(info);
            for (int i = 0; i < selection.length; i++) {
                scriptType.addItem(selection[i]);
            }
            scriptType.setSelectedItem(selectedObject);
        }
    }

    private void shiftDownSelectedElement() {
        scriptList.shiftDownSelectedElement();
        saveToDisk();
    }

    private void shiftUpSelectedElement() {
        scriptList.shiftUpSelectedElement();
        saveToDisk();
    }

    private void deleteSelectedElement() {
        scriptList.deleteSelectedElement();
        saveToDisk();
        revalidate();
    }

    private void selectScript() {
        ChaseFileChooser fdlg = new ChaseFileChooser(ChaseFileChooser.script);
        fdlg.setDialogType(JFileChooser.CUSTOM_DIALOG);
        fdlg.setDialogTitle("choose");
        fdlg.setFileSelectionMode(JFileChooser.FILES_ONLY);
        if (fdlg.showDialog(this, "Select") != JFileChooser.APPROVE_OPTION) {
            return;
        }
        String str = fdlg.getSelectedFile().getAbsolutePath();
        if (!new File(str).exists()) {
            logger.error("file doesn't exist!!");
            return;
        }
        String name = new File(str).getName();

        String foo = projectInfo.getProjectDirectory()
                + System.getProperty("file.separator") + name;
        try {
            ciss.phase_viewer.common.ExternalProgramExecuter.copy(str, foo);
        } catch (Exception exc) {
            logger.error("failed copy of template file... ");
            foo = str;
        }

        String type = ScriptWrapper.getTypeFromFile(foo);
        ScriptWrapper script = new ScriptWrapper(foo, type);
        scriptList.addScript(script);

        revalidate();
        saveToDisk();
    }

    private void saveToDisk() {
        if (document == null || !document.hasRootElement()) {
            return;
        }

        Element root = document.getRootElement().getChild(
                JobController.JOBCONTROL);
        if (root == null) {
            return;
        }

        Element type_ = root.getChild(script).getChild(script_type);
        if (type_ != null) {
            type_.setText(MyElement.encode(scriptType.getSelectedItem()
                    .toString()));
        }

        Element script_element_exec = root.getChild(script).getChild(this.exec);

        java.util.List exec = script_element_exec.getChildren(exec_script);
        for (int i = exec.size() - 1; i >= 0; i--) {
            script_element_exec.removeContent((Element) exec.get(i));
        }

        ScriptWrapper[] scripts = scriptList.getAllScripts();

        if (scripts != null) {
            for (int i = 0; i < scripts.length; i++) {
                ScriptWrapper script = scripts[i];

                Element exec_element = new Element(exec_script);

                Element type = new Element(script_type);
                type.setText(MyElement.encode(script.getScriptType()));

                Element path = new Element(script_path);
                // path.setText(MyElement.encode(script.getPath()));
                path.setText(MyElement.encode(script.toString()));

                exec_element.addContent(type);
                exec_element.addContent(path);

                script_element_exec.addContent(exec_element);
            }
        }
        ciss.phase_viewer.jobcontrol.JobController.saveJobControlFile(
                projectInfo.getProjectDirectory(), document);
    }

    private void bootScriptEditor() {
        scriptList.bootEditor();
    }

    public boolean readJobControlDocument(org.jdom.Document doc) {
        DefaultScriptCreator creator = projectInfo.getDefaultScriptCreator();
        if (!creator.createDefaultScript()) {
            logger.error("failed creation of default script...");
        }
        Element root = doc.getRootElement().getChild(JobController.JOBCONTROL);
        Element script_element = root.getChild(script);

        if (script_element == null) {
            return false;
        }

        // Element ele = script_element.getChild(init_script);
        // if ( ele == null ) {
        // return false;
        // }

        Element type = script_element.getChild(script_type);
        if (type == null) {
            return false;
        }
        scriptType.setSelectedItem(MyElement.decode(type.getTextTrim()));

        Element exec_element = script_element.getChild(this.exec);
        if (exec_element == null) {
            return false;
        }

        Element bsh_elem = exec_element.getChild(bsh);
        if (bsh_elem == null) {
            return false;
        }

        Element ele = exec_element.getChild(this.bsh).getChild(
                script_exec_script);
        if (ele == null) {
            return false;
        }

        java.util.List list = exec_element.getChildren(exec_script);
        logger.debug("number of exec_script: " + list.size());

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

        for (int i = 0; i < list.size(); i++) {
            Element element = (Element) list.get(i);
            String scriptPath = MyElement.decode(element
                    .getChildTextTrim(script_path));
            if (!new File(scriptPath).isAbsolute()) {
                scriptPath = projectInfo.getProjectDirectory()
                        + System.getProperty("file.separator")
                        + MyElement.decode(element
                                .getChildTextTrim(script_path));
            }
            String strtype = MyElement.decode(element
                    .getChildTextTrim(script_type));
            ScriptWrapper scriptWrapper = new ScriptWrapper(scriptPath, strtype);
            scriptList.addScript(scriptWrapper);
            logger.debug("added : " + scriptWrapper);
        }

        revalidate();

        return true;
    }

    private void createGUI() {
        JSplitPane split = new JSplitPane();
        split.setOrientation(JSplitPane.VERTICAL_SPLIT);
        scriptList = new ScriptList();
        scriptBrowser = new ScriptBrowser("jobcontrol", scriptList);
        split.setTopComponent(scriptList);
        split.setBottomComponent(scriptBrowser);
        split.setDividerLocation(0.5);
        // JPanel panel = new JPanel();
        // panel.setLayout(new GridLayout());
        // panel.add(split);
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        panel.add(scriptList);
        panel.add(createButtons());

        JPanel selector = new JPanel();
        selector.setLayout(new BoxLayout(selector, BoxLayout.Y_AXIS));
        JButton btn = new JButton(Resources.getIcon(Resources.UP20));
        selector.add(btn);
        selector.add(scriptBrowser);

        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true,
                panel, selector);
        splitPane.setResizeWeight(0.5);
        add(splitPane);

        // add(panel);
        // add(createButtons());
        btn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                String[] paths = scriptBrowser.getSelectedPaths();
                if (paths == null || paths.length == 0) {
                    logger.debug("no file selected");
                    return;
                }
                for (int i = 0; i < paths.length; i++) {
                    String name = new File(paths[i]).getName();

                    String foo = projectInfo.getProjectDirectory()
                            + System.getProperty("file.separator") + name;
                    try {
                        ciss.phase_viewer.common.ExternalProgramExecuter.copy(
                                paths[i], foo);
                    } catch (Exception exc) {
                        logger.error("failed copy of template file... ");
                        foo = paths[i];
                    }

                    processScript(paths[i]);

                    logger.debug("path: " + paths[i]);
                    logger.debug("name: " + foo);
                    String type = ScriptWrapper.getTypeFromFile(foo);
                    logger.debug("type: " + type);
                    ScriptWrapper script = new ScriptWrapper(foo, type);
                    scriptList.addScript(script);
                }
                revalidate();
                saveToDisk();
            }
        });

    }

    private String scriptName = "file_transfer.bsh";

    private void processScript(String scrfile) {
        ScriptUtils.copyNecessaryFiles(scrfile,
                projectInfo.getProjectDirectory());

        String sfile = projectInfo.getProjectDirectory()
                + System.getProperty("file.separator") + scriptName;
        if (!new File(sfile).exists())
            return;
        HashMap ma = new HashMap();
        ma.put("projectInfo", projectInfo);
        ScriptUtils.runScript(sfile, ma);
    }

    public void initJobControlDocument(org.jdom.Document doc) {
        DefaultScriptCreator creator = projectInfo.getDefaultScriptCreator();
        if (!creator.createDefaultScript()) {
            logger.error("failed creation of default script...");
        }
        ScriptWrapper[] initScripts = creator.getDefaultScripts();

        Element script_element = new Element(script);
        doc.getRootElement().getChild(JobController.JOBCONTROL)
                .addContent(script_element);

        String foo = props.getProperty("jobcontrol_init_script_path");
        String init_script_path = System.getProperty("pviewer.home")
                + System.getProperty("file.separator")
                + foo.replace('/', java.io.File.separatorChar);
        Element init_script_element = new Element(init_script);
        init_script_element.setText(MyElement.encode(init_script_path));
        script_element.addContent(init_script_element);

        Element script_type_element = new Element(script_type);
        script_type_element.setText(MyElement.encode("sh"));
        script_element.addContent(script_type_element);

        Element exec_element = new Element(this.exec);
        String bar = props.getProperty("jobcontrol_bsh_script_exec_script");
        String script_exec_script_path = System.getProperty("pviewer.home")
                + System.getProperty("file.separator")
                + bar.replace('/', java.io.File.separatorChar);
        Element script_exec_script_element = new Element(script_exec_script);
        script_exec_script_element.setText(MyElement
                .encode(script_exec_script_path));
        Element bsh_element = new Element(this.bsh);
        bsh_element.addContent(script_exec_script_element);
        exec_element.addContent(bsh_element);
        script_element.addContent(exec_element);

        if (initScripts != null && initScripts.length != 0) {
            for (int i = 0; i < initScripts.length; i++) {
                Element exec_script_element = new Element(exec_script);

                Element type = new Element(script_type);
                type.setText(MyElement.encode(initScripts[i].getScriptType()));
                Element path = new Element(script_path);
                // path.setText(MyElement.encode(initScripts[i].getPath()));
                path.setText(MyElement.encode(initScripts[i].toString()));

                exec_script_element.addContent(type);
                exec_script_element.addContent(path);

                exec_element.addContent(exec_script_element);
            }
        }
    }

}
