/*
 * File:     ElanMediaPlayerController.java
 * Project:  MPI Linguistic Application
 * Date:     03 April 2006
 *
 * Copyright (C) 2001-2006  Max Planck Institute for Psycholinguistics
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package mpi.eudico.client.annotator;

import mpi.eudico.client.annotator.gui.*;

import mpi.eudico.client.annotator.viewer.*;

import mpi.eudico.client.mediacontrol.ControllerEvent;
import mpi.eudico.client.mediacontrol.StopEvent;
import mpi.eudico.client.mediacontrol.TimeEvent;

import java.awt.Dimension;

import javax.swing.JComponent;
import javax.swing.JPanel;


/**
 * MediaPlayerControlPanel A collection of buttons, sliders, etc to controls
 * the media, e.g. playing, setting current time.
 */
public class ElanMediaPlayerController extends AbstractViewer {
    /** Holds value of property DOCUMENT ME! */
    final private static Dimension BUTTON_SIZE = new Dimension(30, 20);
    private long userTimeBetweenLoops = 500; //used when playing selection in loop mode, default 0.5 seconds
    private ViewerManager2 vm;
    private ElanSlider rateslider;
    private ElanSlider volumeslider;
    private SelectionPanel selectionpanel;

    //private MediaPlayerControlSlider mpcs;
    private DurationPanel durationPanel;

    //private TimePanel timePanel;
    private PlayButtonsPanel playButtonsPanel;
    private AnnotationNavigationPanel annotationPanel;
    private SelectionButtonsPanel selectionButtonsPanel;
    private ModePanel modePanel;
    private long stopTime = 0;
    private boolean playingSelection = false;
    private boolean bLoopMode = false;
    private boolean bSelectionMode = false;
    private boolean bBeginBoundaryActive = false;

    /**
     * Constructor
     *
     * @param theVM DOCUMENT ME!
     */
    public ElanMediaPlayerController(ViewerManager2 theVM) {
        vm = theVM;

        rateslider = new ElanSlider("ELANSLIDERRATE", 0, 200, 100, vm);
        volumeslider = new ElanSlider("ELANSLIDERVOLUME", 0, 100, 100, vm);
        selectionpanel = new SelectionPanel(vm);

        //	mpcs = new MediaPlayerControlSlider();
        //	timePanel = new TimePanel();
        durationPanel = new DurationPanel(vm.getMasterMediaPlayer()
                                            .getMediaDuration());
        playButtonsPanel = new PlayButtonsPanel(getButtonSize(), vm);
        annotationPanel = new AnnotationNavigationPanel(getButtonSize(), vm);
        selectionButtonsPanel = new SelectionButtonsPanel(getButtonSize(), vm);
        modePanel = new ModePanel(vm, this);
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public Dimension getButtonSize() {
        return BUTTON_SIZE;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public long getUserTimeBetweenLoops() {
        return userTimeBetweenLoops;
    }

    /**
     * DOCUMENT ME!
     *
     * @param loopTime DOCUMENT ME!
     */
    public void setUserTimeBetweenLoops(long loopTime) {
        userTimeBetweenLoops = loopTime;
    }

    // getters for subpanels
    public MediaPlayerControlSlider getSliderPanel() {
        return vm.getMediaPlayerControlSlider();
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public AnnotationDensityViewer getAnnotationDensityViewer() {
        return vm.getAnnotationDensityViewer();
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public JComponent getRatePanel() {
        return rateslider; //.getSlider();
    }

    /**
     * Sets the play rate and updates the ui.
     *
     * @param rate the play rate
     */
    public void setRate(float rate) {
        super.setRate(rate);

        // multiply by 100; the slider uses ints
        rateslider.setValue((int) (100 * rate));
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public JComponent getVolumePanel() {
        return volumeslider;
    }

    /**
     * Sets the volume and updates the ui.
     *
     * @param volume the volume
     */
    public void setVolume(float volume) {
        super.setVolume(volume);

        // multiply by 100; the slider uses ints
        volumeslider.setValue((int) (100 * volume));
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public JPanel getModePanel() {
        return modePanel;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public SelectionButtonsPanel getSelectionButtonsPanel() {
        return selectionButtonsPanel;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public PlayButtonsPanel getPlayButtonsPanel() {
        return playButtonsPanel;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public AnnotationNavigationPanel getAnnotationNavigationPanel() {
        return annotationPanel;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public JComponent getDurationPanel() {
        return durationPanel;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public JComponent getTimePanel() {
        return vm.getTimePanel();
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public JPanel getSelectionPanel() {
        return selectionpanel;
    }

    /**
     * AR heeft dit hier neergezet, zie abstract viewer voor get en set
     * methodes van ActiveAnnotation. Update method from ActiveAnnotationUser
     */
    public void updateActiveAnnotation() {
    }

    /**
     * DOCUMENT ME!
     */
    public void updateLocale() {
    }

    /**
     * AR notification that the selection has changed method from SelectionUser
     * not implemented in AbstractViewer
     */
    public void updateSelection() {
    }

    private void adjustSelection() {
        // set active boundary to current media time
        long currTime = getMediaTime();
        long beginTime = getSelectionBeginTime();
        long endTime = getSelectionEndTime();

        if (bBeginBoundaryActive) {
            beginTime = currTime;
        } else {
            endTime = currTime;
        }

        if (beginTime > endTime) { // begin and end change place
            setSelection(endTime, beginTime);
            toggleActiveSelectionBoundary();
        } else {
            setSelection(beginTime, endTime);
        }
    }

    /**
     * AR notification that some media related event happened method from
     * ControllerListener not implemented in AbstractViewer
     *
     * @param event DOCUMENT ME!
     */
    public void controllerUpdate(ControllerEvent event) {
        // ignore time events within a certain time span after a stop event
        // that happened while playing a selection. This is needed to keep the
        // current selection after play selection is done in selection mode
        if (event instanceof TimeEvent &&
                ((System.currentTimeMillis() - stopTime) < 700)) {
            return;
        }

        // remember the stop time if the stop happened while playing a selection
        // time events will be ignored for a certain period after this stop time
        if (playingSelection && event instanceof StopEvent) {
            playingSelection = false;
            stopTime = System.currentTimeMillis();

            // change active annotation boundary if at end of selection and active edge was on the left
            // added for practical reasons, users got confused and inadvertently destroyed the selection
            //    		long halfTime = getSelectionBeginTime() + (getSelectionEndTime() - getSelectionBeginTime()) / 2;
            if (isBeginBoundaryActive() &&
                    (getMediaTime() == getSelectionEndTime())) {
                toggleActiveSelectionBoundary();
            }

            return;
        }

        //in some cases set a new selection 
        if (!playingSelection && (bSelectionMode == true)) {
            adjustSelection();
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param b DOCUMENT ME!
     */
    public void setPlaySelectionMode(boolean b) {
        playingSelection = b;
    }

    /**
     * DOCUMENT ME!
     *
     * @param b DOCUMENT ME!
     */
    public void setLoopMode(boolean b) {
        bLoopMode = b;
        modePanel.updateLoopMode(bLoopMode);
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public boolean getLoopMode() {
        return bLoopMode;
    }

    /**
     * Toggles the loop mode
     */
    public void doToggleLoopMode() {
        if (bLoopMode == true) {
            bLoopMode = false;
        } else {
            bLoopMode = true;
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public boolean getSelectionMode() {
        return bSelectionMode;
    }

    /**
     * Toggles the selection mode
     */
    public void doToggleSelectionMode() {
        // bSelectionMode = !bSelectionMode
        if (bSelectionMode == true) {
            bSelectionMode = false;
        } else {
            bSelectionMode = true;
        }

        // generate a time event to make sure the image on the button toggles
        setMediaTime(getMediaTime());
    }

    /**
     * When main time is begintime, main time is set to endtime (of selection)
     * When main time is endtime, main time is set to begintime (of selection)
     */
    public void toggleActiveSelectionBoundary() {
        // bBeginBoundaryActive = !bBeginBoundaryActive
        if (bBeginBoundaryActive == true) {
            bBeginBoundaryActive = false;
        } else {
            bBeginBoundaryActive = true;
        }

        // otherwise the button image is not always updated immediately
        if (!playerIsPlaying()) {
            setMediaTime(getMediaTime());
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public boolean isBeginBoundaryActive() {
        return bBeginBoundaryActive;
    }
}


//end of ElanMediaPlayerController
