/***************************************************************************
 *   Copyright (C) 2005 by Bjoern Erik Nilsen & Fredrik Berg Kjoelstad     *
 *   bjoern.nilsen@bjoernen.com     & fredrikbk@hotmail.com                *
 *                                                                         *
 *   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.             *
 ***************************************************************************/
#include "toolsmenu.h"

#include "src/foundation/preferencestool.h"
#include "graphics/icons/play.xpm"
#include "graphics/icons/fastforward.xpm"
#include "graphics/icons/rewind.xpm"
#include "graphics/icons/steptoend.xpm"
#include "graphics/icons/steptobeginning.xpm"
#include "graphics/icons/stop.xpm"
#include "graphics/icons/pause.xpm"
#include "graphics/icons/loop.xpm"
#include "graphics/icons/capture.xpm"
#include "graphics/icons/cameraon.xpm"
#include "graphics/icons/addframeicon.xpm"
#include "graphics/icons/removeframeicon.xpm"
#include "graphics/icons/newscene.xpm"
#include "graphics/icons/removescene.xpm"

#include <QToolTip>
#include <QAction>
#include <QMessageBox>
#include <QPixmap>
#include <QLabel>


ToolsMenu::ToolsMenu( RunAnimationHandler *runAnimationHandler, ModelHandler *modelHandler,
		CameraHandler *cameraHandler, QWidget *parent ) 
	: QWidget(parent), runAnimationHandler(runAnimationHandler), modelHandler(modelHandler), 
		cameraHandler(cameraHandler)
{
	ui.setupUi(this);
	
	loopAccel = 0;
	playAccel = 0;
	mixAccel = 0;
	diffAccel = 0;
	playbackAccel = 0;
	
	captureTimer = new QTimer(this);
	connect( captureTimer, SIGNAL( timeout() ), cameraHandler, SLOT(captureFrame()));
	
	setupUi();
	createAccelerators();
}


void ToolsMenu::setupUi()
{
	ui.addFramesButton->setIcon( QPixmap(addframeicon) );
	ui.addFramesButton->setFocusPolicy( Qt::NoFocus );
	connect(ui.addFramesButton, SIGNAL(clicked()), modelHandler, SLOT(chooseFrame()));
	
	ui.removeFramesButton->setIcon( QPixmap(removeframeicon) );
	ui.removeFramesButton->setFocusPolicy( Qt::NoFocus );
	connect(ui.removeFramesButton, SIGNAL(clicked()), modelHandler, SLOT(removeFrames()));
	
	runAnimationHandler->setRemoveFramesButton(ui.removeFramesButton);
	modelHandler->setRemoveFramesButton(ui.removeFramesButton);
	
	ui.addSceneButton->setIcon( QPixmap(newscene) );
	ui.addSceneButton->setFocusPolicy( Qt::NoFocus );
	connect(ui.addSceneButton, SIGNAL(clicked()), modelHandler, SLOT(newScene()));
	
	ui.removeSceneButton->setIcon( QPixmap(removescene) );
	ui.removeSceneButton->setFocusPolicy( Qt::NoFocus );
	connect(ui.removeSceneButton, SIGNAL(clicked()), modelHandler, SLOT(removeScene()));
	
	ui.cameraButton->setIcon( QPixmap(cameraon) );
	ui.cameraButton->setFocusPolicy( Qt::NoFocus );	
	cameraHandler->setCameraButton(ui.cameraButton);
	connect( ui.cameraButton, SIGNAL(clicked()), cameraHandler, SLOT(toggleCamera()) );
	
	ui.captureGroup->hide();
	connect( cameraHandler, SIGNAL(cameraStateChanged(bool)), this, SLOT(activateCaptureGroup(bool)) );
	
	ui.captureButton->setIcon(  QPixmap(captureicon) );
	ui.captureButton->setFocusPolicy( Qt::NoFocus );
	connect(ui.captureButton, SIGNAL(clicked()), cameraHandler, SLOT(captureFrame()));
	
	ui.viewChooseCombo->setFocusPolicy( Qt::NoFocus );
	connect(ui.viewChooseCombo, SIGNAL(activated (int)),this, SLOT(changeViewingMode(int)));
	
	ui.unitChooseCombo->setFocusPolicy( Qt::NoFocus );
	ui.unitChooseCombo->setEnabled(false);
	connect(ui.unitChooseCombo, SIGNAL(activated (int)),this, SLOT(changeUnitMode(int)));
	
	ui.mixSlider->setMinimum(0);
	ui.mixSlider->setMaximum(5);
	ui.mixSlider->setPageStep(1);
	ui.mixSlider->setValue(2);
	ui.mixSlider->setTickPosition(QSlider::TicksBelow);
	ui.mixSlider->setFocusPolicy( Qt::NoFocus );
	connect( ui.mixSlider, SIGNAL(valueChanged(int)), cameraHandler, SLOT(setMixCount(int)) );
	connect( ui.mixSlider, SIGNAL(valueChanged(int)), this, SLOT(updateSliderValue(int)) );
	
	ui.speedChooser->setMinimum(1);
	ui.speedChooser->setMaximum(30);
	ui.speedChooser->setValue(1);
	ui.speedChooser->setFocusPolicy( Qt::NoFocus );
	ui.speedChooser->setValue(PreferencesTool::get()->getPreference("fps", 10));
	connect( ui.speedChooser, SIGNAL(valueChanged(int)), runAnimationHandler, SLOT(setSpeed(int)));
	connect( ui.speedChooser, SIGNAL( valueChanged(int) ), cameraHandler, SLOT(setPlaybackSpeed(int)) );
	
	ui.playButton->setIcon( QPixmap(playicon));
	ui.playButton->setFocusPolicy( Qt::NoFocus );
	
	runAnimationHandler->setPlayButton(ui.playButton);
	connect(ui.playButton, SIGNAL(clicked()), runAnimationHandler, SLOT(runAnimation()));
	ui.playButton->setEnabled(false);
	
	ui.nextFrameButton->setIcon( QPixmap(fastforwardicon) );
	ui.nextFrameButton->setFocusPolicy( Qt::NoFocus );
	ui.nextFrameButton->setAutoRepeat(true);
	connect( ui.nextFrameButton, SIGNAL(clicked()), runAnimationHandler, SLOT(selectNextFrame()) );
	ui.nextFrameButton->setEnabled(false);
		
	ui.previousFrameButton->setIcon( QIcon(QPixmap(rewindicon)) );
	ui.previousFrameButton->setFocusPolicy( Qt::NoFocus );
	ui.previousFrameButton->setAutoRepeat(true);
	connect( ui.previousFrameButton, SIGNAL(clicked()), runAnimationHandler, SLOT(selectPreviousFrame()) );
	ui.previousFrameButton->setEnabled(false);
	
	ui.toEndButton->setIcon( QIcon(QPixmap(steptoendicon)) );
	ui.toEndButton->setFocusPolicy( Qt::NoFocus );
	connect( ui.toEndButton, SIGNAL(clicked()), runAnimationHandler, SLOT(selectNextScene()) );
	ui.toEndButton->setEnabled(false);
	
	ui.toBeginningButton->setIcon( QIcon(QPixmap(steptobeginningicon)) );
	ui.toBeginningButton->setFocusPolicy( Qt::NoFocus );
	connect( ui.toBeginningButton, SIGNAL(clicked()), runAnimationHandler, SLOT(selectPreviousScene()) );
	ui.toBeginningButton->setEnabled(false);
	
	ui.stopButton->setIcon( QIcon(QPixmap(stopicon)) );
	ui.stopButton->setFocusPolicy( Qt::NoFocus );
	connect( ui.stopButton, SIGNAL(clicked()), runAnimationHandler, SLOT(stopAnimation()));
	ui.stopButton->setEnabled(false);
	
	ui.pauseButton->setIcon( QIcon(QPixmap(pauseicon)) );
	ui.pauseButton->setFocusPolicy( Qt::NoFocus );
	ui.pauseButton->setEnabled(false);
	runAnimationHandler->setPauseButton(ui.pauseButton);
	connect(ui.pauseButton, SIGNAL(clicked()), runAnimationHandler, SLOT(pauseAnimation()));
	
	ui.loopButton->setIcon( QIcon(QPixmap(loopicon)) );
	ui.loopButton->setFocusPolicy( Qt::NoFocus );
	runAnimationHandler->setLoopButton(ui.loopButton);
	connect( ui.loopButton, SIGNAL(clicked()), runAnimationHandler, SLOT(toggleLooping()) );
}


void ToolsMenu::createAccelerators()
{
	loopAccel = new QShortcut(QKeySequence(Qt::ControlModifier + Qt::Key_L), this);
	connect(loopAccel, SIGNAL(activated()), ui.loopButton, SLOT(toggle()));
	
	playAccel = new QShortcut(QKeySequence(Qt::Key_K), this); 
	connect(playAccel, SIGNAL(activated()), runAnimationHandler, SLOT(toggleRunning()));
	
	mixAccel = new QShortcut(QKeySequence(Qt::Key_1), this);
	connect(mixAccel, SIGNAL(activated()), this, SLOT(setMixingMode()));
	
	diffAccel = new QShortcut(QKeySequence(Qt::Key_2), this);
	connect(diffAccel, SIGNAL(activated()), this, SLOT(setDiffingMode()));
	
	playbackAccel = new QShortcut(QKeySequence(Qt::Key_3), this);
	connect(playbackAccel, SIGNAL(activated()), this, SLOT(setPlaybackMode()));
}


void ToolsMenu::activateCaptureGroup(bool activate)
{
	if (activate) {		
		ui.captureGroup->show();
	}
	else {
		ui.captureGroup->hide();
	}
}


void ToolsMenu::retranslateStrings()
{
	ui.speedChooserCaption->setText( tr("FPS chooser") );
	ui.mixSliderCaption->setText( tr("Number of images:") );
	
	ui.viewChooseCombo->clear();
	ui.viewChooseCombo->addItem( tr("Mix") );
	ui.viewChooseCombo->addItem( tr("Diff") );
	ui.viewChooseCombo->addItem( tr("Playback") );
	ui.viewChooseCombo->addItem( tr("Auto") );
	
	ui.unitChooseCombo->clear();
	ui.unitChooseCombo->addItem("");
	ui.unitChooseCombo->addItem( tr("Pr sec") );
	ui.unitChooseCombo->addItem( tr("Pr min") );
	ui.unitChooseCombo->addItem( tr("Pr hr") );
	ui.unitChooseCombo->setCurrentIndex(0);
	
	//Tooltip and whatsthis text
	QString infoText = 
			tr("<h4>Add Frames (CTRL+F)</h4> "
			"<p>Click on this button to <em>add</em> frames to the "
			"animation.</p>");
	ui.addFramesButton->setToolTip(infoText);
	ui.addFramesButton->setWhatsThis(infoText);
	
	infoText = 
			tr("<h4>Remove Selection (Delete)</h4> "
			"<p>Click this button to <em>remove</em> the selected frames "
			"from the animation.</p>");
	ui.removeFramesButton->setToolTip(infoText);
	ui.removeFramesButton->setWhatsThis(infoText);
	
	infoText = 
			tr("<h4>New Scene (CTRL+E)</h4> "
			"<p>Click this button to <em>create</em> a new <em>scene</em> "
			"to the animation.</p>");
	ui.addSceneButton->setToolTip(infoText);
	ui.addSceneButton->setWhatsThis(infoText);
	
	infoText = 
			tr("<h4>Remove Scene (SHIFT+Delete)</h4> "
			"<p>Click this button to <em>remove</em> the selected scene "
			"from the animation.</p>");
	ui.removeSceneButton->setToolTip(infoText);
	ui.removeSceneButton->setWhatsThis(infoText);
	
	infoText = 
			tr("<h4>Toggle camera on/off (C)</h4> "
			"<p>Click this button to toggle the camera on and off</p> ");
	ui.cameraButton->setToolTip(infoText);
	ui.cameraButton->setWhatsThis(infoText );
	
	infoText =
			tr("<h4>Capture Frame (Space)</h4> "
			"<p>Click on this button to <em>capture</em> a frame from the "
			"camera an put it in the animation</p> <p> This can also be "
			"done by pressing the <b>Space key</b></p>");
	ui.captureButton->setWhatsThis(infoText);
	ui.captureButton->setToolTip(infoText);
	
	infoText = 
			tr("<h4>Number of images</h4> "
			"<p>By changing the value in this slidebar you can specify how many images "
			"backwards in the animation which should be mixed on top of the camera or "
			"if you are in playback mode: how many images to play. </p> "
			"<p>By mixing the previous image(s) onto the camera you can more easily see "
			"how the next shot will be in relation to the other, therby making a smoother "
			"stop motion animation!</p>");
	ui.mixSliderCaption->setWhatsThis(infoText );
	ui.mixSlider->setWhatsThis(infoText);
	
	infoText = 
			tr("<h4>FPS chooser</h4> "
			"<p>By changing the value in this "
			"chooser you set which speed the "
			"animation in the <b>FrameView</b> "
			"should run at.</p> "
			"<p>To start an animation press the "
			"<b>Run Animation</b> button.</p>");
    ui.speedChooserCaption->setWhatsThis(infoText );
    ui.speedChooser->setWhatsThis(infoText);
	
	infoText = tr("<h4>Play animation (K, P)</h4>");
	ui.playButton->setToolTip(infoText);
	
	infoText = tr("<h4>Stop animation (K, P)</h4>");
	ui.stopButton->setToolTip(infoText);
	
	infoText = tr("<h4>Previous frame (J, Left)</h4>");
	ui.previousFrameButton->setToolTip(infoText);
	
	infoText = tr("<h4>Next frame (L, Right)</h4>");
	ui.nextFrameButton->setToolTip(infoText);
	
	infoText = tr("<h4>Previous scene (I)</h4>");
	ui.toBeginningButton->setToolTip(infoText);
	
	infoText = tr("<h4>Next scene (O)</h4>");
	ui.toEndButton->setToolTip(infoText);
	
	infoText =
			tr("<h4>Loop animation (CTRL+L)</h4> <p>With this button you can set whether "
			"you want the animation to play to the end, or to loop indefinetly.</p>");
	ui.loopButton->setToolTip(infoText);
}


void ToolsMenu::updateSliderValue(int sliderValue)
{
	if ( captureTimer->isActive() && sliderValue != 0) {
		int factor = 0;
		int index = ui.unitChooseCombo->currentIndex();
		switch (index) {
			case 1:
				factor = 1000;
				break;
			case 2:
				factor = 60000;
				break;
			case 3:
				factor = 3600000;
				break;
		}
		captureTimer->setInterval(factor / sliderValue);
	}
}


void ToolsMenu::setMixingMode()
{
	changeViewingMode(0);
}


void ToolsMenu::setDiffingMode()
{
	changeViewingMode(1);
}


void ToolsMenu::setPlaybackMode()
{
	changeViewingMode(2);
}


void ToolsMenu::changeViewingMode(int index)
{
	if ( cameraHandler->setViewMode(index) ) {
		ui.viewChooseCombo->setCurrentIndex(index);
		ui.unitChooseCombo->setCurrentIndex(0);
		switch (index) {
			case 0:
			{
				ui.mixSlider->setValue(PreferencesTool::get()->getPreference("mixcount", 2));
				ui.mixSlider->setMaximum(5);
				ui.mixSlider->setEnabled(true);
				ui.mixSliderCaption->setEnabled(true);
				ui.unitChooseCombo->setEnabled(false);
				captureTimer->stop();
				break;
			}
			case 2:
			{
				ui.mixSlider->setMaximum(50);
				ui.mixSlider->setValue(PreferencesTool::get()->getPreference("playbackcount", 5));
				ui.mixSliderCaption->setEnabled(true);
				ui.mixSlider->setEnabled(true);
				ui.unitChooseCombo->setEnabled(false);
				captureTimer->stop();
				break;
			}
			case 3:
			{
				ui.mixSlider->setMaximum(10);
				ui.mixSlider->setValue(1);
				ui.mixSliderCaption->setEnabled(true);
				ui.mixSlider->setEnabled(true);
				ui.unitChooseCombo->setEnabled(true);
				break;
			}
			default:
			{
				ui.mixSlider->setEnabled(false);
				ui.mixSliderCaption->setEnabled(false);
				ui.unitChooseCombo->setEnabled(false);
				captureTimer->stop();
				break;
			}
		}
	}
	else {
		QMessageBox::warning(this, tr("Notice"), tr(
				"Playback only currently works when running the grabber \n"
				"as a deamon. Go to the preferences menu (CTRL+P) to switch \n"
				"to running the image grabbing as a deamon."),
				QMessageBox::Ok,
				QMessageBox::NoButton, 
				QMessageBox::NoButton);
		ui.viewChooseCombo->setCurrentIndex(0);
		cameraHandler->setViewMode(0);
	}
}


void ToolsMenu::changeUnitMode(int index)
{
	int sliderValue = ui.mixSlider->value();
	if (sliderValue == 0 || index == 0) {
		if (captureTimer->isActive()) {
			captureTimer->stop();
		}
		return;
	}
	
	int factor = 0;
	switch (index) {
		case 1:
			factor = 1000;
			break;
		case 2:
			factor = 60000;
			break;
		case 3:
			factor = 3600000;
			break;
		default:
			if ( captureTimer->isActive() ) {
				captureTimer->stop();
			}
			break;
	}

	if ( captureTimer->isActive() == false) {
		// Grab the first frame manually
		cameraHandler->captureFrame();
		// then grab at the given interval
		captureTimer->start(factor / sliderValue);
	}
	else {
		captureTimer->setInterval(factor / sliderValue);
	}
}


void ToolsMenu::modelSizeChanged(int modelSize)
{
	//Not <=1 because it is signed with a meaning for -1.
	if (modelSize == 0 || modelSize == 1) {
		if (ui.previousFrameButton->isEnabled()) {
			ui.previousFrameButton->setEnabled(false);
			ui.nextFrameButton->setEnabled(false);
			ui.playButton->setEnabled(false);
			ui.pauseButton->setEnabled(false);
			ui.stopButton->setEnabled(false);
			ui.toEndButton->setEnabled(false);
			ui.toBeginningButton->setEnabled(false);
		}
	}
	else if (modelSize >= 2) {
		if ( !ui.previousFrameButton->isEnabled() && !cameraHandler->isCameraRunning() ) {
			ui.previousFrameButton->setEnabled(true);
			ui.nextFrameButton->setEnabled(true);
			ui.playButton->setEnabled(true);
			ui.pauseButton->setEnabled(true);
			ui.stopButton->setEnabled(true);
			ui.toEndButton->setEnabled(true);
			ui.toBeginningButton->setEnabled(true);
		}
	}
}


void ToolsMenu::cameraOn(bool isOn)
{
	if (isOn) {
		ui.playButton->setEnabled(false);
		ui.pauseButton->setEnabled(false);
		ui.stopButton->setEnabled(false);
		runAnimationHandler->stopAnimation();
 		changeViewingMode(0);
		ui.viewChooseCombo->setCurrentIndex(0);
	}
	else {
		ui.playButton->setEnabled(true);
		ui.pauseButton->setEnabled(true);
		ui.stopButton->setEnabled(true);
		if ( captureTimer->isActive() ) {
			captureTimer->stop();
		}
	}
}
