/***************************************************************************
 *   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 <glibmm/ustring.h>
#include <list>

#include <qgroupbox.h>
#include <qcursor.h>

#include <klineedit.h>
#include <ktextedit.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kconfig.h>
#include <kglobal.h>
#include <kcursor.h>

#include <libinstrudeo/isdwscategory.h>
#include <libinstrudeo/isdwscommunicator.h>
#include <libinstrudeo/isdrecordingmetainfo.h>

#include "srkplatformcombobox.h"
#include "srkcategorycombobox.h"
#include "srkmetainfodialog.h"

//-----CONSTRUCTORS-----
SRKMetaInfoDialog::SRKMetaInfoDialog(ISDRecordingMetaInfo* metaInfo, QWidget* parent, const char* name, bool modal, WFlags fl)
    : SRKMetaInfoDialogBase(parent,name, modal,fl),
      metaInfo(metaInfo)
{
    //init the commentboxes
    title->setText(QString::fromUtf8(metaInfo->getTitle().data()));
    question->setText(QString::fromUtf8(metaInfo->getQuestion().data()));
    description->setText(QString::fromUtf8(metaInfo->getDescription().data()));
    
    //fill the comboboxes with values from the webservice
    setCursor(KCursor::waitCursor());
    initPlatformCombos();
    initCategoryCombos();
    setCursor(KCursor::arrowCursor());

    //now, init the comboboxes with the recording's values
    list<ISDWSPlatform*> platList = metaInfo->getAllPlatforms();
    list<ISDWSPlatform*>::const_iterator platIter;
    list<ISDWSCategory*> catList = metaInfo->getAllCategories();
    list<ISDWSCategory*>::const_iterator catIter;

    //fill the comboboxes
    //note: the setCurrentSelection-method will fire the signals that create child-comboboxes
    //	so they exist before the selection is done.
    SRKPlatformComboBox* platCombo = platformCombo;
    for (platIter=platList.begin(); platIter!=platList.end(); platIter++) {
	ISDWSPlatform* plat  = *platIter;
	if (plat==NULL || platCombo==NULL) {
	    break;
	}
	platCombo->setCurrentSelection(plat);
	platCombo = platCombo->getChildBox();
    }
    SRKCategoryComboBox* catCombo = categoryCombo;
    for (catIter=catList.begin(); catIter!=catList.end(); catIter++) {
	ISDWSCategory* cat  = *catIter;
	if (cat==NULL || catCombo==NULL) {
	    break;
	}
	catCombo->setCurrentSelection(cat);
	catCombo = catCombo->getChildBox();
    }
}

//-----DESTRUCTOR-----
SRKMetaInfoDialog::~SRKMetaInfoDialog()
{
}

//-----PROTECTED SLOTS-----
void SRKMetaInfoDialog::platformChanged(const QString&, SRKPlatformComboBox* c)
{
    KConfig* config = KGlobal::config();
    config->setGroup("Network");
    string serviceEndpoint = config->readEntry("WebserviceUrl", DEFAULT_SERVICE_ENDPOINT).ascii();
    
    ISDWSCommunicator wsComm(serviceEndpoint);

    //if a combobox changed, delete all it's cildren and start over
    c->deleteChildBoxes();

    //if the empty choice was selected, just delete the children and quit
    if (c->getCurrentSelection()==NULL){
	//update the layouts
	recPlatformGrp->adjustSize();
	recPlatformGrp->updateGeometry();
	this->adjustSize();
	this->updateGeometry();
	
	return;
    }

    /*
     * Fetch the child platforms from the webservice.
     * Note: c can't be NULL here.
     */
    list<ISDWSPlatform*> childPlatforms;
    string errorString;

    setCursor(KCursor::waitCursor());

    if (wsComm.getSubPlatforms(c->getCurrentSelection(), childPlatforms, errorString) != ISDObject::ISD_SUCCESS) {
	setCursor(KCursor::arrowCursor());
	webserviceError(WS_PLATFORM_ERROR, errorString);
    }
    else {
	setCursor(KCursor::arrowCursor());
	/*
	 * If an empty list is returned, this means we hit a leaf node and no more comboboxes
	 * need to be created.
	 */
	if (!childPlatforms.empty()) {
	    //create new combobox, just beneath the previous one
	    SRKPlatformComboBox* box = new SRKPlatformComboBox(recPlatformGrp);
	    connect(box, SIGNAL(activated(const QString&, SRKPlatformComboBox*)),
		    this, SLOT(platformChanged(const QString&, SRKPlatformComboBox*)));
	    box->move(c->x(), c->y()+c->height()+10);
	    box->resize(c->width(), c->height());
	    box->show();
	    //update the layouts
	    recPlatformGrp->adjustSize();
	    recPlatformGrp->updateGeometry();
	    this->adjustSize();
	    this->updateGeometry();
	    
	    //link it to its parent box
	    c->setChildBox(box);
	    
	    //add an empty choice, so we force to change it
	    box->addChoice(NULL);
	    
	    //fill the boxes
	    list<ISDWSPlatform*>::const_iterator iter;
	    for (iter=childPlatforms.begin(); iter!=childPlatforms.end(); iter++) {
		box->addChoice(*iter);
	    }
	}
    }
}
void SRKMetaInfoDialog::categoryChanged(const QString&, SRKCategoryComboBox* c)
{
    KConfig* config = KGlobal::config();
    config->setGroup("Network");
    string serviceEndpoint = config->readEntry("WebserviceUrl", DEFAULT_SERVICE_ENDPOINT).ascii();
    ISDWSCommunicator wsComm(serviceEndpoint);

    //if a combobox changed, delete all it's cildren and start over
    c->deleteChildBoxes();

    //if the empty choice was selected, just delete the children and quit
    if (c->getCurrentSelection()==NULL){
	//update the layouts
	recCategoryGrp->adjustSize();
	recCategoryGrp->updateGeometry();
	this->adjustSize();
	this->updateGeometry();
	
	return;
    }

    /*
     * Fetch the child categories from the webservice.
     * Note: c can't be NULL here.
     */
    setCursor(KCursor::waitCursor());

    list<ISDWSCategory*> childCategories;
    string errorString;
    if (wsComm.getSubCategories(c->getCurrentSelection(), childCategories, errorString) != ISDObject::ISD_SUCCESS) {
	setCursor(KCursor::arrowCursor());
	webserviceError(WS_CATEGORY_ERROR, errorString);
    }
    else {
	setCursor(KCursor::arrowCursor());
	
	/*
	 * If an empty list is returned, this means we hit a leaf node and no more comboboxes
	 * need to be created.
	 */
	if (!childCategories.empty()) {
	    //create new combobox, just beneath the previous one
	    SRKCategoryComboBox* box = new SRKCategoryComboBox(recCategoryGrp);
	    connect(box, SIGNAL(activated(const QString&, SRKCategoryComboBox*)),
		    this, SLOT(categoryChanged(const QString&, SRKCategoryComboBox*)));
	    box->move(c->x(), c->y()+c->height()+10);
	    box->resize(c->width(), c->height());
	    box->show();
	    //update the layouts
	    recCategoryGrp->adjustSize();
	    recCategoryGrp->updateGeometry();
	    this->adjustSize();
	    this->updateGeometry();
	    
	    //link it to its parent box
	    c->setChildBox(box);
	    
	    //add an empty choice, so we force to change it
	    box->addChoice(NULL);
	    
	    //fill the boxes
	    list<ISDWSCategory*>::const_iterator iter;
	    for (iter=childCategories.begin(); iter!=childCategories.end(); iter++) {
		box->addChoice(*iter);
	    }
	}
    }
}
void SRKMetaInfoDialog::reject()
{
    QDialog::reject();
}
void SRKMetaInfoDialog::accept()
{
    //save the recording info
    Glib::ustring tempStr = Glib::ustring(title->text().utf8().data());
    metaInfo->setTitle(tempStr);
    tempStr = Glib::ustring(question->text().utf8().data());
    metaInfo->setQuestion(tempStr);
    tempStr = Glib::ustring(description->text().utf8().data());
    metaInfo->setDescription(tempStr);

    /*
     * Save the platforms and categories.
     * Do nothing if an error occurred while contacting the webservice (groupbox disabled)
     * or the first category-choice is empty (NULL)
     */
    SRKPlatformComboBox* platBox = platformCombo;
    metaInfo->deleteAllPlatforms();
    if (recPlatformGrp->isEnabled() && platBox->getCurrentSelection()!=NULL) {
	metaInfo->addPlatform(platBox->getCurrentSelection());
	while (platBox->getChildBox()){
	    if (platBox->getChildBox()->getCurrentSelection())
		metaInfo->addPlatform(platBox->getChildBox()->getCurrentSelection());
	    platBox = platBox->getChildBox();
	}
    }

    SRKCategoryComboBox* catBox = categoryCombo;
    metaInfo->deleteAllCategories();
    if (recCategoryGrp->isEnabled() && catBox->getCurrentSelection()!=NULL) {
	metaInfo->addCategory(catBox->getCurrentSelection());
	while (catBox->getChildBox()){
	    if (catBox->getChildBox()->getCurrentSelection())
		metaInfo->addCategory(catBox->getChildBox()->getCurrentSelection());
	    catBox = catBox->getChildBox();
	}
    }

    QDialog::accept();
}

//-----PROTECTED METHODS-----
void SRKMetaInfoDialog::initPlatformCombos()
{
    KConfig* config = KGlobal::config();
    config->setGroup("Network");
    string serviceEndpoint = config->readEntry("WebserviceUrl", DEFAULT_SERVICE_ENDPOINT).ascii();
    ISDWSCommunicator wsComm(serviceEndpoint);

    //empty the comboboxes first
    platformCombo->clear();

    /*
     * Fetch the top level platforms from the webservice.
     * We create a virtual parent of a top-level platform by assigning it 
     * the ISDWSPlatform::TOP_LEVEL_PARENT_ID id.
     */
    Glib::ustring tempStr("");
    ISDWSPlatform topLevelParent(ISDWSPlatform::TOP_LEVEL_PARENT_ID, tempStr);
    list<ISDWSPlatform*> topLevelPlatforms;

    string errorString;
    if (wsComm.getSubPlatforms(&topLevelParent, topLevelPlatforms, errorString) != ISDObject::ISD_SUCCESS) {
	webserviceError(WS_PLATFORM_ERROR, errorString);
    }
    else {
	//add an empty choice, so we force to change it
	platformCombo->addChoice(NULL);
	
	list<ISDWSPlatform*>::const_iterator iter;
	for (iter=topLevelPlatforms.begin(); iter!=topLevelPlatforms.end(); iter++) {
	    platformCombo->addChoice(*iter);
	}
    }
}
void SRKMetaInfoDialog::initCategoryCombos()
{
    KConfig* config = KGlobal::config();
    config->setGroup("Network");
    string serviceEndpoint = config->readEntry("WebserviceUrl", DEFAULT_SERVICE_ENDPOINT).ascii();
    ISDWSCommunicator wsComm(serviceEndpoint);

    //empty the comboboxes first
    categoryCombo->clear();

    /*
     * Fetch the top level categories from the webservice.
     * We create a virtual parent of a top-level category by assigning it 
     * the ISDWSCategory::TOP_LEVEL_PARENT_ID id.
     */
    Glib::ustring tempStr("");
    ISDWSCategory topLevelParent(ISDWSCategory::TOP_LEVEL_PARENT_ID, tempStr);
    list<ISDWSCategory*> topLevelCategories;

    string errorString;
    if (wsComm.getSubCategories(&topLevelParent, topLevelCategories, errorString) != ISDObject::ISD_SUCCESS) {
	webserviceError(WS_CATEGORY_ERROR, errorString);
    }
    else {
	//add an empty choice, so we force to change it
	categoryCombo->addChoice(NULL);
	
	list<ISDWSCategory*>::const_iterator iter;
	for (iter=topLevelCategories.begin(); iter!=topLevelCategories.end(); iter++) {
	    categoryCombo->addChoice(*iter);
	}
    }
}
void SRKMetaInfoDialog::webserviceError(WSErrorCodes type, string errorString)
{
    QString errorMessage = i18n("Error while contacting Instrudeo webservice. (no Internet connection?).");
    if (errorString!="") {
	errorMessage += i18n("\nWebservice returned: ") + errorString;
    }
    switch (type) {
    case WS_PLATFORM_ERROR:
	errorMessage += i18n("\nPlatform-selecting will be disabled");
	recPlatformGrp->setEnabled(false);
	break;
    case WS_CATEGORY_ERROR:
	errorMessage += i18n("\nCategory-selecting will be disabled");
	recCategoryGrp->setEnabled(false);
	break;
    }

    KMessageBox::error(this, errorMessage, i18n("Error"));
}

#include "srkmetainfodialog.moc"
