/***************************************************************************
    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 "upcvalidator.h"
#include "isbnvalidator.h"
#include "tellico_debug.h"

#include <kmdcodec.h>

using Tellico::UPCValidator;

UPCValidator::UPCValidator(TQObject* parent_, const char* name_/*=0*/)
    : TQValidator(parent_, name_), m_checkISBN(false) {
}

TQValidator::State UPCValidator::validate(TQString& input_, int& pos_) const {
  // check if it's a cuecat first
  State catState = CueCat::decode(input_);
  if(catState == Acceptable) {
    pos_ = input_.length();
    return catState;
  }

  // no spaces allowed
  if(input_.contains(' ')) {
    return TQValidator::Invalid;
  }

  // no real checking, just if starts with 978, use isbnvalidator
  const uint len = input_.length();
  if(len < 10) {
    m_isbn = false;
  }

  if(!m_checkISBN || (!m_isbn && len < 13)) {
    return TQValidator::Intermediate;
  }

  // once it gets converted to an ISBN, remember that, and use it for later
  if(input_.startsWith(TQString::fromLatin1("978")) || input_.startsWith(TQString::fromLatin1("979"))) {
    ISBNValidator val(0);
    TQValidator::State s = val.validate(input_, pos_);
    if(s == TQValidator::Acceptable) {
      m_isbn = true;
      // bad hack
      UPCValidator* that = const_cast<UPCValidator*>(this);
      that->signalISBN();
    }
    return s;
  }

  return TQValidator::Intermediate;
}

void UPCValidator::fixup(TQString& input_) const {
  if(input_.isEmpty()) {
    return;
  }
  input_ = input_.stripWhiteSpace();

  int pos = input_.find(' ');
  if(pos > -1) {
    input_ = input_.left(pos);
  }

  if(!m_checkISBN) {
    return;
  }

  const uint len = input_.length();
  if(len > 12 && (input_.startsWith(TQString::fromLatin1("978")) || input_.startsWith(TQString::fromLatin1("979")))) {
    TQString s = input_;
    ISBNValidator val(0);
    int p = 0;
    int state = val.validate(s, p);
    if(state == TQValidator::Acceptable) {
      // bad hack
      UPCValidator* that = const_cast<UPCValidator*>(this);
      that->signalISBN();
      input_ = s;
    }
  }
}

TQValidator::State Tellico::CueCat::decode(TQString& input_) {
  if(input_.length() < 3) {
    return TQValidator::Intermediate;
  }
 if(!input_.startsWith(TQString::fromLatin1(".C3"))) { // all cuecat codes start with .C3
    return TQValidator::Invalid;
  }
  const int periods = input_.contains('.');
  if(periods < 4) {
    return TQValidator::Intermediate; // not enough yet
  } else if(periods > 4) {
    return TQValidator::Invalid;
  }

  // ok, let's have a go, take the third token
  TQString code = TQStringList::split('.', input_)[2];
  while(code.length() % 4 > 0) {
    code += '=';
  }

  for(uint i = 0; i < code.length(); ++i) {
    if(code[i] >= 'A' && code[i] <= 'Z') {
      code.replace(i, 1, code[i].lower());
    } else if(code[i] >= 'a' && code[i] <= 'z') {
      code.replace(i, 1, code[i].upper());
    }
  }

  code = TQString::fromLatin1(KCodecs::base64Decode(TQCString(code.latin1())));

  for(uint i = 0; i < code.length(); ++i) {
    char c = code[i].latin1() ^ 'C';
    code.replace(i, 1, c);
  }

  input_ = code;
  return TQValidator::Acceptable;
}

#include "upcvalidator.moc"
