/*
 * kioskgui.cpp
 *
 *   Copyright (C) 2003,2004 Waldo Bastian <bastian@kde.org>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License versin 2 as
 *   published by the Free Software Foundation.
 *
 *   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 "kioskgui.h"

#include <qdir.h>
#include <qlineedit.h>
#include <qobjectlist.h>
#include <qwidgetstack.h>
#include <qpushbutton.h>

#include <kapplication.h>
#include <kaction.h>
#include <kcombobox.h>
#include <kconfig.h>
#include <kfiledialog.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <kiconview.h>
#include <klocale.h>
#include <kmenubar.h>
#include <kmessagebox.h>
#include <kstatusbar.h>
#include <kstdaccel.h>
#include <kstdaction.h>
#include <kstandarddirs.h>
#include <kurlrequester.h>

#include "mainview.h"
#include "profileSelectionPage_ui.h"
#include "profilePropsPage.h"
#include "componentSelectionPage.h"
#include "desktopComponent.h"
#include "menueditComponent.h"
#include "screensaverComponent.h"
#include "panelComponent.h"
#include "filetypeeditComponent.h"
#include "componentPage.h"
#include "pageWidget.h"
#include "userManagement.h"
#include "kioskConfigDialog.h"
#include "kioskdata.h"
#include "kioskrun.h"
#include "kiosksync.h"

KioskGui::KioskGui()
    : KMainWindow( 0, "kioskgui" ), m_profileSelectionPage(0),
    m_componentSelectionPage(0), m_componentPage(0), m_profileAssignPage(0),
    m_profilePropsPage(0), m_data(0),
    m_activePage(0), m_profile(0), m_componentData(0)
{
    m_run = new KioskRun;

    m_view = new MainView(this);

    setupActions();

    updateBackground();

    // tell the KMainWindow that this is indeed the main widget
    setCentralWidget(m_view);

    setWidgetBackground(m_view);
    m_view->setBackgroundOrigin(WindowOrigin);


    createGUI();

    // apply the saved mainwindow settings, if any, and ask the mainwindow
    // to automatically save settings if changed: window size, toolbar
    // position, icon size, etc.
    setAutoSaveSettings();

    m_view->pbHelp->hide(); // TODO, write help :)

    connect(m_view->pbDiscard, SIGNAL(clicked()), this, SLOT(discardPage()));
    connect(m_view->pbFinished, SIGNAL(clicked()), this, SLOT(finishedPage()));

    KConfig *config = kapp->config();
    config->setGroup("General");
    m_profile = config->readEntry("CurrentProfile", "default");
    m_component = config->readEntry("CurrentComponent");

    selectPage(PAGE_PROFILE_SELECTION, true);
    
    QTimer::singleShot(0, this, SLOT(slotCheckEtcSkel()));
}

KioskGui::~KioskGui()
{
    delete m_data;
    delete m_run;
}

void KioskGui::slotCheckEtcSkel()
{
    QString etcSkel = "/etc/skel/.kde";
    KioskSync skelDir;
    skelDir.addDir(etcSkel, KURL());
    QStringList skelFiles = skelDir.listFiles();
    if (!skelFiles.isEmpty())
    {
        KMessageBox::informationList(this,
            i18n("<qt>Your system contains KDE configuration settings in the "
                 "skeleton directory <b>%1</b>. These files are copied to the "
                 "personal KDE settings directory of newly created users.<p>"
                 "This may interfere with the correct operation of user profiles.<p>"
                 "Unless a setting has been locked down, settings that have been copied "
                 "to the personal KDE settings directory of a user will override "
                 "a default setting configured in a profile.<p>"
                 "<b>If this is not the intended behavior, please remove the offending "
                 "files from the skeleton folder on all systems that you want to "
                 "administer with user profiles.</b><p>"
                 "The following files were found under <b>%2</b>:").arg(etcSkel).arg(etcSkel),
            skelFiles,
            QString::null,
            "etc_skel_warning");
    }
}

void KioskGui::setWidgetBackground(QWidget *w)
{
    QObjectList *l = w->queryList( "QWidget" );
    QObjectListIt it( *l );
    for(QWidget *wid=0; (wid = (QWidget*)it.current()); ++it)
    {
        wid->setBackgroundOrigin(WindowOrigin);
        if (::qt_cast<QPushButton*>(wid))
           wid->setAutoMask(true);
    }
    w->setBackgroundOrigin(WindowOrigin);
    delete l;
}

void KioskGui::setSubCaption(const QString &subCaption)
{
    m_view->subCaptionLabel->setText("<h1>"+subCaption+"</h1>");
}

void KioskGui::setupActions()
{
//    KStdAction::open(this, SLOT(fileOpen()), actionCollection());
//    KStdAction::save(this, SLOT(fileSave()), actionCollection());
//    KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
    KStdAction::quit(this, SLOT(close()), actionCollection());
//    KStdAction::back(this, SLOT(previousPage()), actionCollection(), "previousPage");
//    KStdAction::forward(this, SLOT(nextPage()), actionCollection(), "nextPage");

//    createStandardStatusBarAction();
//    setStandardToolBarMenuEnabled(true);

//    KStdAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection());
//    KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection());
    KStdAction::preferences(this, SLOT(slotConfig()), actionCollection());
    m_uploadAction = new KAction(i18n("Upload &All Profiles"), QString::null, 0, this, SLOT(uploadAllProfiles()), actionCollection(), "upload_all");
    m_backgroundAction = new KToggleAction(i18n("Background Graphics"), QString::null, 0, this, SLOT(slotUpdateBackground()), actionCollection(), "show_background");

    updateActions();
}

void KioskGui::updateActions()
{
   KConfig *config = kapp->config();
   config->setGroup("General");
   
   bool uploadEnabled = !config->readEntry("uploadURL").isEmpty();
   
   m_uploadAction->setEnabled(uploadEnabled);
   m_backgroundAction->setChecked(config->readBoolEntry("FancyBackground", true));
}

void KioskGui::saveProperties(KConfig * /*config*/ )
{
    // the 'config' object points to the session managed
    // config file.  anything you write here will be available
    // later when this app is restored
}

void KioskGui::readProperties(KConfig * /*config*/ )
{
    // the 'config' object points to the session managed
    // config file.  this function is automatically called whenever
    // the app is being restored.  read in here whatever you wrote
    // in 'saveProperties'
}

void KioskGui::slotAddProfile()
{
    selectPage(PAGE_PROFILE_NEW, true);
}

void KioskGui::slotProfileProperties()
{
    selectPage(PAGE_PROFILE_PROPS, true);
#if 0
    savePage(PAGE_PROFILE_SELECTION);
    ProfileConfigDialog dlg(this, m_profile);
    if (dlg.exec())
    {
       loadPage(PAGE_PROFILE_SELECTION);
       updateActions();
    }
#endif
}

void KioskGui::slotProfileSetup()
{
    selectPage(PAGE_COMPONENT_SELECTION, true);
}

void KioskGui::slotDeleteProfile(QListViewItem *item)
{
    if (!m_profileSelectionPage)
       return;
    if (!item)
       item = m_profileSelectionPage->listProfile->selectedItem();
    if (!item)
       return;
    QString profile = item->text(0);
    int result = KMessageBox::warningContinueCancel(this,
               i18n("<qt>You are about to delete the profile <b>%1</b>.<p>"
                    "Are you sure you want to do this?").arg(profile),
               QString::null, KGuiItem(i18n("Delete"),"editdelete"));
    if (result == KMessageBox::Continue)
    {
       if (KioskRun::self()->deleteProfile(profile))
       {
          delete item;

          item = m_profileSelectionPage->listProfile->currentItem();
          if (item)
             m_profileSelectionPage->listProfile->setSelected(item, true);
       }
    }
}

void KioskGui::slotManageUsers()
{
    selectPage(PAGE_PROFILE_ASSIGN, true);
}

void KioskGui::slotProfileContextMenu(QListViewItem *item, const QPoint &p)
{
    if (!item) return; // No item selected

    QPopupMenu menu(this);
    menu.insertItem(i18n("&Delete Profile"), 1);

    int result = menu.exec( p );
    if (result == 1)
       slotDeleteProfile(item);
}

void KioskGui::selectPage(int page, bool save)
{
    if (save && !savePage(m_activePage))
       return;
    m_activePage = page;
    if ((m_activePage == PAGE_PROFILE_SELECTION) && !m_profileSelectionPage)
    {
       m_profileSelectionPage = new ProfileSelectionPageUI(this);
       setWidgetBackground(m_profileSelectionPage);

       connect(m_profileSelectionPage->listProfile,
               SIGNAL(contextMenuRequested(QListViewItem *, const QPoint &, int)),
               this, SLOT(slotProfileContextMenu(QListViewItem *, const QPoint &)));
       connect(m_profileSelectionPage->listProfile,
               SIGNAL(doubleClicked (QListViewItem *, const QPoint &, int )),
               this, SLOT(nextPage()));
       connect(m_profileSelectionPage->buttonDelete, SIGNAL(clicked()),
               this, SLOT(slotDeleteProfile()));
       connect(m_profileSelectionPage->buttonAdd, SIGNAL(clicked()),
               this, SLOT(slotAddProfile()));
       connect(m_profileSelectionPage->buttonProperty, SIGNAL(clicked()),
               this, SLOT(slotProfileProperties()));
       connect(m_profileSelectionPage->buttonSetup, SIGNAL(clicked()),
               this, SLOT(slotProfileSetup()));
       connect(m_profileSelectionPage->buttonUsers, SIGNAL(clicked()),
               this, SLOT(slotManageUsers()));

       m_view->widgetStack->addWidget(m_profileSelectionPage, PAGE_PROFILE_SELECTION);
       m_profileSelectionPage->listProfile->setFocus();
    }
    if ((m_activePage == PAGE_COMPONENT_SELECTION) && !m_componentSelectionPage)
    {
       m_data = new KioskData;
       if (!m_data->load())
       {
          KMessageBox::error(this, m_data->errorMsg(), i18n("Error accessing Kiosk data"));
       }

       m_componentSelectionPage = new ComponentSelectionPage(m_data, this);
       connect(m_componentSelectionPage, SIGNAL(componentActivated()), this, SLOT(nextPage()));
       m_componentSelectionPage->setCurrentComponent(m_component);
       setWidgetBackground(m_componentSelectionPage);

       m_view->widgetStack->addWidget(m_componentSelectionPage, PAGE_COMPONENT_SELECTION);
       m_componentSelectionPage->listComponent->setFocus();
    }
    if (m_activePage == PAGE_PROFILE_NEW)
    {
       delete m_profilePropsPage;
       m_profilePropsPage = new ProfilePropsPage(this, QString::null);
       setWidgetBackground(m_profilePropsPage->widget());

       m_view->widgetStack->addWidget(m_profilePropsPage->widget(), PAGE_PROFILE_NEW);
       m_profilePropsPage->setFocus();
    }
    if (m_activePage == PAGE_PROFILE_PROPS)
    {
       delete m_profilePropsPage;
       m_profilePropsPage = new ProfilePropsPage(this, m_profile);
       setWidgetBackground(m_profilePropsPage->widget());

       m_view->widgetStack->addWidget(m_profilePropsPage->widget(), PAGE_PROFILE_PROPS);
       m_profilePropsPage->setFocus();
    }
    if ((m_activePage == PAGE_PROFILE_ASSIGN) && !m_profileAssignPage)
    {
       m_profileAssignPage = new UserManagementPage(this);
       setWidgetBackground(m_profileAssignPage->widget());

       m_view->widgetStack->addWidget(m_profileAssignPage->widget(), PAGE_PROFILE_ASSIGN);
       m_profileAssignPage->setFocus();
    }
    if (m_activePage == PAGE_COMPONENT)
    {
       delete m_componentPage;

       Component *component = 0;
       if (m_component == "kdesktop")
          component = new DesktopComponent;
       else if (m_component == "kdemenu")
          component = new MenuEditComponent;
       else if (m_component == "screensaver")
          component = new ScreenSaverComponent;
       else if (m_component == "kicker")
          component = new PanelComponent;
       else if (m_component == "filetypes")
          component = new FileTypeEditComponent;

       m_componentPage = new ComponentPage(m_componentData, component, m_view->widgetStack);
       setWidgetBackground(m_componentPage->widget());
       m_view->widgetStack->addWidget(m_componentPage->widget(), PAGE_COMPONENT);
       m_componentPage->setFocus();
    }
    m_view->widgetStack->raiseWidget(m_activePage);

    switch (m_activePage)
    {
      case PAGE_PROFILE_SELECTION:
       setSubCaption(i18n("Main Menu"));
       setCaption(i18n("Main Menu"));
       break;
      case PAGE_PROFILE_NEW:
       setSubCaption(i18n("Add New Profile"));
       setCaption(i18n("Add New Profile"));
       break;
      case PAGE_PROFILE_PROPS:
       setSubCaption(i18n("Profile Properties"));
       setCaption(i18n("Profile Properties"));
       break;
      case PAGE_COMPONENT_SELECTION:
       setSubCaption(i18n("Setup Profile \"%1\"").arg(m_profile));
       setCaption(m_profile);
       break;
      case PAGE_COMPONENT:
       setSubCaption(m_componentPage->subCaption());
       break;
      case PAGE_PROFILE_ASSIGN:
       setSubCaption(i18n("Assign Profiles"));
       break;
    }
    
    loadPage(m_activePage);

    updateButtons();
}

void KioskGui::updateButtons()
{
    switch(m_activePage)
    {
      case PAGE_PROFILE_SELECTION:
      {
         m_view->pbDiscard->hide();
         m_view->pbFinished->hide();
         break;
      }

      case PAGE_COMPONENT_SELECTION:
      {
         m_view->pbDiscard->hide();
         m_view->pbFinished->show();
         break;
      }

      case PAGE_COMPONENT:
      {
         m_view->pbDiscard->hide();
         m_view->pbFinished->show();
         break;
      }

      case PAGE_PROFILE_NEW:
      {
         m_view->pbDiscard->show();
         m_view->pbFinished->show();
         break;
      }

      case PAGE_PROFILE_PROPS:
      {
         m_view->pbDiscard->show();
         m_view->pbFinished->show();
         break;
      }

      case PAGE_PROFILE_ASSIGN:
      {
         m_view->pbDiscard->show();
         m_view->pbFinished->show();
         break;
      }
    }

    if (m_activePage == PAGE_PROFILE_NEW)
    {
      m_view->pbDiscard->setText(i18n("&Cancel"));
      m_view->pbFinished->setText(i18n("&Add"));
    }
    else
    {
      m_view->pbDiscard->setText(i18n("&Discard Changes"));
      m_view->pbFinished->setText(i18n("&Finished"));
    }

}

void KioskGui::loadProfiles()
{
   m_profileSelectionPage->listProfile->clear();

   QStringList profiles = KioskRun::self()->allProfiles();

   for(QStringList::ConstIterator it = profiles.begin();
       it != profiles.end(); ++it)
   {
      QString profile = *it;
      QString description;
      QString installUser;
      QString installDir;

      KioskRun::self()->getProfileInfo(profile, description, installDir, installUser);

      QListViewItem *item = new QListViewItem(m_profileSelectionPage->listProfile, profile, description);
      if (m_profile == profile)
         m_profileSelectionPage->listProfile->setSelected(item, true);
   }
   if (!m_profileSelectionPage->listProfile->selectedItem())
      m_profileSelectionPage->listProfile->setSelected(m_profileSelectionPage->listProfile->firstChild(), true);
}

void KioskGui::loadPage(int page)
{
    switch(page)
    {
      case PAGE_PROFILE_SELECTION:
      {
        loadProfiles();
        break;
      }

      case PAGE_COMPONENT:
      {
        m_componentPage->load();
        break;
      }

      case PAGE_PROFILE_NEW:
      {
        m_profilePropsPage->load();
        break;
      }

      case PAGE_PROFILE_PROPS:
      {
        m_profilePropsPage->load();
        break;
      }

      case PAGE_PROFILE_ASSIGN:
      {
        m_profileAssignPage->load();
        break;
      }
    }
}

bool KioskGui::savePage(int page)
{
    switch(page)
    {
      case PAGE_PROFILE_SELECTION:
      {
        m_profile = m_profileSelectionPage->listProfile->selectedItem() ?
                    m_profileSelectionPage->listProfile->selectedItem()->text(0) : QString::null;

        KConfig *config = kapp->config();
        config->setGroup("General");
        config->writeEntry("CurrentProfile", m_profile);
        config->sync();

        QString description;
        QString installDir;
        QString installUser;

        KioskRun::self()->getProfileInfo(m_profile, description, installDir, installUser);

        QStringList kdeDirs;
        kdeDirs << installDir;
        m_run->setKdeDirs(kdeDirs);
        m_run->setUser(installUser);

        break;
      }

      case PAGE_COMPONENT_SELECTION:
      {
        m_component = m_componentSelectionPage->currentComponent();
        m_componentData = m_data->m_componentData.find(m_component);
        if (!m_componentData)
           return false;

        return m_componentSelectionPage->save();
      }

      case PAGE_COMPONENT:
      {
        if (m_componentPage)
           return m_componentPage->save();
      }

      case PAGE_PROFILE_NEW:
      {
        if (m_profilePropsPage)
        {
           m_profile = m_profilePropsPage->profile();
           return m_profilePropsPage->save();
        }
      }

      case PAGE_PROFILE_PROPS:
      {
        if (m_profilePropsPage)
        {
           m_profile = m_profilePropsPage->profile();
           return m_profilePropsPage->save();
        }
      }

      case PAGE_PROFILE_ASSIGN:
      {
        if (m_profileAssignPage)
           return m_profileAssignPage->save();
      }
    }
    return true;
}

void KioskGui::finishedPage(bool save)
{
    if (m_activePage == PAGE_PROFILE_NEW)
       selectPage(PAGE_PROFILE_SELECTION, save);
    else if (m_activePage == PAGE_PROFILE_PROPS)
       selectPage(PAGE_PROFILE_SELECTION, save);
    else if (m_activePage == PAGE_PROFILE_ASSIGN)
       selectPage(PAGE_PROFILE_SELECTION, save);
    else if (m_activePage > 1)
       selectPage(m_activePage - 1, save);
}

void KioskGui::discardPage()
{
   finishedPage(false);
}

void KioskGui::nextPage()
{
    if (m_activePage < PAGE_LAST)
       selectPage(m_activePage + 1, true);
}

void KioskGui::slotConfig()
{
    KioskConfigDialog dlg(this);
    if (dlg.exec())
    {
       dlg.save();
       updateActions();
    }
}

bool KioskGui::queryClose()
{
    if (!savePage(m_activePage))
    {
       int result = KMessageBox::warningContinueCancel(this,
       		i18n("Your changes could not be saved, do you want to quit anyway?"),
       		QString::null,
       		KStdGuiItem::quit());
       if (result == KMessageBox::Continue)
          return true;
       return false;
    }
    if (m_uploadAction->isEnabled())
    {
       KConfig *config = kapp->config();
       config->setGroup("General");
   
       KURL uploadUrl = config->readEntry("uploadURL");
       int result = KMessageBox::questionYesNo(this,
                    i18n("<qt>Do you want to upload the profiles to <b>%1</b> ?</qt>").arg(uploadUrl.prettyURL()));
       if (result == KMessageBox::Yes)
       {
          uploadAllProfiles();
       }
    }
    
    return true;
}

void KioskGui::uploadAllProfiles()
{
   KConfig *config = kapp->config();
   config->setGroup("General");
   QString uploadPrefix = config->readEntry("uploadPrefix");
   QString uploadURL = config->readEntry("uploadURL");

   KioskSync sync(this);
   
   QStringList profiles = KioskRun::self()->allProfiles();

   for(QStringList::ConstIterator it = profiles.begin();
       it != profiles.end(); ++it)
   {
      QString profile = *it;
      QString description;
      QString installUser;
      QString installDir;

      KioskRun::self()->getProfileInfo(profile, description, installDir, installUser);

//      sync.addDir(installDir, KURL("ftp://localhost/kde/profiles"));

      QString dir = installDir;
      if (dir.startsWith(uploadPrefix))
         dir = dir.mid(uploadPrefix.length());
      if (dir.startsWith("/"))
         dir = dir.mid(1);

      KURL url(uploadURL);
      url.setPath(url.path(1)+dir);
      sync.addDir(installDir, url);
   }

   if (sync.sync())
   {
      KMessageBox::information(this, i18n("<qt>All profiles have been successfully uploaded to <b>%1</b>").arg(uploadURL));
   }
}

void KioskGui::uploadCurrentProfile()
{
}

void KioskGui::slotUpdateBackground()
{
  KConfig *config = kapp->config();
  config->setGroup("General");
  config->writeEntry("FancyBackground", m_backgroundAction->isChecked());
  config->sync();
  updateBackground();
}

void KioskGui::updateBackground()
{
  if (m_backgroundAction->isChecked())
  {
    m_view->setPaletteBackgroundPixmap(locate("appdata", "background.png"));
    m_view->logoLabel->setPixmap(locate("appdata", "logo.png"));
    m_view->logoLabel->setMinimumSize(QSize(160,170));
    QString language = KGlobal::locale()->language();
    QString caption = locate("appdata", "caption-"+language+".png");
    if (caption.isEmpty())
       caption = locate("appdata", "caption.png");
    QPixmap pm(caption);
    m_view->captionLabel->setPixmap(pm);
    m_view->captionLabel->setMinimumHeight(pm.height());
  }
  else
  {
    m_view->unsetPalette();
    m_view->logoLabel->setPixmap(QPixmap());
    m_view->logoLabel->setMinimumSize(0,0);
    m_view->captionLabel->setPixmap(QPixmap());
    m_view->captionLabel->setMinimumHeight(0);
  }
}


#include "kioskgui.moc"
