/***************************************************************************
 *   Copyright (C) 2006 by Bram Biesbrouck                                 *
 *   b@beligum.org                                                         *
 *                                                                         *
 *   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.,                                       *
 *   51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.             *
 ***************************************************************************/

#include <cstdio>
#include <cstdlib>
#include <iostream>

#include <qfile.h>
#include <qbuttongroup.h>
#include <qcheckbox.h>
#include <qstringlist.h>
#include <qlabel.h>
#include <qmap.h>

#include <kpushbutton.h>
#include <kaction.h>
#include <klocale.h>
#include <kcombobox.h>
#include <kstatusbar.h>
#include <kmessagebox.h>
#include <kurl.h>
#include <kfiledialog.h>
#include <kaboutdata.h>
#include <klineedit.h>
#include <krestrictedline.h>
#include <kmessagebox.h>
#include <kpopupmenu.h>
#include <klanguagebutton.h>
#include <kseparator.h>

#include <libinstrudeo/isdcommentbox.h>

#include "srkaddlanguagedialog.h"
#include "srkvideocanvas.h"
#include "srkprefdialog.h"
#include "srkstopserverdialog.h"
#include "srkstartserverdialog.h"
#include "srkmainview.h"
#include "srkmainwindow.h"

//-----CONSTRUCTORS-----
SRKMainWindow::SRKMainWindow()
    : KMainWindow(0, "ScreenKast"),
      mainView(new SRKMainView(this)),
      zoomCombo(new KComboBox(this)),
      languageCombo(new KLanguageButton(this)),
      addLanguageButton(new KPushButton(this)),
      fileOpened(false),
      newFile(false)
{
    //tell the KMainWindow that this is indeed the main widget
    setCentralWidget(mainView);

    //init actions
    createActions();

    //init statusbar
    statusBar()->show();
    setupStatusBar();

    //connect the actions to the menu and toolbar(s)
    createGUI("screenkastui.rc");

    showMaximized();
  
    stateChanged("noFileOpened");
}

//-----DESTRUCTOR-----
SRKMainWindow::~SRKMainWindow()
{
    if (mainView!=NULL) {
	delete mainView;
	mainView = NULL;
    }
}

//-----PUBLIC METHODS-----
SRKError::SRKErrorCode SRKMainWindow::loadFile(QString fileName)
{
    if (QFile::exists(fileName)) {
	if (maybeSave()){
	    if (mainView->loadFile(fileName)!=SRKError::SRKError::SRK_SUCCESS) {
		KMessageBox::error(this, i18n("Error during loading of file.")+fileName, i18n("Error"));
		RETURN_ERROR(SRKError::SRK_FILE_ERROR);
	    }
	    lastFileName = fileName;

	    //note: the language-combo will be adjusted through the appropriate callback-methods
	    //      (addActiveLanguage, ...)

	    newFile = false;
	}
    }
    else {
	KMessageBox::error(this, i18n("File doesn't exist.")+fileName, i18n("Error"));
	RETURN_ERROR(SRKError::SRK_FILE_ERROR);
    }

    RETURN_SUCCESS;
}

//-----PUBLIC SLOTS----
void SRKMainWindow::setFileOpened(bool open)
{
    this->fileOpened = open;
    
    if (open) {
	stateChanged("fileOpened");
    }
    else {
	stateChanged("noFileOpened");
    }
}
void SRKMainWindow::popupMenu(QString& name, QPoint& pos)
{
    KPopupMenu *pop = (KPopupMenu*)factory()->container(name, this);
    pop->popup(pos);
}
void SRKMainWindow::addActiveLanguage(QString langCode)
{
    //don't add if the language is already present
    if (!languageCombo->contains(langCode)) {
	languageCombo->insertItem(KGlobal::locale()->twoAlphaToLanguageName(langCode) , langCode);
	languageCombo->setCurrentItem(langCode);
    }
    //if it is present, just make it active
    else {
	languageCombo->setCurrentItem(langCode);
    }
}
void SRKMainWindow::clearActiveLanguages()
{
    languageCombo->clear();
}
void SRKMainWindow::syncActiveLanguage()
{
    statusLanguageChanged(languageCombo->current());
}

//-----PROTECTED OVERLOADED SLOTS-----
bool SRKMainWindow::queryClose()
{
    if (maybeSave()) {
	if (fileOpened) {
	    closeFile();
	}
    
	return true;
    }
    else {
	//cancel the closing
	return false;
    }
}

//-----PROTECTED FILE MENU SLOTS-----
void SRKMainWindow::fileNew()
{
    if (maybeSave()){
	if (fileOpened)
	    closeFile();
	
	mainView->newRecording();
	
	newFile = true;
    }
}
void SRKMainWindow::fileOpen()
{
    if (maybeSave()) {
	if (fileOpened)
	    closeFile();
	
	KURL url = KFileDialog::getOpenURL("::"+kapp->aboutData()->programName(), 
					   FILE_DIALOG_FILTER_STRING, this, i18n("Open Location"));
	if (!url.isEmpty()){
	    loadFile(url.path());
	}
    }
}
void SRKMainWindow::fileSave()
{
    if (newFile) {
	fileSaveAs();
    }
    else{
	mainView->saveRecording(lastFileName);
	newFile = false;
	statusBar()->message(i18n("Document saved."), 3000);
    }
}
void SRKMainWindow::fileSaveAs()
{
    QString fileName = KFileDialog::getSaveFileName("::"+kapp->aboutData()->programName(),
						    FILE_DIALOG_FILTER_STRING, this);
    if (!fileName.isEmpty()){
	if (QFile::exists(fileName)){
	    int retVal = KMessageBox::warningYesNo(this, i18n("File exists, overwrite?"), i18n("Warning"));
	    if (retVal==KMessageBox::No)
		return;
	}
	mainView->saveRecording(fileName);
	lastFileName = fileName;
	newFile = false;
	statusBar()->message(i18n("Document saved."), 3000);
    }
}
void SRKMainWindow::fileMetaInfo()
{
    if (fileOpened) {
	mainView->editMetaInfo();
    }
}
void SRKMainWindow::fileTransmitRecording()
{
    //If we transmit the recording, ask to save it first if dirty.
    if (fileOpened && maybeSave()) {
	mainView->transmitRecording(lastFileName);
    }
}
void SRKMainWindow::fileExport()
{
    if (fileOpened){
	if (newFile) {
	    KMessageBox::error(this, i18n("Please save your recording before exporting."), i18n("Error"));
	    return;
	}

	QString fileName = KFileDialog::getSaveFileName("::"+kapp->aboutData()->programName(),
							EXPORT_DIALOG_FILTER_STRING, this);
	if (!fileName.isEmpty()){
	    if (QFile::exists(fileName)){
		int retVal = KMessageBox::warningYesNo(this, i18n("File exists, overwrite?"), i18n("Warning"));
		if (retVal==KMessageBox::No)
		    return;
	    }
	    
	    if (mainView->exportRecording(lastFileName, fileName) != SRKError::SRK_SUCCESS) {
		KMessageBox::error(this, i18n("Error while exporting the recording."), i18n("Error"));
	    }
	}
    }
}
void SRKMainWindow::fileClose()
{
    if (maybeSave()) {
	if (fileOpened) {
	    closeFile();
	}
    }
}

//-----PROTECTED EDIT MENU SLOTS-----
void SRKMainWindow::editAddTextBalloonComment()
{
    if (fileOpened) {
	mainView->addComment(ISDCommentbox::ISD_COMMENT_TEXTBALLOON_TYPE);
    }
}
void SRKMainWindow::editAddRoundedBoxComment()
{
    if (fileOpened) {
	mainView->addComment(ISDCommentbox::ISD_COMMENT_ROUNDED_BOX_TYPE);
    }
}
void SRKMainWindow::editAddTextBalloon2DComment()
{
    if (fileOpened) {
	mainView->addComment(ISDCommentbox::ISD_COMMENT_TEXTBALLOON_2D_TYPE);
    }
}
void SRKMainWindow::editDeleteComment()
{
    if (fileOpened) {
	mainView->deleteActiveComment();
    }
}
void SRKMainWindow::editCommentProperties()
{
    if (fileOpened) {
	mainView->editActiveCommentProperties();
    }
}
void SRKMainWindow::editEndCommentHere()
{
    if (fileOpened) {
	mainView->endActiveCommentHere();
    }
}

//-----PROTECTED VNC MENU SLOTS-----
void SRKMainWindow::vncStartServer()
{
    SRKStartServerDialog dlg(this);
    
    //if OK was pressed
    if (dlg.exec()){
	int xRes = dlg.vncServerXResInput->text().toInt();
	int yRes = dlg.vncServerYResInput->text().toInt();
	int display = dlg.vncServerDispInput->text().toInt();
	bool killOnExit = dlg.killOnExit->isChecked();
	//check the input
	//remark: the display must be >0
	if (xRes+yRes+display==0){
	    KMessageBox::error(this, i18n("Invalid input.\n"), i18n("Error"));
	}
	else{
	    if (mainView->startVncServer(xRes, yRes, display, killOnExit) != SRKError::SRK_SUCCESS) {
		KMessageBox::error(this, i18n("Error while starting the vnc server.\n \
				      Check the path in your preferences."), i18n("Error"));
	    }
	}
    }
}
void SRKMainWindow::vncStopServer()
{
    SRKStopServerDialog dlg(this);
    
    //if OK was pressed
    if (dlg.exec()){
	int display = dlg.vncServerDispInput->text().toInt();
	//check the input
	//remark: the display must be >0
	if (display<=0){
	    KMessageBox::error(this, i18n("Invalid input.\n"), i18n("Error"));
	}
	else{
	    if (mainView->stopVncServer(display) != SRKError::SRK_SUCCESS) {
		KMessageBox::error(this, i18n("Error while stopping the vnc server."), i18n("Error"));
	    }
	}
    }
}

//-----PROTECTED OPTIONS MENU SLOTS-----
void SRKMainWindow::optionsPreferences()
{
    SRKPrefDialog dlg(this);
    dlg.exec();
}

//-----PROTECTED STATUSBAR SLOTS-----
void SRKMainWindow::statusZoomChanged(const QString& text)
{
    if (text=="auto")
	viewChangeZoomFactor(SRKVideoCanvas::AUTO_ZOOM_FACTOR);
    else{
	//remove the % and cast to a number
	QString temp = text;
	temp.truncate(temp.length()-1);
	viewChangeZoomFactor(temp.toInt());
    }
}
void SRKMainWindow::statusLanguageChanged(const QString& lang)
{
    //Note: no file must be opened to change the current language.
    mainView->changeCommentsLanguage((QString&)lang);
}
void SRKMainWindow::statusAddLanguage()
{
    SRKAddLanguageDialog dlg(this);
    
    //if OK was pressed
    if (dlg.exec()){
	//the method takes care of duplicate-elimination and active-change
	this->addActiveLanguage(dlg.languageCombo->current());
	
	//this is not triggered by the CONNECTion, do it manually
	statusLanguageChanged(dlg.languageCombo->current());
    }
}

//-----PROTECTED METHODS-----
void SRKMainWindow::viewChangeZoomFactor(int factor)
{
    if (fileOpened){
	mainView->changeZoomFactor(factor);
    }
}
void SRKMainWindow::createActions()
{
    KStdAction::openNew(this, SLOT(fileNew()), actionCollection(), "fileNew");
    KStdAction::open(this, SLOT(fileOpen()), actionCollection(), "fileOpen");
    KStdAction::save(this, SLOT(fileSave()), actionCollection(), "fileSave");
    KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection(), "fileSaveAs");
    (void)new KAction(i18n("&Export..."), 0,
		      this, SLOT(fileExport()),
		      actionCollection(), "fileExport");
    (void)new KAction(i18n("E&dit meta info..."), 0,
		      this, SLOT(fileMetaInfo()),
		      actionCollection(), "fileMetaInfo");
    (void)new KAction(i18n("&Send to captorials.com..."), 0,
		      this, SLOT(fileTransmitRecording()),
		      actionCollection(), "fileTransmitRecording");
    KStdAction::close(this, SLOT(fileClose()), actionCollection(), "fileClose");
    KStdAction::quit(kapp, SLOT(quit()), actionCollection(), "fileQuit");
    
    (void)new KAction(i18n("Add 3D &textballoon comment"), 0,
		      this, SLOT(editAddTextBalloonComment()),
		      actionCollection(), "editAddTextBalloonComment");
    (void)new KAction(i18n("Add 3D &rounded box comment"), 0,
		      this, SLOT(editAddRoundedBoxComment()),
		      actionCollection(), "editAddRoundedBoxComment");
    (void)new KAction(i18n("Add 2D t&extballoon comment"), 0,
		      this, SLOT(editAddTextBalloon2DComment()),
		      actionCollection(), "editAddTextBalloon2DComment");

    (void)new KAction(i18n("&Delete comment"), Qt::Key_Delete,
		      this, SLOT(editDeleteComment()),
		      actionCollection(), "editDeleteComment");
    (void)new KAction(i18n("&Edit properties..."), 0,
		      this, SLOT(editCommentProperties()),
		      actionCollection(), "editCommentProperties");
    (void)new KAction(i18n("E&nd comment here"), 0,
		      this, SLOT(editEndCommentHere()),
		      actionCollection(), "editEndCommentHere");
    
    (void)new KAction(i18n("&Start server..."), 0,
		      this, SLOT(vncStartServer()),
		      actionCollection(), "vncStartServer");

    (void)new KAction(i18n("S&top server..."), 0,
		      this, SLOT(vncStopServer()),
		      actionCollection(), "vncStopServer");
    
    KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection());
}
void SRKMainWindow::setupStatusBar()
{
    //create zoom combobox
    connect(zoomCombo, SIGNAL(activated(const QString&)), this, SLOT(statusZoomChanged(const QString&)));
    QString options[] = ZOOM_OPTIONS;
    
    for (int i=0;i<ZOOM_OPTIONS_SIZE;i++) {
	zoomCombo->insertItem(options[i]);
    }
    statusBar()->addWidget(new QLabel(i18n("Zoom factor:"), this));
    statusBar()->addWidget(zoomCombo);
    statusBar()->addWidget(new KSeparator(Qt::Vertical, this));
    
    //create language combobox
    connect(languageCombo, SIGNAL(activated(const QString&)), this, SLOT(statusLanguageChanged(const QString&)));

    QString defaultLangCode = KGlobal::locale()->defaultLanguage();

    languageCombo->insertItem(KGlobal::locale()->twoAlphaToLanguageName(defaultLangCode) , defaultLangCode);
    languageCombo->setCurrentItem(defaultLangCode);
    statusLanguageChanged(defaultLangCode);
    statusBar()->addWidget(new QLabel(i18n("Current comments language:"), this));
    statusBar()->addWidget(languageCombo);
    statusBar()->addWidget(new KSeparator(Qt::Vertical, this));

    //setup the newLanguage button
    addLanguageButton->setText(i18n("New language"));
    connect(addLanguageButton, SIGNAL(clicked()), this, SLOT(statusAddLanguage()));
    statusBar()->addWidget(addLanguageButton);

    statusBar()->clearFocus();
}
bool SRKMainWindow::maybeSave()
{
    if (fileOpened && mainView->recIsDirty()){
	int ret = KMessageBox::warningYesNoCancel(this,
						  i18n("The recording has been modified.\n"
						       "Do you want to save your changes?"),
						  i18n("Save changes?"));
	if (ret == KMessageBox::Yes){
	    fileSave();
	    return true;
	}
	else if (ret == KMessageBox::Cancel)
	    return false;
    }
    
    return true;
}
void SRKMainWindow::closeFile()
{
    if (fileOpened) {
	mainView->closeRecording();
	newFile = false;
    }
}
