/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on ----
!  AUTHOR(S): KOGA, Junichiro
!  File : Animater.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;

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

import org.apache.log4j.Logger;

import ciss.phase_viewer.acviewer.scenegraphelements.TGAtom;
import ciss.phase_viewer.acviewer.vrml.VRMLExporter;
import ciss.phase_viewer.atomcoord.AtomCoords;

public class Animater implements Runnable {
    public static final int ON_SCREEN = 0;

    public static final int EXPORT = 1;

    public static final int JPEG = 2;

    public static final int VRML = 3;

    private int batchImageMode = JPEG;

    private static Logger logger = Logger.getLogger(Animater.class.getName());

    private MainPanel parent;

    private ConfigDataManager mCD;

    private Vector frames;

    private int numFrames = 0;

    private int mode = ON_SCREEN;

    private boolean cyclic = false;

    private boolean sleep = false;

    private int frameRate = 10;

    private int skip = 1;

    private Vector images;

    private ImageReciver imageReciever;

    private String prefix = "frame";

    private boolean rescaleOnUpdate = false;

    public Animater(MainPanel parent) {
        this.parent = parent;
        init();
    }

    public Animater(J3DPanel j3d) {
        this.parent = (MainPanel) j3d;
    }

    public Animater(MainPanel parent, int mode) {
        this.parent = parent;
        this.mode = mode;
        init();
    }

    /**
     * バッチでファイルへ出力する際のファイル形式をセット. JPEGないしVRML より汎用性の高い仕組みにすべきかな
     * 
     * @param batchImageMode
     *            ファイルへバッチ出力する場合のmode
     */
    public void setBatchImageMode(int batchImageMode) {
        this.batchImageMode = batchImageMode;
    }

    /**
     * バッチでファイルへ出力する際のファイル形式をゲット. JPEGないしVRML より汎用性の高い仕組みにすべきかな
     * 
     * @return ファイルへバッチ出力する場合のmode
     */
    public int getBatchImageMode() {
        return batchImageMode;
    }

    private void init() {
        this.frames = parent.getFramesAC();
        this.numFrames = frames.size();
        this.mCD = parent.getCD();
    }

    public void setSleep(boolean sleep) {
        this.sleep = sleep;
    }

    public void setFrameRate(int frameRate) {
        this.frameRate = frameRate;
    }

    public void setSkip(int skip) {
        this.skip = skip;
    }

    public void doAnim() {
        new Thread(new Anim()).start();
    }

    class Anim implements Runnable {
        public void run() {
            parent.doRedraw(false);
            for (int i = 0; i < frames.size(); i++) {
                // parent.prepareRedraw();
                AtomCoords coords = (AtomCoords) frames.get(i);
                mCD.setCoords(coords, rescaleOnUpdate);
                mCD.setFrameNum(i);
                try {
                    Thread.sleep(frameRate);
                } catch (InterruptedException ie) {
                    logger.warn("failed pause");
                }
                // parent.postRedraw();
            }
            parent.doRedraw(true);
        }
    }

    /**
     * 現在のフレームを取得
     * 
     * @return 現在のフレームの数字
     */
    public int getCurrentFrame() {
        return currframe;
    }

    public void setFrame(int currentFrame) {
        if (currentFrame >= frames.size() || currentFrame < 0) {
            return;
        }
        this.currframe = currentFrame;
        parent.doRedraw(false);
        ((TGAtom) parent.getScene().getTGAtom()).setUpdateMode(TGAtom.ANIM);
        AtomCoords coords = (AtomCoords) frames.get(currentFrame);
        mCD.setCoords(coords, rescaleOnUpdate);
        mCD.setFrameNum(currentFrame);
        ((TGAtom) parent.getScene().getTGAtom()).updateMeasureObjects();
        parent.doRedraw(true);
        if (sleep) {
            try {
                Thread.sleep((int) (frameRate));
            } catch (InterruptedException ie) {
                logger.warn("failed pause");
            }
        }
        ((TGAtom) parent.getScene().getTGAtom()).setUpdateMode(TGAtom.GENERIC);
    }

    private int currframe = 0;

    public void nextFrame() {
        currframe++;
        if (currframe >= frames.size())
            currframe = 0;
        setFrame(currframe);
    }

    public void previousFrame() {
        currframe--;
        if (currframe < 0)
            currframe = frames.size() - 1;
        setFrame(currframe);
    }

    public void firstFrame() {
        currframe = 0;
        setFrame(currframe);
    }

    public void lastFrame() {
        currframe = frames.size() - 1;
        setFrame(currframe);
    }

    public void nextFrame(int skip_) {
        if (skip_ >= frames.size())
            nextFrame();
        currframe += skip_;
        if (currframe >= frames.size()) {
            int amari = currframe - frames.size();
            currframe = amari;
        }
        setFrame(currframe);
    }

    public void previousFrame(int skip_) {
        logger.debug("at previousFrame(int skip_)");
        if (skip_ >= frames.size())
            previousFrame();
        currframe -= skip_;
        if (currframe < 0) {
            currframe = frames.size() + currframe - 1;
        }
        setFrame(currframe);
    }

    private void updateFrame() {
    }

    public void setCyclic(boolean cyclic) {
        this.cyclic = cyclic;
    }

    public void setRescaleOnUpdate(boolean rescaleOnUpdate) {
        this.rescaleOnUpdate = rescaleOnUpdate;
    }

    public void run() {
        // try {
        // parent.setSelected(true);
        // } catch(PropertyVetoException pve) {}
        this.batchAnimation();
    }

    public void setImageReciever(ImageReciver imageReciever) {
        this.imageReciever = imageReciever;
    }

    private String baseDir;

    public String getBaseDir() {
        return this.baseDir;
    }

    public void setBaseDir(String baseDir) {
        this.baseDir = baseDir;
    }

    public void batchAnimation() {
        images = new Vector();
        parent.doRedraw(false);
        for (int i = 0; i < numFrames; i = i + skip) {
            AtomCoords coords = (AtomCoords) frames.get(i);
            mCD.setCoords(coords, rescaleOnUpdate);
            mCD.setFrameNum(i);
            ((TGAtom) parent.getScene().getTGAtom()).updateMeasureObjects();
            logger.info("processing frame no. " + i);
            images.addElement(createImageFiles(baseDir, i));
        }
        AtomCoords coords = (AtomCoords) frames.get(0);
        ((TGAtom) parent.getScene().getTGAtom()).updateMeasureObjects();
        mCD.setCoords(coords, rescaleOnUpdate);
        mCD.setFrameNum(0);
        parent.doRedraw(true);

        imageReciever.setImages(images);
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    private VRMLExporter vrmlExporter;

    private String createImageFiles(String baseDir, int currentFrame) {
        String imageDir = baseDir + System.getProperty("file.separator")
                + "imagefiles";
        if ((new File(imageDir)).mkdir()) {
            logger.info("created image directory: " + baseDir
                    + System.getProperty("file.separator") + "imagefiles");
        }
        int numDigits = (String.valueOf(numFrames)).length();
        int numDigitsNow = (String.valueOf(currentFrame)).length();
        String ext = new String();
        for (int j = 0; j < (numDigits - numDigitsNow); j++) {
            ext += "0";
        }
        ext += String.valueOf(currentFrame);

        String fileName = "";
        if (batchImageMode == JPEG) {
            fileName = imageDir + System.getProperty("file.separator") + prefix
                    + ext + ".jpg";
            try {
                parent.export(fileName);
            } catch (IOException ioe) {
                logger.error("failed export to file: " + fileName);
            }
        } else if (batchImageMode == VRML) {
            fileName = imageDir + System.getProperty("file.separator") + prefix
                    + ext + ".wrl";
            if (vrmlExporter == null)
                vrmlExporter = new VRMLExporter(parent);
            vrmlExporter.doExport(fileName);
            // try{
            // parent.doExportVRML(fileName);
            // return "";
            // } catch(IOException ioe){
            // logger.error("failed export to file: "+fileName);
            // }
        }

        return new String(fileName);
    }

    public Vector getImages() {
        if (images == null) {
            batchAnimation();
        }
        return images;
    }

    private boolean isCyclic() {
        return cyclic;
    }

}
