/***************************************************************************
                          mymoneystatement.cpp
                          -------------------
    begin                : Mon Aug 30 2004
    copyright            : (C) 2000-2004 by Michael Edwardes
    email                : mte@users.sourceforge.net
                           Javier Campos Morales <javi_c@users.sourceforge.net>
                           Felix Rodriguez <frodriguez@users.sourceforge.net>
                           John C <thetacoturtle@users.sourceforge.net>
                           Thomas Baumgart <ipwizard@users.sourceforge.net>
                           Kevin Tambascio <ktambascio@users.sourceforge.net>
                           Ace Jones <acejones@users.sourceforge.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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

// ----------------------------------------------------------------------------
// TQt Includes

#include <tqdom.h>
#include <tqstringlist.h>
#include <tqfile.h>
#include <tqtextstream.h>

// ----------------------------------------------------------------------------
// Project Includes

#include "mymoneystatement.h"

const TQStringList kAccountTypeTxt = TQStringList::split(",","none,checkings,savings,investment,creditcard,invalid");
const TQStringList kActionText = TQStringList::split(",","none,buy,sell,reinvestdividend,cashdividend,add,remove,stocksplit,fees,interest,invalid");

void MyMoneyStatement::write(TQDomElement& _root,TQDomDocument* _doc) const
{
  TQDomElement e = _doc->createElement("STATEMENT");
  _root.appendChild(e);

  e.setAttribute("version","1.1");
  e.setAttribute("accountname", m_strAccountName);
  e.setAttribute("accountnumber", m_strAccountNumber);
  e.setAttribute("routingnumber", m_strRoutingNumber);
  e.setAttribute("currency", m_strCurrency);
  e.setAttribute("begindate", m_dateBegin.toString(TQt::ISODate));
  e.setAttribute("enddate", m_dateEnd.toString(TQt::ISODate));
  e.setAttribute("closingbalance", m_closingBalance.toString());
  e.setAttribute("type", kAccountTypeTxt[m_eType]);
  e.setAttribute("accountid", m_accountId);
  e.setAttribute("skipCategoryMatching", m_skipCategoryMatching);

  // iterate over transactions, and add each one
  TQValueList<Transaction>::const_iterator it_t = m_listTransactions.begin();
  while ( it_t != m_listTransactions.end() )
  {
    TQDomElement p = _doc->createElement("TRANSACTION");
    p.setAttribute("dateposted", (*it_t).m_datePosted.toString(TQt::ISODate));
    p.setAttribute("payee", (*it_t).m_strPayee);
    p.setAttribute("memo", (*it_t).m_strMemo);
    p.setAttribute("number", (*it_t).m_strNumber);
    p.setAttribute("amount", (*it_t).m_amount.toString());
    p.setAttribute("bankid", (*it_t).m_strBankID);
    p.setAttribute("reconcile", (*it_t).m_reconcile);
    p.setAttribute("action", kActionText[(*it_t).m_eAction]);

    if (m_eType == etInvestment)
    {
      p.setAttribute("shares", (*it_t).m_shares.toString());
      p.setAttribute("security", (*it_t).m_strSecurity);
      p.setAttribute("brokerageaccount", (*it_t).m_strBrokerageAccount);
    }

    // add all the splits we know of (might be empty)
    TQValueList<Split>::const_iterator it_s;
    for(it_s = (*it_t).m_listSplits.begin(); it_s != (*it_t).m_listSplits.end(); ++it_s) {
      TQDomElement split = _doc->createElement("SPLIT");
      split.setAttribute("accountid", (*it_s).m_accountId);
      split.setAttribute("amount", (*it_s).m_amount.toString());
      split.setAttribute("reconcile", (*it_s).m_reconcile);
      split.setAttribute("category", (*it_s).m_strCategoryName);
      split.setAttribute("memo", (*it_s).m_strMemo);
      split.setAttribute("reconcile", (*it_s).m_reconcile);
      p.appendChild(split);
    }

    e.appendChild(p);

    ++it_t;
  }

  // iterate over prices, and add each one
  TQValueList<Price>::const_iterator it_p = m_listPrices.begin();
  while ( it_p != m_listPrices.end() )
  {
    TQDomElement p = _doc->createElement("PRICE");
    p.setAttribute("dateposted", (*it_p).m_date.toString(TQt::ISODate));
    p.setAttribute("security", (*it_p).m_strSecurity);
    p.setAttribute("amount", (*it_p).m_amount.toString());

    e.appendChild(p);

    ++it_p;
  }

  // iterate over securities, and add each one
  TQValueList<Security>::const_iterator it_s = m_listSecurities.begin();
  while ( it_s != m_listSecurities.end() )
  {
    TQDomElement p = _doc->createElement("SECURITY");
    p.setAttribute("name", (*it_s).m_strName);
    p.setAttribute("symbol", (*it_s).m_strSymbol);
    p.setAttribute("id", (*it_s).m_strId);

    e.appendChild(p);

    ++it_s;
  }

}

bool MyMoneyStatement::read(const TQDomElement& _e)
{
  bool result = false;

  if ( _e.tagName() == "STATEMENT" )
  {
    result = true;

    m_strAccountName = _e.attribute("accountname");
    m_strAccountNumber = _e.attribute("accountnumber");
    m_strRoutingNumber = _e.attribute("routingnumber");
    m_strCurrency = _e.attribute("currency");
    m_dateBegin = TQDate::fromString(_e.attribute("begindate"),TQt::ISODate);
    m_dateEnd = TQDate::fromString(_e.attribute("enddate"),TQt::ISODate);
    m_closingBalance = MyMoneyMoney(_e.attribute("closingbalance"));
    m_accountId = _e.attribute("accountid");
    m_skipCategoryMatching = !(_e.attribute("skipCategoryMatching").isEmpty());

    int i = kAccountTypeTxt.findIndex(_e.attribute("type",kAccountTypeTxt[1]));
    if ( i != -1 )
      m_eType = static_cast<EType>(i);

    TQDomNode child = _e.firstChild();
    while(!child.isNull() && child.isElement())
    {
      TQDomElement c = child.toElement();

      if ( c.tagName() == "TRANSACTION" )
      {
        MyMoneyStatement::Transaction t;

        t.m_datePosted = TQDate::fromString(c.attribute("dateposted"),TQt::ISODate);
        t.m_amount = MyMoneyMoney(c.attribute("amount"));
        t.m_strMemo = c.attribute("memo");
        t.m_strNumber = c.attribute("number");
        t.m_strPayee = c.attribute("payee");
        t.m_strBankID = c.attribute("bankid");
        t.m_reconcile = static_cast<MyMoneySplit::reconcileFlagE>(c.attribute("reconcile").toInt());
        int i = kActionText.findIndex(c.attribute("action",kActionText[1]));
        if ( i != -1 )
          t.m_eAction = static_cast<Transaction::EAction>(i);

        if (m_eType == etInvestment)
        {
          t.m_shares = MyMoneyMoney(c.attribute("shares"));
          t.m_strSecurity = c.attribute("security");
          t.m_strBrokerageAccount = c.attribute("brokerageaccount");
        }

        // process splits (if any)
        TQDomNode child = c.firstChild();
        while(!child.isNull() && child.isElement()) {
          TQDomElement c = child.toElement();
          if(c.tagName() == "SPLIT") {
            MyMoneyStatement::Split s;
            s.m_accountId = c.attribute("accountid");
            s.m_amount = MyMoneyMoney(c.attribute("amount"));
            s.m_reconcile = static_cast<MyMoneySplit::reconcileFlagE>(c.attribute("reconcile").toInt());
            s.m_strCategoryName = c.attribute("category");
            s.m_strMemo = c.attribute("memo");
            t.m_listSplits += s;
          }
          child = child.nextSibling();
        }
        m_listTransactions += t;
      }
      else if ( c.tagName() == "PRICE" )
      {
        MyMoneyStatement::Price p;

        p.m_date = TQDate::fromString(c.attribute("dateposted"), TQt::ISODate);
        p.m_strSecurity = c.attribute("security");
        p.m_amount = MyMoneyMoney(c.attribute("amount"));

        m_listPrices += p;
      }
      else if ( c.tagName() == "SECURITY" )
      {
        MyMoneyStatement::Security s;

        s.m_strName = c.attribute("name");
        s.m_strSymbol = c.attribute("symbol");
        s.m_strId = c.attribute("id");

        m_listSecurities += s;
      }
      child = child.nextSibling();
    }
  }

  return result;
}

bool MyMoneyStatement::isStatementFile(const TQString& _filename)
{
  // filename is considered a statement file if it contains
  // the tag "<KMYMONEY2-STATEMENT>" in the first 20 lines.
  bool result = false;

  TQFile f( _filename );
  if ( f.open( IO_ReadOnly ) )
  {
    TQTextStream ts( &f );

    int lineCount = 20;
    while ( !ts.atEnd() && !result && lineCount != 0) {
      if ( ts.readLine().contains("<KMYMONEY-STATEMENT>",false) )
        result = true;
      --lineCount;
    }
    f.close();
  }

  return result;
}

void MyMoneyStatement::writeXMLFile( const MyMoneyStatement& _s, const TQString& _filename )
{
  static unsigned filenum = 1;
  TQString filename = _filename;
  if ( filename.isEmpty() ) {
    filename = TQString("statement-%1%2.xml").arg((filenum<10)?"0":"").arg(filenum);
    filenum++;
  }

  TQDomDocument* doc = new TQDomDocument("KMYMONEY-STATEMENT");
  TQ_CHECK_PTR(doc);

  //writeStatementtoXMLDoc(_s,doc);
  TQDomProcessingInstruction instruct = doc->createProcessingInstruction(TQString("xml"), TQString("version=\"1.0\" encoding=\"utf-8\""));
  doc->appendChild(instruct);
  TQDomElement eroot = doc->createElement("KMYMONEY-STATEMENT");
  doc->appendChild(eroot);
  _s.write(eroot,doc);

  TQFile g( filename );
  if(g.open( IO_WriteOnly )) {
    TQTextStream stream(&g);
    stream.setEncoding(TQTextStream::UnicodeUTF8);
    stream << doc->toString();
    g.close();
  }

  delete doc;
}

bool MyMoneyStatement::readXMLFile( MyMoneyStatement& _s, const TQString& _filename )
{
  bool result = false;
  TQFile f( _filename );
  f.open( IO_ReadOnly );
  TQDomDocument* doc = new TQDomDocument;
  if(doc->setContent(&f, false))
  {
    TQDomElement rootElement = doc->documentElement();
    if(!rootElement.isNull())
    {
      TQDomNode child = rootElement.firstChild();
      while(!child.isNull() && child.isElement())
      {
        result = true;
        TQDomElement childElement = child.toElement();
        _s.read(childElement);

        child = child.nextSibling();
      }
    }
  }
  delete doc;

  return result;
}
