/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2005/11/21, 11:15
!  AUTHOR(S): KOGA, Junichiro
!  File : DataSetCollection.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.graph.dataset;

import java.util.HashMap;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

/**
 * 「DataSet」をひとまとめにして管理するクラス. データセットを登録 -> その内のいくつかをdomain, range用データとして登録
 * (これを「データセットセット」と呼ぼう) -> グラフツールに渡す, という操作を行う. 各データセットセットは, 各々一つの軸に相当する.
 * rangeの場合, 一つの軸に複数の データが存在する可能性がある.
 * 
 * @author
 */
public class DataSetCollection {
    private Logger logger = Logger.getLogger(DataSetCollection.class.getName());
    private Vector dsetVector = new Vector();
    private Vector dsetSet = new Vector();

    private String name = "";

    /**
     * なにも登録されてない状態での初期化.
     * 
     * @param name
     *            このデータセットコレクションの名前.
     */
    public DataSetCollection(String name) {
        this.name = name;
        initData();
    }

    /**
     * この「データセットコレクション」の名前を返す.
     * 
     * @return このデータセットコレクションに割り当てられた名前.
     */
    public String getName() {
        return name;
    }

    public int getDataSetCollectionCount() {
        return dsetSet.size();
    }

    /**
     * rangeやdomainの情報を初期化.
     */
    public void initData() {
        dsetSet = new Vector();
    }

    private DataSetSet getDataSetSet(int ID) {
        for (int i = 0; i < dsetSet.size(); i++) {
            if (ID == ((DataSetSet) dsetSet.get(i)).getID()) {
                return (DataSetSet) dsetSet.get(i);
            }
        }
        DataSetSet set = new DataSetSet(ID);
        dsetSet.addElement(set);
        return set;
    }

    /**
     * rangeを, デフォルトのDataSetSetに登録.
     * 
     * @param dse
     *            登録したいrange情報
     */
    public void addRange(DataSetElement dse) {
        addRange(0, dse);
    }

    /**
     * rangeを追加. 引数の識別子によって識別されるデータセットセットに登録される.
     * 
     * @param ID
     *            この識別子によって識別されるデータセット・セットに登録される.
     * @param dse
     *            追加したいrange情報を持つDataSetElement
     */
    public void addRange(int ID, DataSetElement dse) {
        DataSetSet set = getDataSetSet(ID);
        set.addRange(dse);
    }

    /**
     * domainを, デフォルトのDataSetSetに登録.
     * 
     * @param dse
     *            登録したいdomain情報
     */
    public void setDomain(DataSetElement dse) {
        setDomain(0, dse);
    }

    /**
     * domainを新規登録. 引数の識別子によって識別されるデータセットセットに登録される.
     * 
     * @param ID
     *            この識別子によって識別されるデータセット・セットに登録される.
     * @param dse
     *            新規登録したい情報を持つDataSetElement
     */
    public void setDomain(int ID, DataSetElement dse) {
        DataSetSet set = getDataSetSet(ID);
        set.setDomain(dse);
    }

    /**
     * domain 軸の名前をセット.
     * 
     * @param ID
     *            セットしたい軸のデータセットのID
     * @param domainAxisName
     *            domain axisの名前
     */
    public void setDomainAxisName(int ID, String domainAxisName) {
        DataSetSet set = getDataSetSet(ID);
        set.setDomainAxisName(domainAxisName);
    }

    /**
     * range 軸の名前をセット.
     * 
     * @param ID
     *            セットしたい軸のデータセットのID
     * @param rangeAxisName
     *            range axisの名前
     */
    public void setRangeAxisName(int ID, String rangeAxisName) {
        DataSetSet set = getDataSetSet(ID);
        set.setRangeAxisName(rangeAxisName);
    }

    /**
     * 軸の名前をゲット
     * 
     * @param ID
     *            ゲットしたい軸名のID
     * @return 軸の名前を確保した文字列配列; 第0要素がdomain, 第2要素がrangeに相当.
     */
    public String[] getAxisNames(int ID) {
        DataSetSet set = getDataSetSet(ID);
        return set.getAxisNames();
    }

    /**
     * range軸の名前をゲット
     * 
     * @param ID
     *            欲しい軸名のID
     * @return range軸の名前
     */
    public String getRangeAxisName(int ID) {
        DataSetSet set = getDataSetSet(ID);
        return set.getRangeAxisName();
    }

    /**
     * domain軸の名前をゲット
     * 
     * @param ID
     *            欲しい軸名のID
     * @return domain軸の名前
     */
    public String getDomainAxisName(int ID) {
        DataSetSet set = getDataSetSet(ID);
        return set.getDomainAxisName();
    }

    /**
     * IDによって指定されるdomainなDataSetElementを返す.
     * 
     * @return domainとされているDataSetElement
     */
    public DataSetElement getDomain(int ID) {
        DataSetSet set = getDataSetSet(ID);
        return set.getDomain();
    }

    /**
     * デフォルトのdomainなDataSetElementを返す.
     * 
     * @param domainとされているDataSetElement
     */
    public DataSetElement getDomain() {
        DataSetSet set = getDataSetSet(0);
        return set.getDomain();
    }

    /**
     * 引数で識別されるデータセットセットに登録されているrangeデータの配列を返す.
     * 
     * @param ID
     *            識別子
     */
    public DataSetElement[] getRange(int ID) {
        DataSetSet set = getDataSetSet(ID);
        return set.getRange();
    }

    /**
     * デフォルトデータセットセットに登録されているrangeなDataSetElementの配列を返す.
     * 
     * @return rangeとされているDataSetElement
     */
    public DataSetElement[] getRange() {
        return getRange(0);
    }

    private HashMap pieDataSet = new HashMap();

    /**
     * IDで指定されるデータを, DefaultPieDatasetに変換して返す.
     * 
     * @param ID
     *            欲しいデータのID.
     * @param IDに対応するDefaultPieDataset
     */
    public DefaultPieDataset getPieDataset(int ID) {
        Object obj = pieDataSet.get(String.valueOf(ID));
        if (obj != null) {
            return (DefaultPieDataset) obj;
        }
        DefaultPieDataset piedata = new DefaultPieDataset();
        DataSetElement delem = getDomain(ID);
        DataSetElement[] relem = getRange(ID);
        if (delem == null || relem == null) {
            return null;
        }
        String[] ident = delem.getData();
        String[] value = relem[0].getData();
        for (int i = 0; i < ident.length; i++) {
            try {
                piedata.setValue(ident[i], Double.parseDouble(value[i]));
            } catch (NumberFormatException npe) {
                for (int j = 0; j < ident.length; j++) {
                    try {
                        piedata.setValue(value[j], Double.parseDouble(ident[j]));
                    } catch (NumberFormatException npe2) {
                        logger.error("invalid data");
                        return null;
                    }
                }
                break;
            }
        }
        pieDataSet.put(String.valueOf(ID), piedata);
        return piedata;
    }

    private HashMap xySeriesCollection = new HashMap();

    /**
     * IDで指定されるデータを, XYSeriesCollectionに変換して返す.
     * 
     * @param ID
     *            欲しいデータのID.
     * @return IDに対応するXYSeriesCollection.
     */
    public XYSeriesCollection getXYSeriesCollection(int ID) {
        Object obj = xySeriesCollection.get(String.valueOf(ID));
        if (obj != null) {
            return (XYSeriesCollection) obj;
        }

        XYSeriesCollection collection = new XYSeriesCollection();
        DataSetElement delem = getDomain(ID);
        DataSetElement[] relem = getRange(ID);
        if (delem == null || relem == null) {
            return null;
        }

        String[] domainData = delem.getData();
        if (domainData == null || domainData.length == 0) {
            return null;
        }
        double[] ddomainData = new double[domainData.length];
        try {
            for (int j = 0; j < domainData.length; j++) {
                if (domainData[j] == null)
                    continue;
                ddomainData[j] = Double.parseDouble(domainData[j].replace('D',
                        'E'));
                logger.debug("dsetx at " + j + ": " + ddomainData[j]);
            }
        } catch (NumberFormatException nfe) {
            logger.error("domain data: not a number. ");
            return null;
        }
        for (int ra = 0; ra < relem.length; ra++) {
            DataSetElement dsete = relem[ra];
            XYSeries series = new XYSeries(dsete.getFullName(), true, true);
            try {
                String[] str = dsete.getData();
                if (str == null || str.length == 0) {
                    continue;
                }
                for (int j = 0; j < str.length; j++) {
                    if (str[j] == null)
                        continue;
                    double d = Double.parseDouble(str[j].replace('D', 'E'));
                    logger.debug("range data for " + dsete.getName() + " at "
                            + j + ": " + str[j]);
                    series.add(ddomainData[j], d);
                }
            } catch (NumberFormatException npe) {
                logger.warn("data no. " + ra + " of " + ID
                        + " was not a number; ignoring.");
                continue;
            } catch (ArrayIndexOutOfBoundsException aiobe) {
                logger.error("inconsistent data");
                return null;
            }
            collection.addSeries(series);
        }
        xySeriesCollection.put(String.valueOf(ID), collection);
        return collection;
    }

}

class DataSetSet {
    private int ID;
    private DataSetElement domain;
    private Vector range = new Vector();

    private String domainAxisName = "domain axis";
    private String rangeAxisName = "range axis";

    protected DataSetSet(int ID) {
        this.ID = ID;
        domainAxisName += String.valueOf(ID);
        rangeAxisName += String.valueOf(ID);
    }

    protected void setDomainAxisName(String domainAxisName) {
        this.domainAxisName = domainAxisName;
    }

    protected void setRangeAxisName(String rangeAxisName) {
        this.rangeAxisName = rangeAxisName;
    }

    protected String getDomainAxisName() {
        return domainAxisName;
    }

    protected String getRangeAxisName() {
        return rangeAxisName;
    }

    protected String[] getAxisNames() {
        return new String[] { domainAxisName, rangeAxisName };
    }

    protected int getID() {
        return this.ID;
    }

    protected void addRange(DataSetElement ra) {
        range.addElement(ra);
    }

    protected void setRange(DataSetElement ra) {
        range = new Vector();
        range.addElement(ra);
    }

    protected void setDomain(DataSetElement doma) {
        this.domain = doma;
    }

    protected DataSetElement[] getRange() {
        if (range == null) {
            return null;
        }
        DataSetElement[] ra = new DataSetElement[range.size()];
        range.copyInto(ra);
        return ra;
    }

    protected DataSetElement getDomain() {
        return domain;
    }

}
