/***************************************************************************
    copyright            : (C) 2005-2006 by Robby Stephenson
    email                : robby@periapsis.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of version 2 of the GNU General Public License as  *
 *   published by the Free Software Foundation;                            *
 *                                                                         *
 ***************************************************************************/

#include "gcfilmsimporter.h"
#include "../collections/videocollection.h"
#include "../latin1literal.h"
#include "../tellico_utils.h"
#include "../imagefactory.h"
#include "../borrower.h"
#include "../progressmanager.h"
#include "xslthandler.h"
#include "tellicoimporter.h"

#include <kapplication.h>
#include <kstandarddirs.h>

#include <tqtextcodec.h>

#define CHECKLIMITS(n) if(values.count() <= n) continue

using Tellico::Import::GCfilmsImporter;

GCfilmsImporter::GCfilmsImporter(const KURL& url_) : TextImporter(url_), m_coll(0), m_cancelled(false) {
}

bool GCfilmsImporter::canImport(int type) const {
  return type == Data::Collection::Video
      || type == Data::Collection::Book
      || type == Data::Collection::Album
      || type == Data::Collection::Game
      || type == Data::Collection::Wine
      || type == Data::Collection::Coin;
}

Tellico::Data::CollPtr GCfilmsImporter::collection() {
  if(m_coll) {
    return m_coll;
  }

  ProgressItem& item = ProgressManager::self()->newProgressItem(this, progressLabel(), true);
  item.setTotalSteps(100);
  connect(&item, TQT_SIGNAL(signalCancelled(ProgressItem*)), TQT_SLOT(slotCancel()));
  ProgressItem::Done done(this);

  TQString str = text();
  TQTextIStream t(&str);
  TQString line = t.readLine();
  if(line.startsWith(TQString::fromLatin1("GCfilms"))) {
    readGCfilms(str);
  } else {
    // need to reparse the string if it's in utf-8
    if(line.lower().find(TQString::fromLatin1("utf-8")) > 0) {
      str = TQString::fromUtf8(str.local8Bit());
    }
    readGCstar(str);
  }
  return m_coll;
}

void GCfilmsImporter::readGCfilms(const TQString& text_) {
  m_coll = new Data::VideoCollection(true);
  bool hasURL = false;
  if(m_coll->hasField(TQString::fromLatin1("url"))) {
    hasURL = m_coll->fieldByName(TQString::fromLatin1("url"))->type() == Data::Field::URL;
  } else {
    Data::FieldPtr field = new Data::Field(TQString::fromLatin1("url"), i18n("URL"), Data::Field::URL);
    field->setCategory(i18n("General"));
    m_coll->addField(field);
    hasURL = true;
  }

  bool convertUTF8 = false;
  TQMap<TQString, Data::BorrowerPtr> borrowers;
  const TQRegExp rx(TQString::fromLatin1("\\s*,\\s*"));
  TQRegExp year(TQString::fromLatin1("\\d{4}"));
  TQRegExp runTimeHr(TQString::fromLatin1("(\\d+)\\s?hr?"));
  TQRegExp runTimeMin(TQString::fromLatin1("(\\d+)\\s?mi?n?"));

  bool gotFirstLine = false;
  uint total = 0;

  TQTextIStream t(&text_);

  const uint length = text_.length();
  const uint stepSize = TQMAX(s_stepSize, length/100);
  const bool showProgress = options() & ImportProgress;

  ProgressManager::self()->setTotalSteps(this, length);
  uint j = 0;
  for(TQString line = t.readLine(); !m_cancelled && !line.isNull(); line = t.readLine(), j += line.length()) {
    // string was wrongly converted
    TQStringList values = TQStringList::split('|', (convertUTF8 ? TQString::fromUtf8(line.local8Bit()) : line), true);
    if(values.empty()) {
      continue;
    }

    if(!gotFirstLine) {
      if(values[0] != Latin1Literal("GCfilms")) {
        setStatusMessage(i18n("<qt>The file is not a valid GCstar data file.</qt>"));
        m_coll = 0;
        return;
      }
      total = Tellico::toUInt(values[1], 0)+1; // number of lines really
      if(values.size() > 2 && values[2] == Latin1Literal("UTF8")) {
        // if locale encoding isn't utf8, need to do a reconversion
        TQTextCodec* codec = TQTextCodec::codecForLocale();
        if(TQCString(codec->name()).find("utf-8", 0, false) == -1) {
          convertUTF8 = true;
        }
      }
      gotFirstLine = true;
      continue;
    }

    bool ok;

    Data::EntryPtr entry = new Data::Entry(m_coll);
    entry->setId(Tellico::toUInt(values[0], &ok));
    entry->setField(TQString::fromLatin1("title"), values[1]);
    if(year.search(values[2]) > -1) {
      entry->setField(TQString::fromLatin1("year"), year.cap());
    }

    uint time = 0;
    if(runTimeHr.search(values[3]) > -1) {
      time = Tellico::toUInt(runTimeHr.cap(1), &ok) * 60;
    }
    if(runTimeMin.search(values[3]) > -1) {
      time += Tellico::toUInt(runTimeMin.cap(1), &ok);
    }
    if(time > 0) {
      entry->setField(TQString::fromLatin1("running-time"),  TQString::number(time));
    }

    entry->setField(TQString::fromLatin1("director"),      splitJoin(rx, values[4]));
    entry->setField(TQString::fromLatin1("nationality"),   splitJoin(rx, values[5]));
    entry->setField(TQString::fromLatin1("genre"),         splitJoin(rx, values[6]));
    KURL u = KURL::fromPathOrURL(values[7]);
    if(!u.isEmpty()) {
      TQString id = ImageFactory::addImage(u, true /* quiet */);
      if(!id.isEmpty()) {
        entry->setField(TQString::fromLatin1("cover"), id);
      }
    }
    entry->setField(TQString::fromLatin1("cast"),  splitJoin(rx, values[8]));
    // values[9] is the original title
    entry->setField(TQString::fromLatin1("plot"),  values[10]);
    if(hasURL) {
      entry->setField(TQString::fromLatin1("url"), values[11]);
    }

    CHECKLIMITS(12);

    // values[12] is whether the film has been viewed or not
    entry->setField(TQString::fromLatin1("medium"), values[13]);
    // values[14] is number of DVDS?
    // values[15] is place?
    // gcfilms's ratings go 0-10, just divide by two
    entry->setField(TQString::fromLatin1("rating"), TQString::number(int(Tellico::toUInt(values[16], &ok)/2)));
    entry->setField(TQString::fromLatin1("comments"), values[17]);

    CHECKLIMITS(18);

    TQStringList s = TQStringList::split(',', values[18]);
    TQStringList tracks, langs;
    for(TQStringList::ConstIterator it = s.begin(); it != s.end(); ++it) {
      langs << (*it).section(';', 0, 0);
      tracks << (*it).section(';', 1, 1);
    }
    entry->setField(TQString::fromLatin1("language"),    langs.join(TQString::fromLatin1("; ")));
    entry->setField(TQString::fromLatin1("audio-track"), tracks.join(TQString::fromLatin1("; ")));

    entry->setField(TQString::fromLatin1("subtitle"), splitJoin(rx, values[19]));

    CHECKLIMITS(20);

    // values[20] is borrower name
    if(!values[20].isEmpty()) {
      TQString tmp = values[20];
      Data::BorrowerPtr b = borrowers[tmp];
      if(!b) {
        b = new Data::Borrower(tmp, TQString());
        borrowers.insert(tmp, b);
      }
      // values[21] is loan date
      if(!values[21].isEmpty()) {
        tmp = values[21]; // assume date is dd/mm/yyyy
        int d = Tellico::toUInt(tmp.section('/', 0, 0), &ok);
        int m = Tellico::toUInt(tmp.section('/', 1, 1), &ok);
        int y = Tellico::toUInt(tmp.section('/', 2, 2), &ok);
        b->addLoan(new Data::Loan(entry, TQDate(y, m, d), TQDate(), TQString()));
        entry->setField(TQString::fromLatin1("loaned"), TQString::fromLatin1("true"));
      }
    }
    // values[22] is history ?
    // for certification, only thing we can do is assume default american ratings
    // they're not translated one for one
    CHECKLIMITS(23);

    int age = Tellico::toUInt(values[23], &ok);
    if(age < 2) {
      entry->setField(TQString::fromLatin1("certification"), TQString::fromLatin1("U (USA)"));
    } else if(age < 3) {
      entry->setField(TQString::fromLatin1("certification"), TQString::fromLatin1("G (USA)"));
    } else if(age < 6) {
      entry->setField(TQString::fromLatin1("certification"), TQString::fromLatin1("PG (USA)"));
    } else if(age < 14) {
      entry->setField(TQString::fromLatin1("certification"), TQString::fromLatin1("PG-13 (USA)"));
    } else {
      entry->setField(TQString::fromLatin1("certification"), TQString::fromLatin1("R (USA)"));
    }

    m_coll->addEntries(entry);

    if(showProgress && j%stepSize == 0) {
      ProgressManager::self()->setProgress(this, j);
      kapp->processEvents();
    }
  }

  if(m_cancelled) {
    m_coll = 0;
    return;
  }

  for(TQMap<TQString, Data::BorrowerPtr>::Iterator it = borrowers.begin(); it != borrowers.end(); ++it) {
    if(!it.data()->isEmpty()) {
      m_coll->addBorrower(it.data());
    }
  }
}

void GCfilmsImporter::readGCstar(const TQString& text_) {
  TQString xsltFile = locate("appdata", TQString::fromLatin1("gcstar2tellico.xsl"));
  XSLTHandler handler(xsltFile);
  if(!handler.isValid()) {
    setStatusMessage(i18n("Tellico encountered an error in XSLT processing."));
    return;
  }

  TQString str = handler.applyStylesheet(text_);

  if(str.isEmpty()) {
    setStatusMessage(i18n("<qt>The file is not a valid GCstar data file.</qt>"));
    return;
  }

  Import::TellicoImporter imp(str);
  m_coll = imp.collection();
  setStatusMessage(imp.statusMessage());
}

inline
TQString GCfilmsImporter::splitJoin(const TQRegExp& rx, const TQString& s) {
  return TQStringList::split(rx, s, false).join(TQString::fromLatin1("; "));
}

void GCfilmsImporter::slotCancel() {
  m_cancelled = true;
}

#undef CHECKLIMITS
#include "gcfilmsimporter.moc"
