/***************************************************************************
                           flashkard.cpp  -  description
                             -------------------
    begin                : Tue Feb 12 00:09:29 EST 2002
    copyright            : (C) 2002 by Scott Wheeler
    email                : wheeler@kde.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.                                   *
***************************************************************************/

#include <klocale.h>
#include <kmessagebox.h>
#include <kfiledialog.h>
#include <kcmdlineargs.h>
#include <kdebug.h>

#include <qfile.h>

#include <keduvocdata.h>

#include "flashkard.h"
#include "flashkard.moc"
#include "guesswidget.h"
#include "flashcardswidget.h"
#include "card.h"
#include "xmlwriter.h"

FlashKard::FlashKard(QWidget *parent, const char *name) : 
    KMainWindow(parent, name),
    data(0),
    quiz(0),
    randomQuiz(false),
    changed(false),
    fileExtension("kvtml"),
    focusedLineEdit(0)
{
  fileMask = "*." + fileExtension;

  setupActions();
  setupLayout();
  readConfig();
  processArgs();
}

FlashKard::~FlashKard()
{

}

////////////////////////////////////////////////////////////////////////////////
// public slots
////////////////////////////////////////////////////////////////////////////////

void FlashKard::dataChanged()
{
  QFileInfo fileInfo(fileName);
  setCaption(fileInfo.fileName(), true);
  changed = true;
}

void FlashKard::selectionChanged()
{
  //  kdDebug() << "FlashKard::selectionChanged()" << endl;
  if((data && data->hasSelectedText()) || (quiz && quiz->hasSelectedText()))
    enableCutCopy();
  else
    disableCutCopy();
}

////////////////////////////////////////////////////////////////////////////////
// private member implementations
////////////////////////////////////////////////////////////////////////////////

void FlashKard::setupActions()
{
  // file menu
  KStdAction::openNew(this, SLOT(fileNew()), actionCollection());
  KStdAction::open(this, SLOT(fileOpen()), actionCollection());
  KStdAction::save(this, SLOT(fileSave()), actionCollection());
  KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
  KStdAction::quit(this, SLOT(quit()), actionCollection());

  // edit menu
  cutAction = KStdAction::cut(this, SLOT(cut()), actionCollection());
  copyAction = KStdAction::copy(this, SLOT(copy()), actionCollection());
  pasteAction = KStdAction::paste(this, SLOT(paste()), actionCollection());

  // function menu
  showDataAction = new KAction(i18n("Data Entry"), "edit", 0, this, SLOT(showData()), actionCollection(), "showData");
  showQuizAction = new KAction(i18n("Quiz"), "quiz", 0, this, SLOT(showQuiz()), actionCollection(), "showQuiz");

  // settings menu

  // "Quiz Mode" sub menu
  quizModeAction = new KSelectAction(i18n("Quiz Mode"), 0, actionCollection(), "selectQuizMode");
  QStringList quizModeItems;
  quizModeItems << i18n("Flash Cards") << i18n("Random Order Quiz") << i18n("Ordered Quiz");
  quizModeAction->setItems(quizModeItems);
  connect(quizModeAction, SIGNAL(activated(int)), this, SLOT(changeQuizMode(int)));

  showAnswerLengthAction = new KSelectAction(i18n("Show Answer For"), 0, actionCollection(), "showAnswerLength");
  QStringList showAnswerItems;
  showAnswerItems << i18n("1 Second") << i18n("2 Seconds") << i18n("3 Seconds") << i18n("4 Seconds") << i18n("5 Seconds");
  showAnswerLengthAction->setItems(showAnswerItems);
  connect(showAnswerLengthAction, SIGNAL(activated(int)), this, SLOT(changeShowAnswerLength(int)));

  reverseFrontBackAction = new KToggleAction(i18n("Reverse Front && Back"), 0, actionCollection(), "reverseFrontBack");

  createGUI();

  disableCutCopy();
  disablePaste();
}

void FlashKard::setupLayout()
{
  setAutoSaveSettings();
  data = new DataWidget(this, "data");

  connect(data, SIGNAL(dataChanged()), this, SLOT(dataChanged()));
  connect(data, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
  connect(data, SIGNAL(lineEditFocusIn(KLineEdit *)), this, SLOT(enablePaste(KLineEdit *)));
  connect(data, SIGNAL(lineEditFocusOut()), this, SLOT(disablePaste()));

  showData();
}

void FlashKard::processArgs()
{
  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
  QStringList files;

  for(int i = 0; i < args->count(); i++)
    files.append(args->arg(i));

  fileOpen(files);
}

void FlashKard::readConfig()
{
  KConfig *config = KGlobal::config();
  {
    KConfigGroupSaver saver(config, "Settings");
    if(quizModeAction) {
      int mode = config->readNumEntry("QuizMode", 0);
      quizModeAction->setCurrentItem(mode);
      changeQuizMode(mode);
    }
    if(showAnswerLengthAction) {
      int length = config->readNumEntry("ShowAnswerLength", 2);
      showAnswerLengthAction->setCurrentItem(length - 1);
    }
    if(reverseFrontBackAction) {
      bool checked = config->readBoolEntry("FrontBackReversed", false);
      reverseFrontBackAction->setChecked(checked);
    }
  }
}

void FlashKard::saveConfig()
{
  KConfig *config = KGlobal::config();
  {
    KConfigGroupSaver saver(config, "Settings");
    if(quizModeAction)
      config->writeEntry("QuizMode", quizModeAction->currentItem());
    if(showAnswerLengthAction)
      config->writeEntry("ShowAnswerLength", showAnswerLengthAction->currentItem() + 1);
    if(reverseFrontBackAction)
      config->writeEntry("FrontBackReversed", reverseFrontBackAction->isChecked());
  }
}

bool FlashKard::saveChangesPrompt()
{
  if(changed) {
    const QString message = i18n("You have made changes to the current deck since saving.\n"
				 "Do you want to save your changes?");
    int action = KMessageBox::warningYesNoCancel(this, message);
    switch(action) {
    case KMessageBox::Yes:
      return fileSave();
      break;
    case KMessageBox::No:
      return true;
      break;
    case KMessageBox::Cancel:
      return false;
      break;
    default:
      return false;
      break;
    }
  }
  else
    return true;
}

void FlashKard::dataCurrent()
{
  QFileInfo fileInfo(fileName);
  setCaption(fileInfo.fileName(), false);
  changed = false;
}

bool FlashKard::queryClose()
{
  if(saveChangesPrompt()) {
    saveConfig();
    return true;
  }
  else
    return false;
}

////////////////////////////////////////////////////////////////////////////////
// private slots
////////////////////////////////////////////////////////////////////////////////

// file menu

void FlashKard::fileNew()
{
  if(saveChangesPrompt()) {
    data->clear();
    showData();

    fileName = QString::null;
    dataCurrent();
  }
}

void FlashKard::fileOpen()
{
  if(saveChangesPrompt()) {
    QStringList files = KFileDialog::getOpenFileNames(QString::null, fileMask, this, i18n("Open Decks"));
    fileOpen(files);
  }
}

void FlashKard::fileOpen(const QStringList &files)
{
  if(files.size() > 0) {
    data->clear();
    CardList cardList;
    for(QStringList::ConstIterator fileIt = files.begin(); fileIt != files.end(); fileIt++) {
      KEduVocDataItemList dataList = KEduVocData::parse(*fileIt);
      for(KEduVocDataItemList::Iterator dataIt = dataList.begin(); dataIt != dataList.end(); dataIt++) {
	Card card((*dataIt).originalText(), (*dataIt).translatedText());
	cardList.append(card);
      }
    }
    
    data->loadCards(cardList);
    showData();
    
    if(files.count() == 1)
      fileName = files.first();
    else
      fileName = QString::null;
    
    dataCurrent();
  }
}

bool FlashKard::fileSave()
{
  QFileInfo fileInfo(fileName);

  if(!(fileInfo.fileName()).isEmpty()) {
    QFileInfo dirInfo(fileInfo.dirPath());

    if( (fileInfo.isFile() && fileInfo.isWritable()) || (!fileInfo.exists() && dirInfo.isWritable()) ) {
      QFile output(fileName);
      XMLWriter handler(&output);

      CardList cards = data->cardList();
      for(CardList::ConstIterator it = cards.begin(); it != cards.end(); it++)
	handler.addItem((*it).front(), (*it).back());

      setCaption(fileInfo.fileName(), false);
      dataCurrent();
      return true;
    }
    else {
      KMessageBox::sorry(this, i18n("Could not write to ") + fileInfo.fileName(), i18n("FlashKard"));
      return false;
    }
  }
  else
    return fileSaveAs();
}

bool FlashKard::fileSaveAs()
{
  fileName = KFileDialog::getSaveFileName(QString::null, fileMask, this, QString::null).simplifyWhiteSpace();
  if(!fileName.isEmpty()) {
    if(!fileName.endsWith(fileExtension))
      fileName.append("." + fileExtension);

    return fileSave();
  }
  else
    return false;
}

void FlashKard::quit()
{
    close();
}

// edit menu

void FlashKard::cut()
{
  if(data && data->isVisible())
    data->cut();
  else if(quiz && quiz->isVisible())
    quiz->cut();
}

void FlashKard::copy()
{
  if(data && data->isVisible())
    data->copy();
  else if(quiz && quiz->isVisible())
    quiz->copy();
}

void FlashKard::paste()
{
  if(focusedLineEdit)
    focusedLineEdit->paste();
}

void FlashKard::enableCutCopy()
{
  if(cutAction && copyAction) {
    cutAction->setEnabled(true);
    copyAction->setEnabled(true);
  }
}

void FlashKard::disableCutCopy()
{
  if(cutAction && copyAction) {
    cutAction->setEnabled(false);
    copyAction->setEnabled(false);
  }
}

void FlashKard::enablePaste(KLineEdit *lineEdit)
{
  if(lineEdit && pasteAction) {
    focusedLineEdit = lineEdit;
    pasteAction->setEnabled(true);
  }
}

void FlashKard::disablePaste()
{
  if(pasteAction) {
    focusedLineEdit = 0;
    pasteAction->setEnabled(false);
  }
}

void FlashKard::showData()
{
  statusBar()->hide();

  showQuizAction->setEnabled(true);
  showDataAction->setEnabled(false);

  if(quiz)
    quiz->hide();

  data->show();
  setCentralWidget(data);
}

void FlashKard::showQuiz()
{
  CardList list = data->cardList();
  if(!list.isEmpty()) {
    if(quiz) {

      if(showAnswerLengthAction)
	quiz->setShowAnswerLength(showAnswerLengthAction->currentItem() + 1);

      statusBar()->show();

      showQuizAction->setEnabled(false);
      showDataAction->setEnabled(true);

      quiz->setCardList(list);

      data->hide();
      quiz->show();
      setCentralWidget(quiz);
      quiz->getCard(randomQuiz);
    }
  }
  else
    KMessageBox::sorry( this, i18n("You don't have any cards defined."), i18n("FlashKard"));
}

void FlashKard::changeQuizMode(int id)
{
  bool visible = false;

  if(quiz) {
    if(quiz->isVisible())
      visible = true;
    delete(quiz);
  }

  switch(id) {
  case 0: // flash cards
    quiz = new FlashCardsWidget(statusBar(), this);
    randomQuiz = true;
    break;
  case 1: // random quiz
    quiz = new GuessWidget(statusBar(), true, this);
    randomQuiz = true;
    break;
  case 2: // ordered quiz
    quiz = new GuessWidget(statusBar(), false, this);
    randomQuiz = false;
    break;
  default: // none of the above
    quiz = 0;
    return;
    break;
  }

  connect(quiz, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
  connect(quiz, SIGNAL(lineEditFocusIn(KLineEdit *)), this, SLOT(enablePaste(KLineEdit *)));

  quiz->setFrontBackReversed(reverseFrontBackAction->isChecked());
  connect(reverseFrontBackAction, SIGNAL(toggled(bool)), quiz, SLOT(setFrontBackReversed(bool)));

  if(visible)
    showQuiz();
  else
    showData();
}

void FlashKard::changeShowAnswerLength(int id)
{
  if(quiz)
    quiz->setShowAnswerLength(id + 1);
}
