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

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.border.TitledBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;

import org.apache.log4j.Logger;

import ciss.phase_viewer.acviewer.Animater;
import ciss.phase_viewer.acviewer.ConfigData;
import ciss.phase_viewer.acviewer.ConfigDataManager;
import ciss.phase_viewer.acviewer.ConfigDataUpdateEvent;
import ciss.phase_viewer.acviewer.MainPanel;
import ciss.phase_viewer.acviewer.Stoppable;
import ciss.phase_viewer.common.Resources;
import ciss.phase_viewer.common.SimpleHeavyGUI;
import ciss.phase_viewer.primitiveguis.ValueSlider;
import ciss.phase_viewer.primitiveguis.ValueSliderListener;

public class FramePanel extends SimpleHeavyGUI implements Runnable, Stoppable,
        ConfigData {
    private static Logger logger = Logger.getLogger(FramePanel.class.getName());

    private MainPanel parent;

    private Vector frames;
    private int currentFrame = 0;
    private int numFrames = 0;
    private ConfigDataManager mCD;

    private ValueSlider frameSlider;
    private JTextField skip;
    private int numskip = 1;
    private int amari = 0;
    private JSlider frameRate;
    // private JCheckBox rescale;
    private Animater animater;

    private boolean update = false;

    private JToggleButton bounce;
    private JPanel specifypanel;
    private JPanel cont;

    public FramePanel(MainPanel parent) {
        super("frames", "movie maker", "close", new Dimension(400, 300));
        this.parent = parent;
        this.frames = parent.getFramesAC();
        this.parent.addDisposeOnExit(this);
        this.numFrames = frames.size();
        this.mCD = parent.getCD();
        this.animater = parent.getAssociatedAnimater();
        TitledBorder title = new TitledBorder("number of frames: "
                + String.valueOf(numFrames));
        cont.setBorder(title);
        this.init();
        this.setVisible(true);
    }

    private void init() {
        mCD.register(this);
        frameSlider = new ValueSlider(0, frames.size() - 1, 0);
        frameSlider.addValueSliderListener(new ValueSliderListener() {
            public void valueSliderValueChanged() {
                int cf = (int) frameSlider.getValue();
                currentFrame = cf;
                animater.setFrame(currentFrame);
            }
        });
        frameSlider.setTitleForBorder("specify frame no.");
        frameSlider.setOrientation(ValueSlider.VERTICAL);
        currentFrame = animater.getCurrentFrame();
        frameSlider.setValueInt(currentFrame);
        frameSliderPanel.add(frameSlider);

        addInternalFrameListener(new InternalFrameAdapter() {
            public void internalFrameClosed(InternalFrameEvent ev) {
                close();
            }
        });
        //
        // addWindowListener(new WindowListener() {
        // public void windowActivated(WindowEvent e) {
        // }
        // public void windowClosed(WindowEvent e) {
        // close();
        // }
        // public void windowClosing(WindowEvent e) {
        // }
        // public void windowDeactivated(WindowEvent e) {
        // }
        // public void windowDeiconified(WindowEvent e) {
        // }
        // public void windowIconified(WindowEvent e) {
        // }
        // public void windowOpened(WindowEvent e) {
        // }
        // });
    }

    private void close() {
        mCD.removeConfigData(this);
    }

    private JPanel frameSliderPanel;
    private JButton next;
    private JButton previous;
    private JButton rewind;
    private JButton lastframe;
    private JButton animate;

    private void setEnableBtns(boolean bool) {
        next.setEnabled(bool);
        previous.setEnabled(bool);
        rewind.setEnabled(bool);
        lastframe.setEnabled(bool);
        animate.setEnabled(bool);
    }

    public JPanel createMainPanel() {
        cont = new JPanel();
        cont.setLayout(new BoxLayout(cont, BoxLayout.Y_AXIS));

        String icondir = "/org/javalobby/icons/20x20/";
        JPanel buttons = new JPanel();
        buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));

        next = new JButton(Resources.getIcon(Resources.VCRForward20));
        next.setToolTipText("next frame");
        previous = new JButton(Resources.getIcon(Resources.VCRBack20));
        previous.setToolTipText("previous frame");
        rewind = new JButton(Resources.getIcon(Resources.VCRBegin20));
        rewind.setToolTipText("rewind to first frame");
        lastframe = new JButton(Resources.getIcon(Resources.VCREnd20));
        lastframe.setToolTipText("skip to last frame");

        skip = new JTextField(5);
        skip.setText("1");
        skip.setToolTipText("specify the number of frames to skip on each redraw");
        //
        // specifypanel = new JPanel();
        // specifypanel.setLayout(new BoxLayout(specifypanel,BoxLayout.X_AXIS));
        // specifypanel.setPreferredSize(new Dimension(30,5));
        //
        // frameno = new JTextField();
        // frameno.setText(String.valueOf(currentFrame));
        // frameno.setToolTipText("specify frame number");
        //
        // JButton ok = new JButton("OK");
        // ok.setToolTipText("apply specified frame number");
        // specifypanel.add(skip);
        // // specifypanel.add(frameno);
        // specifypanel.add(ok);
        //
        animate = new JButton(Resources.getIcon(Resources.VCRPlay20));
        animate.setToolTipText("start");
        JButton stop = new JButton(Resources.getIcon(Resources.VCRStop20));
        stop.setToolTipText("stop");
        bounce = new JToggleButton(Resources.getIcon(Resources.WIDEN20));
        bounce.setToolTipText("enable 'bounce'");

        // rescale = new JCheckBox("rescale each frame");

        buttons.add(animate);
        buttons.add(bounce);
        buttons.add(stop);
        buttons.add(previous);
        buttons.add(next);
        buttons.add(rewind);
        buttons.add(lastframe);
        // buttons.add(specifypanel);

        cont.add(buttons);

        JPanel skippanel = new JPanel();
        skippanel.setBorder(new TitledBorder("skip"));
        skippanel.add(skip);
        frameSliderPanel = new JPanel();
        frameSliderPanel.setLayout(new BoxLayout(frameSliderPanel,
                BoxLayout.X_AXIS));
        frameSliderPanel.add(skippanel);
        cont.add(frameSliderPanel);

        // cont.add(rescale);
        JLabel sliderLabel = new JLabel("frame rate", JLabel.CENTER);
        sliderLabel.setAlignmentX(Component.CENTER_ALIGNMENT);

        int min = 0;
        int max = 100;
        int init = 50;

        frameRate = new JSlider(JSlider.HORIZONTAL, min, max, init);
        frameRate.setMajorTickSpacing(10);
        frameRate.setPaintTicks(true);
        frameRate.setPaintLabels(true);

        cont.add(sliderLabel);
        cont.add(frameRate);

        animate.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                anim();
            }
        });

        stop.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                update = false;
                animater.setSleep(false);
            }
        });

        next.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                update = false;
                calCurrFrame(true);
                animater.setFrame(currentFrame);
                frameSlider.setValueInt(currentFrame);
            }
        });

        previous.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                update = false;
                calCurrFrame(false);
                animater.setFrame(currentFrame);
                frameSlider.setValueInt(currentFrame);
            }
        });

        rewind.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                currentFrame = 0;
                animater.setFrame(currentFrame);
                frameSlider.setValueInt(currentFrame);
            }
        });

        lastframe.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                currentFrame = numFrames - 1;
                animater.setFrame(currentFrame);
                frameSlider.setValueInt(currentFrame);
            }
        });
        //
        // ok.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent e) {
        // update = false;
        // String frn = frameno.getText();
        // int cf = (int) frameSlider.getValue();
        // // int frnum = 0;
        // // try {
        // // frnum = Integer.parseInt(frn);
        // // if ( frnum >= numFrames ) {
        // // frnum = 0;
        // // } else if ( frnum <= -1 ) {
        // // frnum = numFrames - 1;
        // // }
        // // } catch(NumberFormatException nfe) {
        // // return;
        // // }
        // // currentFrame = frnum;
        // currentFrame = cf;
        // animater.setFrame(currentFrame);
        // // frameno.setText(String.valueOf(currentFrame));
        // }
        // });
        //
        // rescale.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent e) {
        // animater.setRescaleOnUpdate(rescale.isSelected());
        // }
        // });

        frameRate.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                if (!frameRate.getValueIsAdjusting()) {
                    int frame = frameRate.getValue();
                    int frame_ = 250;
                    if (frame != 0) {
                        frame_ = 250 / frame;
                    }
                    animater.setFrameRate(frame_);
                }
            }
        });

        skip.addCaretListener(new CaretListener() {
            public void caretUpdate(CaretEvent ce) {
                try {
                    numskip = Integer.parseInt(skip.getText().trim());
                    if (numskip < 0 || numskip >= numFrames) {
                        numskip = 1;
                    }
                    animater.setSkip(numskip);
                    amari = numFrames % numskip;
                } catch (Exception exc) {
                    numskip = 1;
                }
            }
        });

        return cont;
    }

    private void anim() {
        new Thread(this).start();
        // animater.doAnim();
    }

    private void calCurrFrame(boolean forward) {
        if (forward) {
            currentFrame += numskip;
            if (currentFrame >= numFrames) {
                currentFrame = amari;
            }
        } else {
            currentFrame -= numskip;
            if (currentFrame < 0) {
                currentFrame = frames.size() + currentFrame;
            }
        }
    }

    public void run() {
        imDoingit = true;
        boolean reverse = false;
        update = true;
        animater.setSleep(true);
        setEnableBtns(false);
        int initframe = currentFrame;
        int frameshown = 1;
        while (update) {
            if (reverse) {
                currentFrame = currentFrame - numskip;
                // currentFrame--;
            } else {
                // currentFrame++;
                currentFrame = currentFrame + numskip;
            }
            if (currentFrame >= numFrames) {
                if (bounce.isSelected()) {
                    reverse = true;
                    // currentFrame--;
                    currentFrame = currentFrame - amari - 1;
                } else {
                    // currentFrame = 0;
                    currentFrame = amari;
                }
            }
            if (currentFrame < 0) {
                reverse = false;
                currentFrame = 0;
            }
            animater.setFrame(currentFrame);
            // frameno.setText(String.valueOf(currentFrame));
            if (frameshown % 5 == 0) {
                frameSlider.setValueInt(currentFrame);
                frameshown = 1;
            } else {
                frameshown++;
            }
        }
        frameSlider.setValueInt(currentFrame);
        setEnableBtns(true);
    }

    protected boolean action() {
        try {
            String parentDir = parent.getData().getParentDir();
            String projdir = System.getProperty("user.dir");
            if (parentDir != null && new File(parentDir).exists()) {
                projdir = parentDir;
            }
            logger.debug("projdir: " + projdir);
            MovieMakerPanel mmp = new MovieMakerPanel(new MovieMaker(animater),
                    projdir);
            Point location = this.getLocation();
            this.parent.addDisposeOnExit(mmp);

            mmp.setVisible(true);
        } catch (Exception exc) {
            exc.printStackTrace();
        }
        return true;
    }

    public void destructor() {
        update = false;
        imDoingit = false;
        // animater.setFrame(0);
    }

    public void stop() {
        update = false;
        imDoingit = false;
    }

    public void configDataUpdate(boolean rescaleOnUpdate,
            ConfigDataUpdateEvent e) {
        configDataUpdate();
    }

    public boolean needsUpdate() {
        return true;
    }

    private boolean imDoingit = false;

    public void configDataUpdate() {
        // if ( update ) return;
        // currentFrame = mCD.getFrameNum();
        // frameSlider.setValueInt(currentFrame);
    }

}
