/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/09/01, 18:12
!  AUTHOR(S): KOGA, Junichiro
!  File : AtomStateList.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.atomcoord;

import java.util.Vector;

import org.apache.log4j.Logger;

/**
 * 原子配置の"状態"を保持しておくクラス
 * 
 * @author
 */
public class AtomStateList {
    private Logger logger = Logger.getLogger(AtomStateList.class.getName());
    private Vector stateVector;

    private int origNumAt;

    /**
     * @param numAt
     *            この時点での原子の数
     */
    public AtomStateList(int numAt) {
        origNumAt = numAt;
        stateVector = new Vector();
        for (int i = 0; i < numAt; i++) {
            stateVector.addElement(new AtomState(AtomState.UNCHANGED, i));
        }
    }

    /**
     * インデックスが単純な昇順でない場合, このコンストラクターを利用して オリジナルのインデックスを指定する.
     * 
     * @param インデックス配列
     */
    public AtomStateList(int[] indeces) {
        origNumAt = indeces.length;
        stateVector = new Vector();
        for (int i = 0; i < origNumAt; i++) {
            stateVector.addElement(new AtomState(AtomState.UNCHANGED,
                    indeces[i]));
        }
    }

    private int getNumAdded() {
        int ret = 0;
        for (int i = 0; i < stateVector.size(); i++) {
            AtomState as = (AtomState) stateVector.get(i);
            if (as.mode == AtomState.ADDED)
                ret++;
        }
        return ret;
    }

    /**
     * 元々のインデックスを指定すると, 新しいインデックスを返す配列を返す ただし削除された原子に対応する「元々のインデックス」の場合負の数を返す.
     * 
     * @return 上記の通り
     */
    public int[] getIndexMap() {
        int added = getNumAdded();
        int[] ret = new int[origNumAt + added];
        for (int i = 0; i < stateVector.size(); i++) {
            AtomState as = (AtomState) stateVector.get(i);
            if (as.mode != AtomState.REMOVED) {
                ret[as.origIndex] = as.index;
            } else {
                ret[as.origIndex] = -1;
            }
        }
        return ret;
    }

    /**
     * 原子を追加する場合に呼ぶ
     */
    public void atomAdded() {
        logger.debug("atom added");
        // int index = stateVector.size()-1;
        // for ( int i=0 ; i<stateVector.size() ; i++ ) {
        // AtomState as = (AtomState) stateVector.get(i);
        // if ( as.index >= index ) as.index++;
        // }
        int natNow = getNumAt();
        stateVector.addElement(new AtomState(AtomState.ADDED, natNow));
    }

    /**
     * 指定の場所に原子を追加する場合によぶ
     */
    public void atomAdded(int index) {
        logger.debug("atom added at " + index);
        for (int i = 0; i < stateVector.size(); i++) {
            AtomState as = (AtomState) stateVector.get(i);
            if (as.index >= index)
                as.index++;
        }
        stateVector.add(new AtomState(AtomState.ADDED, index));
    }

    /**
     * 原子を削除した場合に呼ぶ
     * 
     * @param removed
     *            削除した原子のインデックス
     */
    public void atomRemoved(int removed) {
        if (removed < 0 || removed >= stateVector.size())
            return;
        for (int i = 0; i < stateVector.size(); i++) {
            AtomState as = (AtomState) stateVector.get(i);
            if (as.index > removed)
                as.index--;
        }
        stateVector.set(removed, new AtomState(AtomState.REMOVED, removed));
    }

    /**
     * 原子の属性を変更した場合によぶ
     * 
     * @param mod
     *            変更した原子のインデックス
     */
    public void atomModified(int mod) {
        if (mod < 0 || mod >= stateVector.size())
            return;
        stateVector.set(mod, new AtomState(AtomState.MODIFIED, mod));
    }

    /**
     * (現在の)原子の数を取得
     * 
     * @return 現在の原子の数
     */
    public int getNumAt() {
        int ret = 0;
        for (int i = 0; i < stateVector.size(); i++) {
            if (((AtomState) stateVector.get(i)).mode == AtomState.REMOVED)
                continue;
            ret++;
        }
        if (ret < 0)
            ret = 0;
        return ret;
    }

    /**
     * 結果を取得; 配列のインデックスが原子のインデックスで, ADDEDの場合はそれは足しこまれた原子, REMOVEDの場合は削除された原子,
     * MODIFIEDの場合は変更された原子, UNCHANGEDの場合はなにも起こらなかった原子を意味する 配列はindexの昇順になっている.
     * 
     * @return 結果を格納した配列
     */
    public AtomState[] getResults() {
        AtomState[] res = new AtomState[stateVector.size()];
        stateVector.copyInto(res);
        java.util.Arrays.sort(res);
        return res;
    }

    //
    // /**
    // * 古いインデックスから新しいインデックスを返す
    // */
    // public int [] oldIndex2NewIndex() {
    // int [] ret = new int[origNumAt];
    // int count = 0;
    // for ( int i=0 ; i<stateVector.size() ; i++ ) {
    // int state = ((Integer)stateVector.get(i)).intValue();
    // if ( state == MODIFIED || state == UNCHANGED ) {
    // ret[count] = i;
    // count++;
    // } else if ( state == REMOVED ) {
    // ret[count] = -1;
    // count++;
    // }
    // }
    // return ret;
    // }
    //
    // /**
    // * 新しいインデックスを指定すると, 古いインデックスを返す配列を取得. 元々なかった原子(足された原子)の場合-1を得る
    // * @return 上記の通り
    // */
    // public int [] getIndexMap() {
    // Vector vec = new Vector();
    // int count=0;
    // for ( int i=0 ; i<stateVector.size() ; i++ ) {
    // int state = ((Integer)stateVector.get(i)).intValue();
    // if ( state != ADDED ) {
    // vec.addElement(new Integer(count));
    // count++;
    // } else {
    // vec.addElement(new Integer(-1));
    // }
    // }
    //
    // Integer [] inte = new Integer[vec.size()];
    // vec.copyInto(inte);
    // int [] ret = new int[inte.length];
    // for ( int i=0 ; i<inte.length ; i++ ) {
    // ret[i] = inte[i].intValue();
    // }
    //
    // return ret;
    // }
    //
    // /**
    // * 足した原子のインデックスを取得 小さい順に並ぶようになっている
    // * @return 上記の通り
    // */
    // public int [] getIndecesOfAddedAtoms() {
    // Vector vec = new Vector();
    //
    // for ( int i=0 ; i<stateVector.size() ; i++ ) {
    // int state = ((Integer)stateVector.get(i)).intValue();
    // if ( state == ADDED ) {
    // vec.addElement(new Integer(i));
    // }
    // }
    //
    // Integer [] inte = new Integer[vec.size()];
    // vec.copyInto(inte);
    // int [] ret = new int[inte.length];
    // for ( int i=0 ; i<inte.length ; i++ ) {
    // ret[i] = inte[i].intValue();
    // }
    //
    // Arrays.sort(ret);
    //
    // return ret;
    // }
    //
    // /**
    // * 削除された原子のインデックスを取得 小さい順にならぶ
    // * @return 上記の通り
    // */
    // public int [] getIndecesOfRemovedAtoms() {
    // Vector vec = new Vector();
    //
    // for ( int i=0 ; i<stateVector.size() ; i++ ) {
    // int state = ((Integer)stateVector.get(i)).intValue();
    // if ( state == REMOVED ) {
    // vec.addElement(new Integer(i));
    // }
    // }
    //
    // Integer [] inte = new Integer[vec.size()];
    // vec.copyInto(inte);
    // int [] ret = new int[inte.length];
    // for ( int i=0 ; i<inte.length ; i++ ) {
    // ret[i] = inte[i].intValue();
    // }
    //
    // Arrays.sort(ret);
    //
    // return ret;
    // }
    //
    /**
     * 元の原子数を取得
     * 
     * @return 元の原子数
     */
    public int getOrigNumAt() {
        return this.origNumAt;
    }

}
