
/**
 *
 *  This file is part of the kdewebdev package
 *  Copyright (c) 2002 Keith Isdale <keith@kdewebdev.org>
 *
 *  This library 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 library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 **/

#include <klocale.h>
#include <kfiledialog.h>

#include <QDialog>
#include <QLineEdit>
#include <QCheckBox>
#include <QMessageBox>
#include "xsldbgdebugger.h"
#include "xsldbgconfigimpl.h"
#include <libxsldbg/utils.h>
#include <kdebug.h>
#include <kglobal.h>
#include <ksharedptr.h>
#include <kconfiggroup.h>
#include <QStandardItemModel>


class XsldbgParamModel : public QStandardItemModel
{
    public:
        XsldbgParamModel(QObject * parent = 0);
        bool addItem(QString name, QString value);
        QString getName(int row);
        QString getValue(int row);
};



XsldbgParamModel::XsldbgParamModel(QObject * parent)
    :QStandardItemModel(0,2,parent)
{
}

bool XsldbgParamModel::addItem(QString name, QString value)
{
    bool result = true;
    int row = rowCount();
    setItem(row,0, new QStandardItem(name));
    setItem(row,1, new QStandardItem(value));

    return result;
}

QString XsldbgParamModel::getName(int row)
{
    QString result;
    if (row >=0 && row < rowCount()) {
        QStandardItem *param = item(row,0);
        if (param) {
            result = param->text();
        }else {
            qWarning("XsldbgParamModel::getName item not retrieved");
        }
    }

    return result;
}

QString XsldbgParamModel::getValue(int row)
{

    QString result;
    if (row >=0 && row < rowCount()) {
        QStandardItem *param = item(row,1);
        if (param) {
            result = param->text();
        }else {
            qWarning("XsldbgParamModel::getValue item not retrieved");
        }
    }

    return result;
}

XsldbgConfigImpl::XsldbgConfigImpl(QWidget *parent /*=0*/)
	: QWidget(parent)
{
	setupUi(this);
	paramIndex= 0;

        // setup the map of optionID to line edits
        lineEdits.insert(OPTIONS_SOURCE_FILE_NAME, xslSourceEdit);
        lineEdits.insert(OPTIONS_DATA_FILE_NAME, xmlDataEdit);
        lineEdits.insert(OPTIONS_OUTPUT_FILE_NAME, outputFileEdit);
        lineEdits.insert(OPTIONS_CWD, workDirEdit);
        // emit the changed signal when a lined edit has changed
        QLineEdit *ed;
        foreach (int optionID, lineEdits.keys()) {
            ed = lineEdits.value(optionID);
            connect(ed, SIGNAL(textChanged(const QString &)), this, SIGNAL(changed()));
        }


        // setup the map of optionID to check boxes
        checkBoxes.insert(OPTIONS_CATALOGS, catalogsChkBox);
        checkBoxes.insert(OPTIONS_DEBUG, debugChkBox);
        checkBoxes.insert(OPTIONS_HTML, htmlChkBox);
        checkBoxes.insert(OPTIONS_DOCBOOK,docbookChkBox);
        checkBoxes.insert(OPTIONS_NET, netChkBox);
        checkBoxes.insert(OPTIONS_VALID, validChkBox);
        checkBoxes.insert(OPTIONS_OUT, outChkBox);
        checkBoxes.insert(OPTIONS_TIMING, timingChkBox);
        checkBoxes.insert(OPTIONS_PROFILING, profileChkBox);
        // emit the changed signal when a checkbox has changed
        QCheckBox *chk;
        foreach (int optionID, checkBoxes.keys()) {
            chk = checkBoxes.value(optionID);
            connect(chk, SIGNAL(stateChanged(int)),this,SIGNAL(changed()));
        }



        paramModel = new XsldbgParamModel(this);
        Q_ASSERT(paramModel);
        //  emit the changed signal when something in the paramModel has changed
        connect(paramModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)),
                this, SIGNAL(changed()));
        connect(paramModel, SIGNAL(rowsInserted(QModelIndex, int, int)),
                this, SIGNAL(changed()));
        connect(paramModel, SIGNAL(rowsRemoved(QModelIndex, int, int)),
                this, SIGNAL(changed()));
        paramTable->setModel(paramModel);

}

XsldbgConfigImpl::~XsldbgConfigImpl()
{
}

void XsldbgConfigImpl::setModel(XsldbgSettingsModel *theModel)
{
    Q_ASSERT(theModel);

    if (theModel)
        connect(theModel, SIGNAL(modelReset()), this, SLOT(refresh()));
    else
        disconnect(model, SIGNAL(modelReset()), this, SLOT(refresh()));

    model = theModel;
}

void XsldbgConfigImpl::show()
{
    updatesDisabled = false ;
    QWidget::show();
    refresh();
}


void XsldbgConfigImpl::addParam(const QString & name, const QString & value)
{
    if (!model || !model->addParameter(name, value)) 
        qWarning() << " Failed to add parameter '" << name << "'";
}


void XsldbgConfigImpl::deleteParam(const QString & name)
{
    if (!model || !model->removeParameter(name)) 
        qWarning() << " Failed to remove parameter '" << name << "'";
}


bool XsldbgConfigImpl::isValid()
{
  bool isOK = true;
  m_lastError = "";
  if (xslSourceEdit->text().isEmpty())
    m_lastError.append( i18n("\t\"XSL source\" \n"));
  if (xmlDataEdit->text().isEmpty())
    m_lastError.append(i18n("\t\"XML data\" \n"));
  if (outputFileEdit->text().isEmpty())
    m_lastError.append(i18n("\t\"Output file\" \n"));
  if (!m_lastError.isEmpty()){
    m_lastError.prepend(i18n("Missing values for \n"));
    isOK = false;
  }else if (( xslSourceEdit->text() == outputFileEdit->text())  ||
	    (xmlDataEdit->text() == outputFileEdit->text())){
    m_lastError.append(i18n("Output file is the same as either XSL Source or "
		    "XML Data file\n"));
    isOK = false;
  }

  return isOK;
}


/*we previously said that isValid() == true so we must commit our changes */
void XsldbgConfigImpl::update()
{
    QString msg;
    if (!model)
        return;

    updatesDisabled = true;
    /* update values from line edits, ie source, data, output, workDir */
    QVariant value;
    QString newText;
    foreach (int optionID, lineEdits.keys()) {
        newText = lineEdits.value(optionID)->text();
        // expand a "~" prefix into the $HOME and add "file:///" if required
        value = filesExpandName(newText, optionID != OPTIONS_CWD);
        model->updateSetting(optionID, value);
    }


    foreach (int optionID, checkBoxes.keys()) {
        value = checkBoxes.value(optionID)->checkState() == Qt::Checked;
        model->updateSetting(optionID, value);
    }

    // must have these values set
    value = true;
    model->updateSetting(int(OPTIONS_PREFER_HTML), value);
    model->updateSetting(int(OPTIONS_UTF8_INPUT), value);
    model->updateSetting(int(OPTIONS_SHELL), value);


    // update parameters
    model->removeAllParameters();
    for (int row = 0; row < paramModel->rowCount(); row++) {
        if (!model->addParameter(paramModel->getName(row), paramModel->getValue(row)))
            qWarning() << " Failed to add parameter '" << paramModel->getName(row) << "'";
    }
    updatesDisabled = false;

    emit appliedSettings();
}


void XsldbgConfigImpl::refresh()
{
    // do not refresh the data unless this dialog is showing
    if (!isVisible() || !model || updatesDisabled)
        return;

    model->lock(true); // ensure that the option data does not change underneath us
    int row;
    QModelIndex myIndex = model->index(0,0);
    foreach (int optionID, lineEdits.keys()) {
        row =  model->findModelRow(optionID);
        if (row >= 0) {
            myIndex = model->index(row,0);
            lineEdits.value(optionID)->setText(model->data(myIndex,
                                XsldbgSettingsModel::SettingValueRole).toString());
        }else {
            qWarning() << "Did not find option" << optionID << " in OptionID map";
        }
    }

    bool checkValue;
    Qt::CheckState checkState;
    foreach (int optionID, checkBoxes.keys()) {
        row =  model->findModelRow(optionID);
        if (row >= 0) {
            myIndex = model->index(row,0);
            checkValue = model->data(myIndex,
                    XsldbgSettingsModel::SettingValueRole).toBool();
            if (checkValue) 
                checkState = Qt::Checked;
            else
                checkState = Qt::Unchecked;
            checkBoxes.value(optionID)->setCheckState(checkState);
        }else {
            qWarning() << "Did not find option" << optionID << " in OptionID map";
        }
    }

    //refresh the parameters
    paramModel->clear();
    QStringList headerlabels;
    headerlabels << i18nc("variable name", "Name") << i18nc("variable value", "Value");
    paramModel->setHorizontalHeaderLabels(headerlabels);
    QStringList paramList =
        model->settingsList(XsldbgSettingsModel::ParamSettingType,
                XsldbgSettingsModel::SortByName);
    XsldbgSettingData item;
    foreach (QString paramItem, paramList){
        if (model->findSetting(paramItem, XsldbgSettingsModel::ParamSettingType,  item)) {
            paramModel->addItem(item.m_name, item.m_value.toString());
        }else {
            qWarning() << " Did not find parameter named '" << paramItem << "'";
        }
    }
    paramTable->resizeColumnsToContents();

    model->lock(false); // allow option data to change again
}


void XsldbgConfigImpl::on_xslSourceButton_clicked()
{
	KUrl url = KFileDialog::getOpenUrl(KUrl(), "*.xsl; *.XSL; *.Xsl ; *.xslt; *.XSLT; *.Xslt \n *.*", this,
		i18n("Choose XSL Source to Debug"));
	QString fileName = url.prettyUrl();

	if ((!fileName.isNull()) && (fileName.length() > 0)){
	    xslSourceEdit->setText(XsldbgDebugger::fixLocalPaths(fileName));
	}
}


void XsldbgConfigImpl::on_xmlDataButton_clicked()
{
	KUrl url = KFileDialog::getOpenUrl(KUrl(), "*.xml; *.XML; *.Xml \n*.docbook \n *.html;*.HTML; *.htm ; *HTM \n *.*", this,
									i18n("Choose XML Data to Debug"));
	QString fileName = url.prettyUrl();

	if (!fileName.isEmpty())
		xmlDataEdit->setText(XsldbgDebugger::fixLocalPaths(fileName));
}


void XsldbgConfigImpl::on_outputFileButton_clicked()
{
	KUrl url = KFileDialog::getSaveUrl(KUrl(), "*.xml; *.XML; *.Xml \n*.docbook \n *.txt; *.TXT \n *.htm;*.HTM;*.htm;*.HTML \n*.*", this,
									i18n("Choose Output File for XSL Transformation"));
	if (url.isLocalFile()){
	    QString fileName = url.prettyUrl();
	    if (!fileName.isEmpty())
		outputFileEdit->setText(XsldbgDebugger::fixLocalPaths(fileName));
	}
}

void XsldbgConfigImpl::on_workDirButton_clicked()
{
        KUrl startUrl(workDirEdit->text());
        QString recentDirClass;
	QString dirName = KFileDialog::getExistingDirectory(startUrl,this,
                                        i18n("Choose working directory for XSL Transformation"));

	if (!dirName.isEmpty()){
	    workDirEdit->setText(XsldbgDebugger::fixLocalPaths(dirName));
	}
}

void XsldbgConfigImpl::slotAddParam()
{
    paramModel->addItem("", "");
    QModelIndex index = paramModel->index(paramModel->rowCount() - 1, 0);
    paramTable->setFocus();
    paramTable->setCurrentIndex(index);
}

void XsldbgConfigImpl::slotDeleteParam()
{
    bool result = false;
    QItemSelectionModel *sel = paramTable->selectionModel();
    if (sel) {
        QModelIndexList sList = sel->selectedIndexes();
        if (sList.count() == 1) {
            QModelIndex sIndex = sList.first();
            paramModel->removeRow(sIndex.row());
            result = true;
        }
    }
    if (!result)
        QMessageBox::information(this, i18n("Unable to delete a LibXSLT parameter"),
                    i18n("Select a LibXSLT parameter before trying to delete a parameter"));
}


void XsldbgConfigImpl::slotApply()
{
    // Validate the users choices before applying it
    if (isValid()){
	if (!lastError().isEmpty())
	    QMessageBox::information(this, i18n("Suspect Configuration"),
		    lastError(), QMessageBox::Ok);
	update();
    }else{
	QMessageBox::information(this, i18n("Incomplete or Invalid Configuration"),
		lastError(), QMessageBox::Ok);
    }
}


void XsldbgConfigImpl::slotCancel()
{
}

#include "xsldbgconfigimpl.moc"
