/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2005/11/07, 19:14
!  AUTHOR(S): KOGA, Junichiro
!  File : OutputInterface.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.outputinterface;

import java.io.Serializable;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.JPanel;

import org.apache.log4j.Logger;

import ciss.phase_viewer.file.ChaseFile;
import ciss.phase_viewer.file.ChaseFileManager;
import ciss.phase_viewer.graph.DataPanel;
import ciss.phase_viewer.main.PluginLoader;
import ciss.phase_viewer.projectbrowser.ProjectInfo;

/**
 * OutputDataやOutputParserクラスを制御するクラス.
 * 
 * @author
 */
public class OutputInterface implements Serializable {
    private Logger logger = Logger.getLogger(OutputInterface.class.getName());

    private ChaseFileManager cfManager;
    private OutputParser outputParser;

    private ProjectInfo projectInfo;

    public OutputInterface(ChaseFileManager cfManager) {
        this.cfManager = cfManager;
    }

    /**
     * このパーサーに関連付けられたProjectInfoへの参照を返す.
     * 
     * @return このパーサーに関連付けられたProjectInfo.
     */
    public ProjectInfo getProjectInfo() {
        return projectInfo;
    }

    /**
     * このパーサーに関連付けられたProjectInfoへの参照を設定する.
     * 
     * @param このパーサーに関連付けられたProjectInfo
     *            .
     */
    public void setProjectInfo(ProjectInfo projectInfo) {
        this.projectInfo = projectInfo;
    }

    /**
     * グラフ描画用テーブルに識別子やデータなどを取り込んだ状態で作成する.
     * 
     * @param key
     *            欲しいデータのkey (例えば, DOSならF_DOSなど.)
     * @return グラフ描画用パネル
     */
    public JPanel getDataPanel(String key) {
        if (createOutputParser(key)) {
            if (!outputParser.getParsed()) {
                outputParser.doParse();
            }
            OutputData[] data = outputParser.getOutputData();
            if (data != null && data.length > 1) {
                DataPanel dataPanel = new DataPanel(data);
                return dataPanel;
            } else if (data != null && data.length == 1) {
                DataPanel dataPanel = new DataPanel(data[0]);
                return dataPanel;
            }
        }
        return new JPanel();
    }

    /**
     * ファイル名を直接渡してテーブルを作成 (FileInfoから直接ファイル名を解決できない場合に使用せよ).
     * 
     * @param key
     *            パーサーのkey
     * @param fileName
     *            ファイル名
     */
    public JPanel getDataPanel(String key, String fileName) {
        if (createOutputParser(key, fileName)) {
            if (!outputParser.getParsed()) {
                outputParser.doParse();
            }
            DataPanel dataPanel = new DataPanel(outputParser.getOutputData());
            return dataPanel;
        }
        JPanel ret = new JPanel();
        ret.setLayout(new BoxLayout(ret, BoxLayout.Y_AXIS));
        ret.add(new JPanel());
        return ret;
    }

    /**
     * OutputParserを取得する. nullが返ることも有り得るので注意.
     * 
     * @param key
     *            パーサーの種類.
     * @return このクラスに関連付けられたOutputParserオブジェクト.
     */
    public OutputParser getParser(String key) {
        if (!createOutputParser(key)) {
            return null;
        }
        return this.outputParser;
        // if ( doParse() ) {
        // return this.outputParser;
        // } else {
        // return null;
        // }
    }

    /**
     * OutputParserを取得する. nullが返ることも有り得るので注意.
     * 
     * @param key
     *            パーサーの種類.
     * @param listener
     *            このパーサーに関連付けられたリスナー.
     * @return このクラスに関連付けられたOutputParserオブジェクト.
     */
    public OutputParser getParser(String key, OutputParserListener listener) {
        if (!createOutputParser(key)) {
            return null;
        }
        this.outputParser.addParserListener(listener);
        return this.outputParser;
        // if ( doParse() ) {
        // return this.outputParser;
        // } else {
        // return null;
        // }
    }

    /**
     * OutputParserを取得する. nullが返ることも有り得るので注意. ファイル名も渡す必要がある場合はこちらを利用する.
     * 
     * @param key
     *            パーサーの種類.
     * @param fname
     *            実際のファイル名.
     * @return このクラスに関連付けられたOutputParserオブジェクト.
     */
    public OutputParser getParser(String key, String fname) {
        if (!createOutputParser(key, fname)) {
            return null;
        }

        return this.outputParser;
        // if( doParse() ) {
        // return this.outputParser;
        // } else {
        // return null;
        // }
    }

    /**
     * OutputParserを取得する. nullが返ることも有り得るので注意.
     * 
     * @param key
     *            パーサーの種類.
     * @param fname
     *            実際のファイル名.
     * @param listener
     *            このパーサーに関連付けられたリスナー.
     * @return このクラスに関連付けられたOutputParserオブジェクト.
     */
    public OutputParser getParser(String key, String fname,
            OutputParserListener listener) {
        if (!createOutputParser(key, fname)) {
            return null;
        }
        outputParser.addParserListener(listener);
        return this.outputParser;
        // if ( doParse() ) {
        // return this.outputParser;
        // } else {
        // return null;
        // }
    }

    /**
     * 「load済みのparser情報」をクリア.
     */
    public void initCache() {
        loadedParsers = new Vector();
    }

    private boolean createOutputParser(String key, String fileName) {
        ChaseFile cf = cfManager.getFile(key);
        return loadParser(cf.getOutputParserPath(), fileName);
    }

    private boolean createOutputParser(String key) {
        ChaseFile cf = cfManager.getFile(key);
        String fname = cf.getFileName();
        String relpath = cf.getRelativePath();
        String dir = projectInfo.getProjectDirectory();
        String fileName = dir + System.getProperty("file.separator") + relpath
                + System.getProperty("file.separator") + fname;
        return loadParser(cf.getOutputParserPath(), fileName);
    }

    private Vector loadedParsers = new Vector();

    private boolean loadParser(String parserPath, String fileName) {
        for (int i = 0; i < loadedParsers.size(); i++) {
            OutputParser parser = (OutputParser) loadedParsers.get(i);
            if (fileName.equals(parser.getFileName())) {
                logger.debug("found cached parser...");
                outputParser = parser;
                return true;
            }
        }
        logger.debug("loading parser: " + parserPath + "... file name is: "
                + fileName);
        if (parserPath == null || parserPath.length() == 0) {
            return false;
        }
        outputParser = (OutputParser) PluginLoader.instantiate(parserPath,
                new Object[] { fileName });
        if (outputParser == null) {
            return false;
        }

        outputParser.setParent(this);
        loadedParsers.addElement(outputParser);
        return true;
    }

    private boolean doParse() {
        if (outputParser == null) {
            return false;
        }
        new Thread(new Parse()).start();
        return true;
    }

    class Parse implements Runnable {
        public void run() {
            outputParser.doParse();
        }
    }

}
