/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/09/27, 15:31
!  AUTHOR(S): KOGA, Junichiro
!  File : BasicOperations.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.acviewer.operations;

import java.util.Arrays;
import java.util.Vector;

import org.apache.log4j.Logger;

import ciss.phase_viewer.acviewer.MainPanel;
import ciss.phase_viewer.acviewer.scenegraphelements.TGAtom;
import ciss.phase_viewer.acviewer.scenegraphelements.atom.AtomObject;
import ciss.phase_viewer.atomcoord.Atom;
import ciss.phase_viewer.atomcoord.AtomCoords;
import ciss.phase_viewer.atomcoord.AtomEvent;
import ciss.phase_viewer.atomcoord.AtomListener;

/**
 * 原子配置に基本的な編集を行うための各種メソッドを配備
 * 
 * @author
 */
public class BasicOperations implements AtomListener {
    private Logger logger = Logger.getLogger(BasicOperations.class.getName());
    private TGAtom tgatom;
    private MainPanel parent;

    public BasicOperations(MainPanel parent) {
        this.parent = parent;
        this.tgatom = (TGAtom) parent.getRootTransform();
    }

    /**
     * 指定の原子を削除
     */
    public void removeAtoms(AtomObject[] atoms) {
        if (atoms == null || atoms.length == 0) {
            return;
        }
        AtomCoords coords = tgatom.getConfigData().getAtomCoords();
        coords.saveState();
        Vector indexVector = new Vector();
        for (int i = 0; i < atoms.length; i++) {
            int id = Integer.parseInt(atoms[i].getID()) - 1;
            indexVector.addElement(new Integer(id));
        }
        if (indexVector.size() == 0) {
            return;
        }
        Integer[] indeces = new Integer[indexVector.size()];
        indexVector.copyInto(indeces);
        Arrays.sort(indeces);
        for (int i = indeces.length - 1; i >= 0; i--) {
            coords.getAtomList().removeAtomAt(indeces[i].intValue());
        }

        coords.getAtomList().setUndoCount(atoms.length);

        if (!wait) {
            redraw();
        }
    }

    /**
     * シーン上で"選択中"の原子をすべて削除
     */
    public void removeSelectedAtoms() {
        AtomObject[] atoms = tgatom.getSelectedAtoms();
        removeAtoms(atoms);
    }

    private void redraw() {
        AtomCoords coords = tgatom.getConfigData().getAtomCoords();
        tgatom.getConfigData().isRenderingManual(true);
        parent.prepareRedraw();
        parent.getCD().setCoords(coords);
        parent.postRedraw();
        parent.getCD().isRenderingManual(false);
        coords.finalizeState();
        wait = false;
    }

    /**
     * 選択中の原子の属性値を変更するメソッド. 引数で与えられる属性値が, 選択中の全原子に適用される.
     * 
     * @param elementName
     *            元素名
     * @param auxvec
     *            auxiliaryな情報を格納したVector
     */
    public void modifyAttributesOfSelectedAtoms(String elementName,
            Vector auxvec) {
        AtomObject[] selectedAtoms = tgatom.getSelectedAtoms();
        AtomCoords coords = tgatom.getConfigData().getAtomCoords();
        if (selectedAtoms == null || selectedAtoms.length == 0)
            return;
        for (int j = 0; j < selectedAtoms.length; j++) {
            int id = Integer.parseInt(selectedAtoms[j].getID()) - 1;
            ciss.phase_viewer.atomcoord.Atom at = coords.getAtomList()
                    .getAtomAt(id);
            if (elementName.trim().length() != 0) {
                at.setElementName(elementName);
            }
            if (auxvec.size() != 0) {
                at.setAuxil(auxvec);
            }
        }
        if (!wait)
            redraw();
    }

    /**
     * 選択中の原子の座標を並進する
     * 
     * @param x
     *            x方向の並進
     * @param y
     *            y方向の並進
     * @param z
     *            z方向の並進
     */
    public void translateSelectedAtoms(double x, double y, double z) {
        AtomObject[] selectedAtoms = tgatom.getSelectedAtoms();
        AtomCoords coords = tgatom.getConfigData().getAtomCoords();
        for (int i = 0; i < selectedAtoms.length; i++) {
            int id = Integer.parseInt(selectedAtoms[i].getID()) - 1;
            double[] pos = parent.getCD().getPos(id);
            pos[0] += x;
            pos[1] += y;
            pos[2] += z;
            ciss.phase_viewer.atomcoord.Atom atnow = coords.getAtomList()
                    .getAtomAt(id);
            ciss.phase_viewer.atomcoord.Atom newatom = atnow.getCopy();
            newatom.setPos(pos);
            coords.getAtomList().replaceAtomAt(id, newatom);
        }
        coords.getAtomList().setUndoCount(selectedAtoms.length);
        if (!wait)
            redraw();
    }

    private boolean wait = false;

    /**
     * これをtrueにセットしておくと, 明示的にシーンを再描画するよう指示しない限りシーンの再描画は行われない.
     * 
     * @param wait
     *            シーンの再描画をコントロールしたい場合trueとする
     */
    public void wait(boolean wait) {
        this.wait = wait;
    }

    /**
     * 強制的に再描画するメソッド
     */
    public void doUpdate() {
        redraw();
    }

    public void atomStateChanged(AtomEvent e) {
        ciss.phase_viewer.atomcoord.Atom atom = e.getAtom();
        int ind = e.getIndex();
        ciss.phase_viewer.atomcoord.AtomCoords coords = parent.getCD()
                .getAtomCoords();
        logger.debug("atom now: " + coords.getAtomList().getAtomAt(ind));
        Atom at = coords.getAtomList().getAtomAt(ind);
        Atom newat = at.getCopy();
        newat.setElementName(atom.getElementName());
        newat.setPos(atom.getPos());
        newat.setAuxil(atom.getAuxil());
        coords.replaceAtomAt(ind, newat);
        logger.debug("AtomStateChanged: " + e);
        if (!wait)
            redraw();
    }

}
