/*
Tiptop
Copyright (C) 2011 Leonid Nekin: nekin@narod.ru

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, version 3.

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, see <http://www.gnu.org/licenses/>.
*/

#include "mytextedit.h"
#define MAXPENALTY 3


MyTextEdit::MyTextEdit(QWidget * parent): QTextEdit(parent) {
    mode = false;
    wasSpace = false;
    setAcceptRichText(false);
    editColor = Qt::black;
    eraserColor = Qt::white;
    setCursorWidth(2);
#ifdef Q_WS_WIN
/*
    soundFile.setFileName(":/sounds/try_again.wav");
    audio = 0;
    format.setFrequency(44100);
    format.setChannels(1);
    format.setSampleSize(16);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::SignedInt);
*/
#else
    player = 0;
    soundFile.setFileName(":/sounds/try_again.wav");
#endif
}

MyTextEdit::~MyTextEdit() {
}

//=========================================================================

void MyTextEdit::keyPressEvent(QKeyEvent *event) {
  
//std::cout << " event" << std::endl;

  //if (event->key() == Qt::Key_Escape) {
  //  setMode(!mode);
  //}
  //else

  if (mode) {
    RightOrWrong(event->text(), event->key());
  }

  else {  
    QTextEdit::keyPressEvent(event);
  }  
}

//==================================================================

void MyTextEdit::inputMethodEvent(QInputMethodEvent *event) {
  if (mode) {
    RightOrWrong(event->commitString(), -1);
  }
  else {
    QTextEdit::inputMethodEvent(event);
  }
}

//==================================================================

void MyTextEdit::RightOrWrong(const QString & s, int k) {
  QTextCursor cursor = textCursor();
  if(cursor.atEnd()) return;
  QChar c = document()->characterAt(cursor.position());
  unsigned short cu = c.unicode();

  //std::cout << " c=" << cu << " s=" << ((s.size() > 0) ? s[0].unicode() : -1) << " k=" << k << std::endl;

  // if the right key is pressed
  if (s == QString(c)
    || (cu==8232 && k==16777220)
    || (cu==8233 && k==16777220)
    || (cu==182  && k==16777220)
    || (cu==160  && k==32)
    ) {
    cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
    QTextCharFormat format;
    format.setForeground(eraserColor);
    cursor.mergeCharFormat(format);
    cursor.clearSelection();
    unsigned short chun = (document()->characterAt(cursor.position())).unicode();
    if (c.unicode()==182 && (chun==8232 || chun==8233)) cursor.movePosition(QTextCursor::NextCharacter);
    setTextCursor(cursor);

    if (c.unicode() == 32) {
      if (!wasSpace) penalty = (penalty < MAXPENALTY) ? penalty+1 : penalty;
      else wasSpace = true;
    }
    else wasSpace = false;

    if (count_added > 0) {
      --count_added;
      ++n_added_typed;
    }
    else ++n_typed;
    emit entered();
  }

  // if the wrong key is pressed
  else if (s.size() != 0 && !cursor.atEnd()) {
    playSound();
    int pos = cursor.position();

    while (!cursor.atBlockStart()) {
      cursor.movePosition(QTextCursor::Left);
      unsigned short chun = (document()->characterAt(cursor.position())).unicode();
      if (chun == 32 || chun == 9 || chun == 8232    || chun == 8233) {
        cursor.movePosition(QTextCursor::Right);
        break;
      }
    }

    cursor.setPosition(pos, QTextCursor::KeepAnchor);
    while (!cursor.atBlockEnd()) {
      unsigned short chun = (document()->characterAt(cursor.position())).unicode();
      if (chun == 32 || chun == 9 || chun == 8232     || chun == 8233) {
        break;
      }
      cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
    }

    QTextDocumentFragment frg = cursor.selection();
    int frg_size_1 = frg.toPlainText().size() + 1;
    cursor.clearSelection();
    if (!frg.isEmpty()) {
      for (int i = 0; i < penalty; ++i) {
        cursor.insertText(" ");
        cursor.insertFragment(frg);
        n_added += frg_size_1;
        count_added += frg_size_1;
      }
      penalty = 0;

      cursor.setPosition(pos, QTextCursor::KeepAnchor);
      QTextCharFormat format;
      format.setForeground(editColor);
      cursor.mergeCharFormat(format);

      //while (cursor.position() > pos) {
      //  QTextCharFormat format = cursor.charFormat();
      //  cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
      //  format.setForeground(QBrush(QColor("black")));
      //  cursor.setCharFormat(format);
      //  cursor.clearSelection();
      //}
      setTextCursor(cursor);
    }
    emit entered(s);
  }
  // keep cursor above the last line
  int pos = cursor.position();
  cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, 5);
  setTextCursor(cursor);
  cursor.setPosition(pos);
  setTextCursor(cursor);
}

//==================================================================

void MyTextEdit::Replace(const QString & ini, const QString & fin) {
  int pos;
  QTextCursor cursor = textCursor();
  cursor.movePosition(QTextCursor::Start);
  while ( !(cursor = document()->find(ini, cursor, QTextDocument::FindCaseSensitively)).isNull() ) {
    pos = -1;
    QTextCursor tmp = textCursor();
    if (cursor.position() == tmp.position() + ini.size()) pos = tmp.position();
    cursor.insertText(fin);
    if (pos != -1) {
        tmp.setPosition(pos);
        setTextCursor(tmp);
    }
  }  
}  

//==================================================================

void MyTextEdit::DoReplacements() {
  QTextCursor cursor = textCursor();
  cursor.movePosition(QTextCursor::Start);
  count_para = 0;
  while (1) {
    cursor.movePosition(QTextCursor::EndOfLine);
    if (cursor.atBlockEnd()
      || (document()->characterAt(cursor.position())).unicode() == 8232 ) {
      cursor.insertText(QChar(182));
      ++count_para;
    }
    if (cursor.atEnd()) break;
    cursor.movePosition(QTextCursor::NextCharacter);
  }
  Replace( QString(QChar(182)).append(QChar(182)), QChar(182) );
  Replace( QChar(9), " ");
  Replace( QString("     "), QString(" ") );
  Replace( QString("    "), QString(" ") );
  Replace( QString("   "), QString(" ") );
  Replace( QString("  "), QString(" ") );
  Replace( QString(" ").append(QChar(182)), QChar(182) );
  
  //Replace( QString(QChar(171)).append(" "), "\"" );
  //Replace( QString(" ").append(QChar(187)), "\"" );
  //Replace( QString(" ").append("!"), "!" );
  //Replace( QString(" ").append("?"), "?" );
  //Replace( QString(" ").append(":"), ":" );
  //Replace( QString(" ").append(";"), ";" );

  Replace( QChar(171), "\"");
  Replace( QChar(187), "\"");
  Replace( QChar(8220), "\"");
  Replace( QChar(8221), "\"");
  Replace( QChar(8222), "\"");

  Replace( QChar(8216), "'");
  Replace( QChar(8217), "'");
  Replace( QChar(8218), "'");
  Replace( QChar(8249), "'");
  Replace( QChar(8250), "'");
  
  Replace( QChar(8210), "-");
  Replace( QChar(8211), "-");
  Replace( QChar(8212), "-");
  Replace( QChar(8213), "-");
  Replace( QChar(8222), "-");
  
  Replace( QChar(8230), "...");

  cursor = textCursor();
  int ich = document()->characterAt(cursor.position()).unicode();
  if (ich == 8232 || ich == 8233) {
    cursor.movePosition(QTextCursor::Left);
    setTextCursor(cursor);
  }
}

//==================================================================

void MyTextEdit::setMode(bool mode_ini) {
  mode = mode_ini;
  if (mode) {
    penalty = MAXPENALTY;
    DoReplacements();
    QTextCursor cr = textCursor();
    cr.clearSelection();
    setTextCursor(cr);
    n_total = document()->characterCount() - count_para;
    n_typed = 0;
    n_added = 0;
    n_added_typed = 0;
    count_added = 0;
  }
  else {
    Replace( QChar(182), QString("") );
  }

  // keep cursor above the last line

  QTextCursor cursor = textCursor();
  int pos = cursor.position();
  cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, 5);
  setTextCursor(cursor);
  cursor.setPosition(pos);
  setTextCursor(cursor);

  emit entered();
}

//==================================================================
#ifdef Q_WS_WIN
void MyTextEdit::playSound() {
  const QStringList args = QCoreApplication::arguments();
  QSound::play(QFileInfo(args.at(0)).canonicalPath() + "/try_again.wav");
}

/*
void MyTextEdit::playSound() {

  if (audio != 0 || !sound) return;
  QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
  if (!info.isFormatSupported(format)) return;

  audio = new QAudioOutput(info, format, this);
  connect(audio,SIGNAL(stateChanged(QAudio::State)),this, SLOT(finishedPlaying(QAudio::State)));
  soundFile.open(QIODevice::ReadOnly);
  audio->start(&soundFile);
}

//==================================================================

void MyTextEdit::finishedPlaying(QAudio::State state)
   {
     if (state == QAudio::IdleState) {
       audio->stop();
       soundFile.close();
       delete audio;
       audio = 0;
     }
}
*/
#else

//==================================================================

void MyTextEdit::playSound() {
  if (player != 0) {
    if (player->state() == 1) {
      disconnect(player, SIGNAL(finished()), player, SLOT(stop()));
      delete player;
      delete auOut;
      player = 0;
    }
  }

  if (player == 0) {
    auOut = new Phonon::AudioOutput(Phonon::NotificationCategory, this);
    player = new Phonon::MediaObject(this);
    Phonon::createPath(player, auOut);
    player->setCurrentSource(Phonon::MediaSource(&soundFile));
    connect(player, SIGNAL(finished()), player, SLOT(stop()));
    player->play();
  }
}
#endif
