/*

                          Firewall Builder

                 Copyright (C) 2009 NetCitadel, LLC

  Author:  Vadim Kurland     vadim@fwbuilder.org

  $Id$

  This program is free software which we release under the GNU General Public
  License. You may redistribute and/or modify this program under the terms
  of that 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 wdarranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  To get a copy of the GNU General Public License, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/


#include "../../config.h"
#include "global.h"
#include "check_update_url.h"
#include "../../VERSION.h"

#include "utils.h"
#include "platforms.h"

#include "PrefsDialog.h"
#include "FWBSettings.h"
#include "FWWindow.h"
#include "ProjectPanel.h"
#include "HttpGet.h"

#include "fwbuilder/Resources.h"

#include <qlineedit.h>
#include <qfiledialog.h>
#include <qcombobox.h>
#include <qlistwidget.h>
#include <qdir.h>
#include <qlabel.h>
#include <qcolor.h>
#include <qtooltip.h>
#include <qspinbox.h>
#include <qpainter.h>
#include <qpushbutton.h>
#include <qcolordialog.h>
#include <qcolor.h>
#include <qpixmapcache.h>
#include <qfontdialog.h>
#include <qmessagebox.h>

#include <QTreeWidgetItem>
#include <QUrl>
#include <QCheckBox>
#include <QFrame>
#include <QTableWidget>
#include <QHeaderView>

#include <sstream>

/*

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#ifdef _WIN32
#  include <direct.h>
#  include <stdlib.h>
#  include <io.h>
#else
#  include <unistd.h>
#endif
*/

#include <iostream>

using namespace std;

void PrefsDialog::setButtonColor(QPushButton *btn,const QString &colorCode)
{
    QPixmap pm(40,14);
    pm.fill( QColor(colorCode) );
    QPainter p( &pm );
    p.drawRect( pm.rect() );
    btn->setIcon(QIcon(pm));
}

PrefsDialog::~PrefsDialog()
{
    disconnect(&current_version_http_getter, SIGNAL(done(const QString&)),
               this, SLOT(checkForUpgrade(const QString&)));

    delete m_dialog;
}

PrefsDialog::PrefsDialog(QWidget *parent) : QDialog(parent)
{
    m_dialog = new Ui::prefsDialog_q;
    m_dialog->setupUi(this);

    m_dialog->tabWidget->setCurrentIndex(0);

    m_dialog->wDir->setText( st->getWDir() );

    m_dialog->objTooltips->setChecked( st->getObjTooltips() );
    m_dialog->tooltipDelay->setValue( st->getTooltipDelay() );

    m_dialog->deletedObj->setChecked( st->getBool("UI/ShowDeletedObjects") );
    m_dialog->attributesInTree->setChecked( st->getBool("UI/ShowObjectsAttributesInTree") );

    m_dialog->emptyRCSLog->setChecked( st->getRCSLogState() );
    m_dialog->autosave->setChecked( st->getAutoSave() );

    m_dialog->autosaveFile->setChecked(st->getBool("Environment/autoSaveFile"));
    m_dialog->autosaveInterval->setValue(
        st->getInt("Environment/autoSaveFilePeriod"));

    m_dialog->dataFileCompression->setChecked( st->getCompression() );

//    dontSaveStdLib->setChecked( st->getDontSaveStdLib() );

    m_dialog->sshPath->setText( st->getSSHPath() );
    m_dialog->scpPath->setText( st->getSCPPath() );
    m_dialog->rememberSshPass->setChecked( st->getBool("Environment/RememberSshPassEnabled") );

    m_dialog->showTips->setChecked( st->getBool("UI/NoStartTip") );

// set label icons colors and text strings using user's settings

    QString t;
    colors[FWBSettings::RED]=st->getLabelColor(FWBSettings::RED);
    t=st->getLabelText (FWBSettings::RED);

    setButtonColor(m_dialog->redBtn,colors[FWBSettings::RED]);
    m_dialog->redText->setText(t);

    colors[FWBSettings::ORANGE]=st->getLabelColor(FWBSettings::ORANGE);
    t=st->getLabelText (FWBSettings::ORANGE);

    setButtonColor(m_dialog->orangeBtn,colors[FWBSettings::ORANGE]);
    m_dialog->orangeText->setText(t);

    colors[FWBSettings::YELLOW]=st->getLabelColor(FWBSettings::YELLOW);
    t=st->getLabelText (FWBSettings::YELLOW);

    setButtonColor(m_dialog->yellowBtn,colors[FWBSettings::YELLOW]);
    m_dialog->yellowText->setText(t);

    colors[FWBSettings::GREEN]=st->getLabelColor(FWBSettings::GREEN);
    t=st->getLabelText (FWBSettings::GREEN);

    setButtonColor(m_dialog->greenBtn,colors[FWBSettings::GREEN]);
    m_dialog->greenText->setText(t);

    colors[FWBSettings::BLUE]=st->getLabelColor(FWBSettings::BLUE);
    t=st->getLabelText (FWBSettings::BLUE);

    setButtonColor(m_dialog->blueBtn,colors[FWBSettings::BLUE]);
    m_dialog->blueText->setText(t);

    colors[FWBSettings::PURPLE]=st->getLabelColor(FWBSettings::PURPLE);
    t=st->getLabelText (FWBSettings::PURPLE);

    setButtonColor(m_dialog->purpleBtn,colors[FWBSettings::PURPLE]);
    m_dialog->purpleText->setText(t);

    colors[FWBSettings::GRAY]=st->getLabelColor(FWBSettings::GRAY);
    t=st->getLabelText (FWBSettings::GRAY);

    setButtonColor(m_dialog->grayBtn,colors[FWBSettings::GRAY]);
    m_dialog->grayText->setText(t);

    m_dialog->chShowIcons->setChecked(st->getShowIconsInRules() );
    m_dialog->showDirectionText->setChecked(st->getShowDirectionText());
    if (FWBSettings::SIZE25X25 == st->getIconsInRulesSize())
        m_dialog->rb25->setChecked(true);
    else
        m_dialog->rb16->setChecked(true);
    changeShowIcons();

    rulesFont = st->getRulesFont();
    treeFont = st->getTreeFont();
    uiFont = st->getUiFont();
    compilerOutputFont = st->getCompilerOutputFont();

    m_dialog->rulesFontDescr->setText(getFontDescription(rulesFont));
    m_dialog->treeFontDescr->setText(getFontDescription(treeFont));
    m_dialog->compilerOutputFontDescr->setText(getFontDescription(compilerOutputFont));

    m_dialog->chClipComment->setChecked(st->getClipComment() );

    m_dialog->checkUpdates->setChecked(st->getCheckUpdates() );

    m_dialog->checkUpdatesProxy->setText(st->getCheckUpdatesProxy() );

#if !defined(Q_OS_WIN32)
    m_dialog->plink_hint->hide();
#endif

    // Fill lists of platforms and host OS

    QMap<QString,QString> platforms = getAllPlatforms(false);
    QMap<QString,QString> os = getAllOS(false);

    m_dialog->enabled_platforms->setRowCount(platforms.size());
    m_dialog->enabled_platforms->setColumnCount(1);
    int row = 0;
    QMap<QString,QString>::iterator it;
    for (it=platforms.begin(); it!=platforms.end(); ++it)
    {
        QString name = it.key();
        QString readable_name = it.value();
        QTableWidgetItem *cb = new QTableWidgetItem(readable_name);
        m_dialog->enabled_platforms->setItem(row, 0, cb);

        QString res_status = Resources::platform_res[name.toStdString()]->getResourceStr(
            "/FWBuilderResources/Target/status/").c_str();
        QString prefs_status = st->getTargetStatus(name, res_status);
        cb->setCheckState((prefs_status=="disabled") ? Qt::Unchecked : Qt::Checked);

        cb->setData(Qt::UserRole, name);
        row++;
    }
    m_dialog->enabled_platforms->horizontalHeader()->setStretchLastSection(true);
    m_dialog->enabled_platforms->sortItems(0);
    m_dialog->enabled_platforms->update();

    m_dialog->enabled_os->setRowCount(os.size());
    m_dialog->enabled_os->setColumnCount(1);
    row = 0;
    for (it=os.begin(); it!=os.end(); ++it)
    {
        QString name = it.key();
        QString readable_name = it.value();
        QTableWidgetItem *cb = new QTableWidgetItem(readable_name);
        m_dialog->enabled_os->setItem(row, 0, cb);

        QString res_status = Resources::os_res[name.toStdString()]->getResourceStr(
            "/FWBuilderResources/Target/status/").c_str();
        QString prefs_status = st->getTargetStatus(name, res_status);
        cb->setCheckState((prefs_status=="disabled") ? Qt::Unchecked : Qt::Checked);

        cb->setData(Qt::UserRole, name);
        row++;
    }
    m_dialog->enabled_os->horizontalHeader()->setStretchLastSection(true);
    m_dialog->enabled_os->sortItems(0);
    m_dialog->enabled_os->update();
}

QString PrefsDialog::getFontDescription(const QFont &font)
{
    ostringstream str;
    str << font.family().toLatin1().constData()
        << " " << font.pointSize();
    return QString(str.str().c_str());
}

void PrefsDialog::changeColor(QPushButton *btn,
                              FWBSettings::LabelColors colorCode)
{
    QColor clr = QColorDialog::getColor(
        QColor(colors[colorCode]), this);

    if (!clr.isValid()) return;
    colors[colorCode]= clr.name();
    setButtonColor(btn,colors[colorCode]);
}

void PrefsDialog::changeRedColor()
{
    changeColor(m_dialog->redBtn, FWBSettings::RED);
}

void PrefsDialog::changeOrangeColor()
{
    changeColor(m_dialog->orangeBtn, FWBSettings::ORANGE);
}

void PrefsDialog::changeYellowColor()
{
    changeColor(m_dialog->yellowBtn, FWBSettings::YELLOW);
}

void PrefsDialog::changeGreenColor()
{
    changeColor(m_dialog->greenBtn, FWBSettings::GREEN);
}

void PrefsDialog::changeBlueColor()
{
    changeColor(m_dialog->blueBtn, FWBSettings::BLUE);
}

void PrefsDialog::changePurpleColor()
{
    changeColor(m_dialog->purpleBtn, FWBSettings::PURPLE);
}

void PrefsDialog::changeGrayColor()
{
    changeColor(m_dialog->grayBtn, FWBSettings::GRAY);
}

void PrefsDialog::changeIconSize25()
{
    //st->setIconsInRulesSize(FWBSettings::SIZE25X25);
}

void PrefsDialog::changeIconSize16()
{
    //st->setIconsInRulesSize(FWBSettings::SIZE16X16);
}

void PrefsDialog::changeShowIcons()
{
    bool areShown = m_dialog->chShowIcons->isChecked();
    m_dialog->rb16->setEnabled(areShown);
    m_dialog->rb25->setEnabled(areShown);
}

void PrefsDialog::changeRulesFont()
{
    changeFont(rulesFont);
    m_dialog->rulesFontDescr->setText(getFontDescription(rulesFont));
}

void PrefsDialog::changeTreeFont()
{
    changeFont(treeFont);
    m_dialog->treeFontDescr->setText(getFontDescription(treeFont));
}

void PrefsDialog::changeCompilerOutputFont()
{
    changeFont(compilerOutputFont);
    m_dialog->compilerOutputFontDescr->setText(getFontDescription(compilerOutputFont));
}

void PrefsDialog::changeFont(QFont &font)
{
    bool ok;
    QFont f = QFontDialog::getFont(&ok, font, this);
    if (ok)
        font = f;
}

void PrefsDialog::findWDir()
{
    QString wd = st->getWDir();
    QString dir = QFileDialog::getExistingDirectory(
            this, tr("Find working directory"), wd, QFileDialog::ShowDirsOnly );

    if (!dir.isEmpty()) m_dialog->wDir->setText(dir);
}

void PrefsDialog::findSSH()
{
    QString fp = QFileDialog::getOpenFileName(
        this,
        tr("Find Secure Shell utility") );

    if (!fp.isEmpty()) m_dialog->sshPath->setText(fp);
}

void PrefsDialog::findSCP()
{
    QString fp = QFileDialog::getOpenFileName(
        this,
        tr("Find SCP utility") );

    if (!fp.isEmpty()) m_dialog->scpPath->setText(fp);
}

void PrefsDialog::accept()
{
    QString wd=m_dialog->wDir->text();

/* check if the default working directory does not exist yet */

    st->setWDir( wd );

    st->setObjTooltips( m_dialog->objTooltips->isChecked() );
    st->setTooltipDelay( m_dialog->tooltipDelay->value() );

    st->setBool("UI/ShowDeletedObjects", m_dialog->deletedObj->isChecked());
    st->setBool("UI/ShowObjectsAttributesInTree", m_dialog->attributesInTree->isChecked());

    ProjectPanel *pp = mw->activeProject();
    if (pp)
    {
        pp->m_panel->om->setAttributesColumnEnabled(
            m_dialog->attributesInTree->isChecked());
        if (m_dialog->attributesInTree->isChecked())
            pp->m_panel->om->loadSectionSizes();
    }

//  QToolTip::setWakeUpDelay( st->getTooltipDelay()*1000 );

    st->setRCSLogState( m_dialog->emptyRCSLog->isChecked() );
    st->setAutoSave( m_dialog->autosave->isChecked() );

    st->setBool("Environment/autoSaveFile", m_dialog->autosaveFile->isChecked());
    st->setInt("Environment/autoSaveFilePeriod", m_dialog->autosaveInterval->value() );

    st->setCompression(m_dialog->dataFileCompression->isChecked());

//    st->setDontSaveStdLib( dontSaveStdLib->isChecked() );

    st->setLabelColor(FWBSettings::RED,    colors[FWBSettings::RED]);
    st->setLabelColor(FWBSettings::ORANGE, colors[FWBSettings::ORANGE]);
    st->setLabelColor(FWBSettings::YELLOW, colors[FWBSettings::YELLOW]);
    st->setLabelColor(FWBSettings::GREEN,  colors[FWBSettings::GREEN]);
    st->setLabelColor(FWBSettings::BLUE,   colors[FWBSettings::BLUE]);
    st->setLabelColor(FWBSettings::PURPLE, colors[FWBSettings::PURPLE]);
    st->setLabelColor(FWBSettings::GRAY,   colors[FWBSettings::GRAY]);

    st->setLabelText (FWBSettings::RED,    m_dialog->redText->text() );
    st->setLabelText (FWBSettings::ORANGE, m_dialog->orangeText->text() );
    st->setLabelText (FWBSettings::YELLOW, m_dialog->yellowText->text() );
    st->setLabelText (FWBSettings::GREEN,  m_dialog->greenText->text() );
    st->setLabelText (FWBSettings::BLUE,   m_dialog->blueText->text() );
    st->setLabelText (FWBSettings::PURPLE, m_dialog->purpleText->text() );
    st->setLabelText (FWBSettings::GRAY,   m_dialog->grayText->text() );

    st->setShowIconsInRules(m_dialog->chShowIcons->isChecked());
    st->setShowDirectionText(m_dialog->showDirectionText->isChecked());
    FWBSettings::IconSize sz = m_dialog->rb25->isChecked() ?
        FWBSettings::SIZE25X25 : FWBSettings::SIZE16X16;
    st->setIconsInRulesSize(sz);

    st->setRulesFont(rulesFont);
    st->setTreeFont(treeFont);
    st->setUiFont(uiFont);
    st->setCompilerOutputFont(compilerOutputFont);

    st->setClipComment(m_dialog->chClipComment->isChecked());
    st->setCheckUpdates(m_dialog->checkUpdates->isChecked());
    st->setCheckUpdatesProxy(m_dialog->checkUpdatesProxy->text());

    st->setSSHPath( m_dialog->sshPath->text() );
    st->setSCPPath( m_dialog->scpPath->text() );
    st->setBool("Environment/RememberSshPassEnabled", m_dialog->rememberSshPass->isChecked());
    
    for (int row=0; row < m_dialog->enabled_platforms->rowCount(); ++row)
    {
        QTableWidgetItem *itm = m_dialog->enabled_platforms->item(row, 0);
        st->setTargetStatus(itm->data(Qt::UserRole).toString(),
                            (itm && itm->checkState() == Qt::Unchecked) ?
                            "disabled" : "active");
    }

    QStringList disabled_os;
    for (int row=0; row < m_dialog->enabled_os->rowCount(); ++row)
    {
        QTableWidgetItem *itm = m_dialog->enabled_os->item(row, 0);
        st->setTargetStatus(itm->data(Qt::UserRole).toString(),
                            (itm && itm->checkState() == Qt::Unchecked) ?
                            "disabled" : "active");
    }

    if (!wd.isEmpty())
    {
        QDir d;
        d.mkdir( wd );
    }

    mw->setupAutoSave();
    mw->showDeletedObjects(st->getBool("UI/ShowDeletedObjects"));
    mw->updateTreeFont();
//    app->setFont(st->getTreeFont());
    st->setBool("UI/NoStartTip", m_dialog->showTips->isChecked());
    QDialog::accept();
}

void PrefsDialog::checkSwUpdates()
{
    st->setCheckUpdatesProxy(m_dialog->checkUpdatesProxy->text());

    connect(&current_version_http_getter, SIGNAL(done(const QString&)),
            this, SLOT(checkForUpgrade(const QString&)));
    QString url = QString(CHECK_UPDATE_URL).arg(VERSION).arg(st->getAppGUID());
    current_version_http_getter.get(QUrl(url));
}

void PrefsDialog::checkForUpgrade(const QString& server_response)
{
    disconnect(&current_version_http_getter, SIGNAL(done(const QString&)),
               this, SLOT(checkForUpgrade(const QString&)));

    if (current_version_http_getter.getStatus())
    {
        /*
         * server response may be some html or other data in case
         * connection goes via proxy, esp. with captive portals. We
         * should not interpret that as "new version is available"
         */
        if (server_response.trimmed() == "update = 1")
        {
            QMessageBox::warning(
                this,"Firewall Builder",
                tr("A new version of Firewall Builder is available at"
                   " http://www.fwbuilder.org"));
        } else
        {
            QMessageBox::information(
                this,"Firewall Builder",
                tr("Your version of Firewall Builder is up to date."));
        }
    } else
    {
        QMessageBox::critical(
            this,"Firewall Builder",
            tr("Error checking for software updates:\n%1").
            arg(current_version_http_getter.getLastError()));
    }
}


