/***************************************************************************

                    maintain a document in text format

    -----------------------------------------------------------------------

    begin          : Sat Sep 06 11:00:53 MET 1999

    copyright      : (C) 1999-2001 Ewald Arnold <kvoctrain@ewald-arnold.de>
                     (C) 2001 The KDE-EDU team
                     (C) 2005 Peter Hedlund <peter.hedlund@kdemail.net>

    -----------------------------------------------------------------------

 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 <tdelocale.h>

#include "kvoctrain.h"

#include <tqtextcodec.h>

#include <vector>
#include <algorithm>
using namespace std;

vector<int> getCsvOrderStatic(kvoctrainDoc *doc)
{
  vector<int> csv_order;
  TQStringList lang_order = Prefs::pasteOrder();

  if (!Prefs::useCurrent())
  {
    if (/*lang_order &&*/ lang_order.count() != 0) {
      for (int i = 0; i < (int) lang_order.count(); i++)
      {
        int j = doc->findIdent((lang_order)[i]);
        if (j >= 0)
          csv_order.push_back (j);
        else
          csv_order.push_back (-1);
      }
    }
  }
/*
  for (int i = 0; i < csv_order.size(); i++)
    cout << csv_order[i] << " ";
  cout << endl;
*/

/*  perhaps skip missing ??
  for (int i = csv_order.size()-1; i >= 0; i--)
    if (csv_order[i] == -1)
      csv_order.erase(csv_order.begin() + i);
*/
  // append indices from doc if no order given
  for (int i = 0; i < doc->numLangs(); i++)
    if (::find (csv_order.begin(), csv_order.end(), i) == csv_order.end())
       csv_order.push_back(i);
/*
  if (csv_order.size() > doc->numLangs() )
    csv_order.erase(csv_order.begin() + doc->numLangs(), csv_order.end());
*/

  // remove trailing garbage
  for (int i = csv_order.size()-1; i >= 0; i--) {
    if (csv_order[i] != -1)
      break;
    else
      csv_order.erase(csv_order.begin() + i);
  }

  return csv_order;
}

bool kvoctrainDoc::saveTypeNameCsv (TQTextStream &)
{
 return true;
}


bool kvoctrainDoc::loadTypeNameCsv (TQTextStream &)
{
 return true;
}


bool kvoctrainDoc::saveLessonCsv (TQTextStream &)
{
 return true;
}


bool kvoctrainDoc::loadLessonCsv (TQTextStream &)
{
 return true;
}

bool kvoctrainDoc::saveToCsv (TQTextStream& os, TQString &)
{
  TQString separator = Prefs::separator();

  saveTypeNameCsv (os);
  saveLessonCsv (os);

  int ent_no = 0;
  int ent_percent = (int) vocabulary.size () / 100;
  float f_ent_percent = (int) vocabulary.size () / 100.0;
  emit progressChanged(this, 0);

  os << i18n("! Title:")  << separator << getTitle() << "\n";
  os << i18n("! Author:") << separator << getAuthor() << "\n";

  vector <int> csv_order = getCsvOrderStatic(this);

  vector<kvoctrainExpr>::const_iterator first =  vocabulary.begin ();
  TQString exp;

  os.setCodec(TQTextCodec::codecForName("UTF-8"));
  while (first != vocabulary.end ()) {

    ent_no++;
    if (ent_percent != 0 && (ent_no % ent_percent) == 0 )
      emit progressChanged(this, ent_no / (int) f_ent_percent);

    exp = "";
    // now concat columns according to paste-order
    bool sep = false;
    for (int i = 0; i < (int) csv_order.size(); i++) {
      if (!sep)
        sep = true;
      else
        exp += separator;

      if (csv_order[i] >= 0) {
        if (csv_order[i] == 0)
          exp += (*first).getOriginal();
        else
          exp += (*first).getTranslation(csv_order[i]);
      }
    }

    if (!exp.isEmpty())
      os << exp << "\n";

    first++;
  }

  setModified (false);
  return os.device()->status() == IO_Ok;
}


bool kvoctrainDoc::loadFromCsv (TQTextStream& is)
{
  TQString separator = Prefs::separator();
  TQStringList lang_order = Prefs::pasteOrder();

  langs.clear();
  vocabulary.clear();
  loadTypeNameCsv (is);
  loadLessonCsv (is);

  // autodetect utf8
  // FIXME: provide choice for Latinx?
  is.setCodec(TQTextCodec::codecForName("ISO 8859-1"));
  is.setEncoding(TQTextStream::Latin1);

  int size = is.device()->size ();
  int ln = size / 20 / 100;  // assume each line about 20 chars
  float f_ent_percent = size / 100.0;
  emit progressChanged (this, 0);

  bool utf8_mode = false;
  int lang_num = 0;
  for (int l = 0; !is.eof(); l++) {
    TQString s = is.readLine();

    // autodetect utf8
    if (!utf8_mode) {
      for (int i = 0; !utf8_mode && i < (int) s.length(); ++i) {
        ushort trigger = s[i].unicode();
        if (trigger >= 0x80) {
          int remain = s.length() - i;
          if ((trigger & 0xE0) == 0xC0){         // 110x xxxx
            if (   (remain > 1)
                && (s[i+1].unicode() & 0xC0) == 0x80)
              utf8_mode = true;
          }
          else if ((trigger & 0xF0) == 0xE0) {  // 1110 xxxx
            if (   remain > 2
                && s[i+1].unicode() & 0xC0 == 0x80
                && s[i+2].unicode() & 0xC0 == 0x80)
              utf8_mode = true;
          }
          else if ((trigger & 0xF8) == 0xF0) {   // 1111 0xxx
            if (   remain > 3
                && s[i+1].unicode() & 0xC0 == 0x80
                && s[i+2].unicode() & 0xC0 == 0x80
                && s[i+3].unicode() & 0xC0 == 0x80)
              utf8_mode = true;
          }
          else if ((trigger & 0xFC) == 0xF8) {   // 1111 10xx
            if (   remain > 4
                && s[i+1].unicode() & 0xC0 == 0x80
                && s[i+2].unicode() & 0xC0 == 0x80
                && s[i+3].unicode() & 0xC0 == 0x80
                && s[i+4].unicode() & 0xC0 == 0x80)
              utf8_mode = true;
          }
          else if ((trigger & 0xFE) == 0xFC) {   // 1111 110x
            if (   remain > 5
                && s[i+1].unicode() & 0xC0 == 0x80
                && s[i+2].unicode() & 0xC0 == 0x80
                && s[i+3].unicode() & 0xC0 == 0x80
                && s[i+4].unicode() & 0xC0 == 0x80
                && s[i+5].unicode() & 0xC0 == 0x80)
              utf8_mode = true;
          }
        }
      }

      if (utf8_mode) {
        is.setCodec(TQTextCodec::codecForName("UTF-8"));
        is.setEncoding(TQTextStream::UnicodeUTF8);
        s = TQString::fromUtf8(s.ascii());
      }

    }

    ln--;
    if (ln <= 0) {
      ln = size / 20 / 100;  // assume each line about 20 chars
      emit progressChanged(this, is.device()->at() / (int) f_ent_percent);
    }

    // similar in kva_clip.cpp::slotEditPaste()

    if (!s.stripWhiteSpace().isEmpty()) {
      kvoctrainExpr bucket (s, separator);
      kvoctrainExpr expr;
      // now move columns according to paste-order
      for (int i = 0; i < bucket.numTranslations()+1; i++) {
        lang_num = TQMAX (lang_num, bucket.numTranslations()+1);
        if (i == 0)
          expr.setOriginal(bucket.getOriginal());
        else {
          TQString ts = bucket.getTranslation(i);
          expr.setTranslation(i, ts);
        }
      }
      appendEntry (&expr);
    }
  }

  for (int j = 0; j < lang_num; j++) {
    if (j < (int) lang_order.count() ) {
      langs.push_back((lang_order)[j]);
    }
    else {
      if (j == 0)
        langs.push_back("org");
      else {
        TQString s;
        s.setNum(j);
        s.insert(0, "trans");
        langs.push_back(s);
      }
    }
  }
  setModified (false);
  return is.device()->status() == IO_Ok;
}


void kvoctrainDoc::errorCsv (int /*line*/, const TQString &text )
{
   unknown_elem = true;
   TQApplication::setOverrideCursor( arrowCursor, true );
   TQString s = kapp->makeStdCaption(i18n("Error in csv file"));
   TQString msg = text;
   KMessageBox::error( 0, msg, s);
   TQApplication::restoreOverrideCursor();
}
