/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/06/01, 21:08
!  AUTHOR(S): KOGA, Junichiro
!  File : ChaseFile.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.file;

import java.io.File;
import java.util.LinkedHashMap;
import java.util.Vector;

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

import ciss.phase_viewer.common.RegExpedString;
import ciss.phase_viewer.jdom.MyElement;

/**
 * Chase用のFile... 通常のファイルの各種機能に加え, 便利な属性を色々持っている. ように作る. ただし,
 * java.io.Fileのサブクラスというわけではなく, そういうフィールドを持っている.
 * ChaseFileManagerなるクラスによってインスタンス化される, という仕組みにするとよいのでは.
 * 
 * @author
 */
public class ChaseFile {
    private Logger logger = Logger.getLogger(ChaseFile.class.getName());

    private String identifier;

    private Element fileInfoElement;

    private File file;

    private String fileName;

    private String parentPath;

    public static final String INTENT = "intent";

    public static final String IDENT = "identifier";

    public static final String DEFAULTNAME = "defaultname";

    public static final String BASEDIR = "basedir";

    public static final String FNAME = "filename";

    public static final String TRANSFER_INFO = "transfer_info";

    public static final String FILENAME_EDITLEVEL = "filename_editlevel";

    public static final String RELATIVE_PATH = "relative_path";

    public static final String OUTPUT_PARSER = "output_parser";

    private String intent;

    private RegExpedString ident;

    private RegExpedString defName;

    private String defaultName;

    private String fileNameEditLevel;

    public static String ALWAYS = "always";

    public static String NEVER = "never";

    public static String ON_DEMAND = "on_demand";

    private String outputParser = "";

    private String monitor = "";

    private boolean monitorable = false;

    private String filename = "";

    private String relative_path = ".";

    public static String ALL = "ALL";

    public static String NEWEST_ONLY = "NEWEST_ONLY";

    private String transfer = ALL;

    private boolean upload = false;

    private boolean download = false;

    public static String OVERWRITE = "OVERWRITE";

    public static String DO_NOTHING = "DO_NOTHING";

    public static String APPEND = "APPEND";

    public static String RENAME = "RENAME";

    public static String RENAME_LOCAL = "RENAME_LOCAL";

    private String duplicate_file = OVERWRITE;

    private Element elem;

    private Vector fileChangeListeners = new Vector();

    private LinkedHashMap chaseFileInfoSpec = new LinkedHashMap();

    public ChaseFile(Element elem, LinkedHashMap chaseFileInfoSpec) {
        this.elem = elem;
        this.chaseFileInfoSpec = chaseFileInfoSpec;
        create();
    }

    public ChaseFile(Element elem) {
        this.elem = elem;
        create();
    }

    protected void recreate() {
        create();
    }

    public Element getElement() {
        return this.elem;
    }

    public void addFileChangeListener(FileChangeListener listener) {
        fileChangeListeners.addElement(listener);
    }

    public void removeFileChangeListener(FileChangeListener listener) {
        fileChangeListeners.remove(listener);
    }

    public void fileStateChanged() {
        for (int i = 0; i < fileChangeListeners.size(); i++) {
            ((FileChangeListener) fileChangeListeners.get(i))
                    .fileChanged(new ChaseFileChangeEvent(this));
        }
    }

    /**
     * このファイルの情報を更新. 無い場合は新たに足す.
     * 
     * @param key
     *            更新したい情報の識別子.
     * @param val
     *            更新したい値.
     */
    public void update(String key, String val) {
        ChaseFileInfoSpec spec = null;
        if (chaseFileInfoSpec != null) {
            Object obj = chaseFileInfoSpec.get(key);
            if (obj != null) {
                spec = (ChaseFileInfoSpec) obj;
            }
        }

        boolean isPathString = false;
        if (spec != null)
            isPathString = spec.getType().equals(
                    ChaseFileInfoSpec.TYPE_PATH_STR);

        Element ele = elem.getChild(key);
        if (ele == null) {
            Element newEle = new Element(key);
            if (!isPathString) {
                newEle.setText(val);
            } else {
                newEle.setText(MyElement.encode(val));
            }
            elem.addContent(newEle);
            return;
        }
        if (!isPathString) {
            ele.setText(val);
        } else {
            ele.setText(MyElement.encode(val));
        }
        create();
    }

    /**
     * このファイルの情報を更新. 真偽値の場合はこれを使う.
     * 
     * @param key
     *            更新したい情報の識別子
     * @param val
     *            更新したい値
     */
    public void update(String key, Boolean b) {
        String val = b.toString();
        update(key, val);
    }

    /**
     * 引数の文字列によってupload()を返す場合もあればdownload()を返す場合もある関数.
     * 
     * @param "upload"の場合upload()を, "download"の場合download()をよぶ.
     * @return upload()ないしdownload()の結果. どちらでもない場合false.
     */
    public boolean upload_or_download(String upload_or_download) {
        if (upload_or_download.equalsIgnoreCase("upload")) {
            return upload();
        } else if (upload_or_download.equalsIgnoreCase("download")) {
            return download();
        }
        return false;
    }

    private void create() {
        // intent
        intent = elem.getChildTextTrim("intent");

        // identifier
        ident = new RegExpedString(elem.getChild("identifier"));

        // defaultname
        defName = new RegExpedString(elem.getChild("defaultname"));

        // filename
        filename = elem.getChildTextTrim("filename");

        // relative path
        relative_path = elem.getChildTextTrim("relative_path");

        // filenameseditlevel
        fileNameEditLevel = elem.getChildTextTrim("filenameeditlevel");

        // OutputParser
        outputParser = elem.getChildTextTrim("output_parser");

        // file monitor
        monitor = elem.getChildTextTrim("monitor");
        if (monitor != null && monitor.trim().length() != 0) {
            monitorable = true;
        }

        transfer = elem.getChildTextTrim("transfer");
        upload = new Boolean(elem.getChildTextTrim("upload")).booleanValue();
        download = new Boolean(elem.getChildTextTrim("download"))
                .booleanValue();
        duplicate_file = elem.getChildTextTrim("duplicate_file");

        logger.debug("ident: " + ident.getValue() + " filename: " + filename
                + " duplicate_file: " + duplicate_file + " monitor: " + monitor);
    }

    public String getIntent() {
        return this.intent;
    }

    public RegExpedString getIdentifier() {
        return this.ident;
    }

    public RegExpedString getDefaultName() {
        return this.defName;
    }

    public String getFileName() {
        if (filename == null || filename.trim().length() == 0) {
            return this.defaultName;
        }
        return this.filename;
    }

    public Object getValue(String ident) {
        Element child = elem.getChild(ident);
        if (child == null) {
            return null;
        }
        String str = child.getTextTrim();
        if (str.equals("true") || str.equals("false")) {
            return new Boolean(str);
        }

        boolean type_path = false;
        if (chaseFileInfoSpec != null) {
            Object obj = chaseFileInfoSpec.get(ident);
            if (obj != null) {
                type_path = ((ChaseFileInfoSpec) obj).getType().equals(
                        ChaseFileInfoSpec.TYPE_PATH_STR);
            }
        }

        String ret = str;
        if (type_path) {
            ret = MyElement.decode(str);
        }
        logger.debug("ChaseFile.getValue: type: path? " + type_path
                + " returning: " + ret);
        return ret;
    }

    public String getFileNameEditLevel() {
        return this.fileNameEditLevel;
    }

    public String getOutputParserPath() {
        return this.outputParser;
    }

    public String getTransfer() {
        return this.transfer;
    }

    public boolean upload() {
        return this.upload;
    }

    public boolean download() {
        return this.download;
    }

    public String getDuplicateFile() {
        return this.duplicate_file;
    }

    public String getRelativePath() {
        return MyElement.decode(this.relative_path);
    }

    public boolean isMonitorable() {
        return monitorable;
    }

    public String getMonitorPath() {
        return monitor;
    }

    public String toString() {
        return getFileName();
    }
}
