/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/06/27, 15:33
!  AUTHOR(S): KOGA, Junichiro
!  File : VRMLExporter.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.vrml;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream;

import javax.media.j3d.BranchGroup;

import org.apache.log4j.Logger;
import org.cybergarage.x3d.j3d.VRML97Saver;

import ciss.phase_viewer.acviewer.J3DPanel;

/**
 * VRML97形式へエクスポート.
 * 
 * @author
 */
public class VRMLExporter {
    private Logger logger = Logger.getLogger(VRMLExporter.class.getName());
    private J3DPanel parent;
    private BranchGroup bg;

    /** Creates a new instance of VRMLExporter */
    public VRMLExporter(J3DPanel parent) {
        this.parent = parent;
        this.bg = parent.getRootBranch();
    }

    /**
     * cat機能を利用したい場合はBaseJ3DPanelへの参照は不要
     */
    public VRMLExporter() {
    }

    private boolean gzip = false;

    /**
     * gzipによる圧縮を有効にする場合true
     * 
     * @param gzip
     *            gzip圧縮を行う場合true
     */
    public void setGzip(boolean gzip) {
        this.gzip = gzip;
    }

    public void doExport(String fileName) {
        doExport(new File(fileName));
    }

    public void doExport(String fileName, BranchGroup bg) {
        this.bg = bg;
        doExport(new File(fileName));
    }

    private VRML97Saver saver;

    public void doExport(File toFile) {
        if (saver == null) {
            saver = new VRML97Saver(false);
            saver.setBranchGroup(bg);
        }
        try {
            logger.info("exporting to " + toFile.getAbsolutePath());
            saver.setBranchGroup(bg);
            saver.save(toFile.getAbsolutePath());
            logger.info("... done.");
            if (gzip) {
                doGzip(toFile);
            }
            saver.initialize();
            saver.clear();
            saver.initializeVRML97NodeStack();
            saver.nullify();
            saver = null;
        } catch (Exception exc) {
            logger.error("failed export...");
            exc.printStackTrace();
        }
    }

    private void doGzip(File toFile) {
        logger.info("compressing " + toFile.getAbsolutePath()
                + " in the gzip format");
        String outFilename = toFile.getAbsolutePath() + "__";
        try {
            // Create the GZIP output stream
            GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(
                    outFilename));

            // Open the input file
            String inFilename = toFile.getAbsolutePath();
            FileInputStream in = new FileInputStream(inFilename);

            // Transfer bytes from the input file to the GZIP output stream
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            in.close();

            // Complete the GZIP file
            out.finish();
            out.close();
        } catch (IOException e) {
        }
        toFile.delete();
        new File(outFilename).renameTo(toFile);
        logger.info("...done.");
    }

    public void concatVRMLFiles(File dir, File outfile, int framerate) {
        concatVRMLFiles(dir, outfile, SIMPLE_ANIM, framerate);
    }

    public static final int SIMPLE_ANIM = 0;

    /**
     * 引数のディレクトリーの下にあるVRMLファイルを昇順にくっつけてアニメーションVRMLファイルに してしまうナイスなメソッド.
     * ただしgzipされていないファイルに限る
     * 
     * @param dir
     *            VRMLファイルの置いてあるディレクトリー
     * @param outfile
     *            結果ファイル
     * @param mode
     *            どんな感じのアニメーションファイルを作成するかを指定できる
     * @param framerate
     *            アニメーションのフレームレート(frames/sec)
     */
    public void concatVRMLFiles(File dir, File outfile, int mode, int framerate) {
        double freq = 1d / ((double) framerate);
        File[] files = dir.listFiles(new FileFilter() {
            public boolean accept(File pathname) {
                if (pathname.getName().toLowerCase().endsWith(".wrl")) {
                    return true;
                }
                return false;
            }
        });

        if (files == null || files.length == 0) {
            logger.error("vrml file not found under directory "
                    + dir.getAbsolutePath());
            return;
        }

        int frameCount = files.length;

        if (mode == SIMPLE_ANIM) {
            PrintWriter writer = null;
            try {
                writer = new PrintWriter(new FileWriter(outfile));
                writer.println("#VRML V2.0 utf8");
                writer.println("DEF SW Switch{");
                writer.println("    whichChoice 0");
                writer.println("    choice[");
            } catch (IOException ioe) {
                ioe.printStackTrace();
                try {
                    writer.close();
                } catch (Exception exc) {
                }
                return;
            }

            for (int i = 0; i < files.length; i++) {
                logger.info("concatinating : " + files[i].getName());
                try {
                    BufferedReader reader = new BufferedReader(new FileReader(
                            files[i]));
                    reader.readLine(); // 一行目は飛ばす
                    String line = "";
                    while ((line = reader.readLine()) != null) {
                        writer.println(line);
                    }
                    reader.close();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                    logger.error("failed concat");
                }
            }

            String post = "    ]\n";
            post += "}\n";
            post += "DEF SENSOR TouchSensor {\n";
            post += "}\n";

            post += "DEF SC Script {\n";
            post += "    eventOut SFBool enabled\n";
            post += "    eventIn SFBool clicked\n";
            post += "    url \"javascript:function clicked(){\n";
            post += "        enabled = !enabled\n";
            post += "    }\"\n";
            post += "}\n";

            post += "DEF TS TimeSensor{\n";
            post += "   enabled FALSE\n";
            post += "   loop TRUE\n";
            post += "   cycleInterval " + String.valueOf(freq) + "\n";
            post += "}\n";

            post += "DEF SCTime Script {\n";
            post += "    eventOut SFInt32 choice\n";
            post += "    eventIn SFTime cycleTime\n";
            post += "    field SFInt32 current 0\n";
            post += "    url \"javascript:function cycleTime(){\n";
            post += "        current++;\n";
            post += "        choice = current;\n";
            post += "        if ( current == " + String.valueOf(frameCount - 1)
                    + " ) current = -1;\n";
            post += "    }\"\n";
            post += "}\n";

            post += "ROUTE SENSOR.touchTime TO SC.clicked\n";
            post += "ROUTE SC.enabled TO TS.enabled\n";
            post += "ROUTE TS.cycleTime TO SCTime.cycleTime\n";
            post += "ROUTE SCTime.choice TO SW.set_whichChoice\n";

            writer.print(post);

            writer.flush();
            writer.close();

            if (gzip) {
                doGzip(outfile);
            }
        }
    }

}
