/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2005/07/21, 20:51
!  AUTHOR(S): KOGA, Junichiro
!  File : PhaseInitializer.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.plugins.projectmanipulator.phase;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;

import javax.swing.BoxLayout;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.tree.TreePath;

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

import ciss.phase_viewer.common.ExternalProgramExecuter;
import ciss.phase_viewer.common.PathSelector;
import ciss.phase_viewer.file.ChaseFile;
import ciss.phase_viewer.file.ChaseFileManager;
import ciss.phase_viewer.input.InputWizardController;
import ciss.phase_viewer.input.InputWizardControllerPHASE;
import ciss.phase_viewer.input.InputWizardEvent;
import ciss.phase_viewer.input.InputWizardListener;
import ciss.phase_viewer.input.InputWizardRoot;
import ciss.phase_viewer.inputinterface.DataManager;
import ciss.phase_viewer.inputinterface.Input;
import ciss.phase_viewer.inputinterface.InputInterface;
import ciss.phase_viewer.projectbrowser.ProjectBrowserUtils;
import ciss.phase_viewer.projectbrowser.ProjectInfo;
import ciss.phase_viewer.projectbrowser.ProjectManipulator;
import ciss.phase_viewer.projectbrowser.projectdirbrowser.ProjectDirBrowserNode;

/**
 * a GUI to initialize a 'phase' subproject.
 * 
 * @author KOGA, Junichiro
 */
public class PhaseInitializer implements InputWizardListener {
    private Logger logger = Logger.getLogger(PhaseInitializer.class.getName());

    private ProjectInfo projectInfo;

    private final String FS = System.getProperty("file.separator");

    private String nfinp = "nfinp.data";

    private String templatePath;

    private java.net.URL fileinfofile = PhaseConstants.FILEINFO_PHASE;

    private ProjectManipulator parent;

    private ProjectDirBrowserNode node;

    /** Creates a new instance of PhaseInitializer */
    public PhaseInitializer(ProjectInfo projectInfo, ProjectManipulator parent,
            ProjectDirBrowserNode node) {
        this.projectInfo = projectInfo;
        this.parent = parent;
        this.node = node;
    }

    private InputWizardController controller;

    public void silentInitialization() {
        logger.debug("creating new project...");
        if (projectInfo == null) {
            logger.error("projectInfo is null!");
        }
        String baseDir = projectInfo.getProjectDirectory();
        if (baseDir == null || baseDir.trim().length() == 0) {
            baseDir = System.getProperty("user.home");
        }

        initializeChaseXML(baseDir);
        initializeFileManager(baseDir);
    }

    public void runWizard() {
        logger.debug("creating new project...");
        if (projectInfo == null) {
            logger.error("projectInfo is null!");
        }
        String baseDir = projectInfo.getProjectDirectory();
        if (baseDir == null || baseDir.trim().length() == 0) {
            baseDir = System.getProperty("user.home");
        }

        initializeChaseXML(baseDir);
        initializeFileManager(baseDir);

        String curnfinp = baseDir
                + System.getProperty("file.separator")
                + projectInfo.getChaseFileManager().getFile("F_INP")
                        .getFileName();

        java.net.URL url = PhaseConstants.TABLESPEC;
        DataManager dm = new DataManager(curnfinp, url, false);
        dm.parse();
        InputInterface inp = dm.getInputInterface();
        try {
            IniWiz wiz = new IniWiz();
            controller = new InputWizardControllerPHASE(inp, wiz, projectInfo);
        } catch (Exception exc) {
            exc.printStackTrace();
        }
        controller.addInputWizardListener(this);
        node.getDirBrowser().getTree()
                .scrollPathToVisible(new TreePath(node.getPath()));
        node.getDirBrowser().getTree()
                .setSelectionPath(new TreePath(node.getPath()));
    }

    private void initializeFileManager(String baseDir) {
        logger.debug("baseDir: " + baseDir);
        File filenamesdata = new File(baseDir + FS + "file_names.data");
        PhaseFileManager pfm = new PhaseFileManager(fileinfofile, filenamesdata);
        logger.debug("ok");
        projectInfo.setChaseFileManager(pfm);
        logger.debug("FileManager initialized.");
    }

    private void initializeInputData(String baseDir) {
        // check initial filename for input file.
        nfinp = iniFileName.getText().trim();
        templatePath = selector.getRawPath();
        if (nfinp == null || nfinp.trim().length() == 0) {
            nfinp = "nfinp.data";
        }

        logger.debug("init F_INP");
        // copy input file template
        if (initFileCombo.getSelectedIndex() == 2) {
            File inputFile = new File(baseDir + FS + nfinp);
            java.net.URL definputFile = getClass()
                    .getResource(
                            "/ciss/phase_viewer/plugins/projectmanipulator/phase/nfinp.data");
            try {
                FileOutputStream fos = new FileOutputStream(inputFile);
                InputStream is = definputFile.openStream();
                int data;
                while ((data = is.read()) != -1) {
                    fos.write(data);
                }
                fos.close();
                is.close();
            } catch (IOException ioe) {
                logger.error("failed to create default file_names.data!");
            }
        } else if (initFileCombo.getSelectedIndex() == 0) {
            if (templatePath != null && templatePath.trim().length() != 0) {
                // copy template file
                String nfinpPath = baseDir + FS + nfinp;
                try {
                    ExternalProgramExecuter.copy(templatePath, nfinpPath);
                } catch (IOException ioe) {
                    logger.warn("couldn't copy template file " + templatePath);
                }
            }
        }

        ChaseFileManager foo = projectInfo.getChaseFileManager();
        if (foo == null) {
            logger.error("invalid filemanager...");
            return;
        }
        ChaseFile cf = projectInfo.getChaseFileManager().getFile("F_INP");
        if (cf == null) {
            logger.error("F_INP is null...");
            return;
        }
        cf.update(ChaseFile.FNAME, nfinp);
        projectInfo.getChaseFileManager().save();
        logger.debug("done initialization of F_INP.");
    }

    private void initializeChaseXML(String baseDir) {
        java.net.URL defchaseXML = getClass()
                .getResource(
                        "/ciss/phase_viewer/plugins/projectmanipulator/phase/phase-viewer.xml");
        Document doc = ciss.phase_viewer.jdom.XMLUtils
                .getDocumentFromURL(defchaseXML);
        String projchaseXML = projectInfo.getProjectDirectory() + FS
                + "phase-viewer.xml";
        ciss.phase_viewer.jdom.XMLUtils.saveDocumentTo(doc, new File(
                projchaseXML));
    }

    public void stateChanged(InputWizardEvent ev) {
        if (ev.getState() == InputWizardEvent.FINISHED) {
            String baseDir = projectInfo.getProjectDirectory();
            initializeInputData(baseDir);
            node.selectMe();
            parent.init();
            logger.debug(projectInfo + " " + projectInfo.getParent());
            controller.cleanUp();
        } else if (ev.getState() == InputWizardEvent.TO_NEXT) {
            initializeInputData(projectInfo.getProjectDirectory());
        } else if (ev.getState() == InputWizardEvent.CANCELED
                || ev.getState() == InputWizardEvent.CANCELED_ERR
                || ev.getState() == InputWizardEvent.FINISHED_ERR) {
            ProjectBrowserUtils.remove(node);
        }
    }

    private JComboBox typeCombo;

    private String[] typeChoice = { "SCF" };

    private JTextField iniFileName;

    private JComboBox initFileCombo;

    private String[] initFileChoice = { "from template", "wizard", "scratch" };

    private PathSelector selector;

    class IniWiz implements InputWizardRoot {
        private InputWizardController controller;

        IniWiz() {
            initializeRootCombo();
        }

        public void setParent(InputWizardController controller) {
            this.controller = controller;
        }

        public void setProperties(HashMap properties) {
        }

        private Input input;

        public void setInput(Input input) {
            this.input = input;
        }

        public String process() {
            return null;
        }

        public boolean hasPrevious() {
            return false;
        }

        public boolean hasNext() {
            return hasNext;
        }

        public boolean hasFinished() {
            return hasFin;
        }

        private final Document rootWizDoc = ciss.phase_viewer.jdom.XMLUtils
                .getDocumentFromURL(PhaseInitializer.class
                        .getResource("/ciss/phase_viewer/plugins/projectmanipulator/phase/inputwizard/InputWizardRoot.xml"));

        public Document getSpecDocument() {
            Element root = rootWizDoc.getRootElement();
            java.util.List roots = root.getChildren("root");
            for (int i = 0; i < roots.size(); i++) {
                Element ele = (Element) roots.get(i);
                if (typeCombo.getSelectedItem().equals(
                        ele.getChildTextTrim("name"))) {
                    Document ret = ciss.phase_viewer.jdom.XMLUtils
                            .getDocumentFromURL(PhaseInitializer.class
                                    .getResource(ele
                                            .getChildTextTrim("specfile")));
                    return ret;
                }
            }

            return null;
        }

        public String getName() {
            return "initial input";
        }

        private JPanel panel;

        public JPanel getGUI() {
            createPanel();
            return panel;
        }

        private boolean hasNext = true;

        private boolean hasFin = false;

        private void update() {
            controller.updateButtons(this);
        }

        private void initializeRootCombo() {
            Element root = rootWizDoc.getRootElement();
            java.util.List list = root.getChildren("root");
            java.util.Vector names = new java.util.Vector();
            for (int i = 0; i < list.size(); i++) {
                names.addElement(((Element) list.get(i))
                        .getChildTextTrim("name"));
            }
            typeCombo = new JComboBox(names);
            typeCombo.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    controller.resetWizards();
                }
            });
            typeCombo.setEnabled(false);
        }

        private void createPanel() {
            panel = new JPanel();
            panel.setLayout(new BorderLayout());
            JPanel typePanel = new JPanel();
            typePanel.setLayout(new BorderLayout());
            typePanel.setBorder(new TitledBorder("wizard type"));
            typePanel.add(typeCombo, BorderLayout.WEST);
            panel.add(typePanel, BorderLayout.SOUTH);

            iniFileName = new JTextField(10);
            iniFileName.setText("nfinp.data");
            JPanel iniName = new JPanel();
            iniName.setBorder(new TitledBorder("file name"));
            iniName.add(iniFileName);
            initFileCombo = new JComboBox(initFileChoice);
            JPanel tmp = new JPanel();
            tmp.add(initFileCombo);
            JPanel initPanel = new JPanel();
            initPanel.setBorder(new TitledBorder("initial input file"));
            initPanel.setLayout(new BoxLayout(initPanel, BoxLayout.Y_AXIS));
            // initPanel.add(iniName);
            JPanel tmpco = new JPanel();
            tmpco.setLayout(new BoxLayout(tmpco, BoxLayout.X_AXIS));
            tmpco.add(tmp);
            JPanel psele = new JPanel();
            selector = new PathSelector("", 20, PathSelector.FILE_PROJ_BROWSER);
            psele.add(selector);
            tmpco.add(psele);
            initPanel.add(tmpco);
            panel.add(initPanel, BorderLayout.NORTH);

            initFileCombo.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    boolean tmpb = false;
                    if (initFileCombo.getSelectedIndex() == 0) {
                        tmpb = true;
                        hasNext = false;
                        hasFin = new File(selector.getRawPath()).exists();
                        typeCombo.setEnabled(false);
                    } else if (initFileCombo.getSelectedIndex() == 1) {
                        tmpb = false;
                        hasNext = true;
                        hasFin = false;
                        typeCombo.setEnabled(true);
                    } else {
                        tmpb = false;
                        hasNext = false;
                        hasFin = true;
                        typeCombo.setEnabled(false);
                    }
                    selector.setEnabled(tmpb);
                    update();
                }
            });

            selector.getTextField().addCaretListener(new CaretListener() {
                public void caretUpdate(CaretEvent e) {
                    if (initFileCombo.getSelectedIndex() != 0)
                        return;
                    if (new File(selector.getRawPath()).exists())
                        hasFin = true;
                    else
                        hasFin = false;
                    update();
                }
            });

            initFileCombo.setSelectedIndex(0);
        }

        public String getDescription() {
            return "specify calculation type & input file creation method";
        }

        public void stateChanged(InputWizardEvent ev) {
            if (ev.getState() == InputWizardEvent.FINISHED) {
            }
        }

        public int getNumWizards() {
            if (initFileCombo.getSelectedIndex() == 1) {
                return -1;
            }
            return 1;
        }

    }

}
