/***************************************************************************
                          listtable.cpp
                         -------------------
    begin                : Sat 28 jun 2008
    copyright            : (C) 2004-2005 by Ace Jones
                               2008 by Alvaro Soliverez
    email                :  acejones@users.sourceforge.net
                            asoliverez@gmail.com
 ***************************************************************************/

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

// ----------------------------------------------------------------------------
// QT Includes
#include <tqvaluelist.h>
#include <tqfile.h>
#include <tqtextstream.h>

// ----------------------------------------------------------------------------
// KDE Includes
// This is just needed for i18n().  Once I figure out how to handle i18n
// without using this macro directly, I'll be freed of KDE dependency.

#include <tdelocale.h>
#include <kdebug.h>

// ----------------------------------------------------------------------------
// Project Includes
#include "../mymoney/mymoneyfile.h"
#include "../mymoney/mymoneyreport.h"
#include "../mymoney/mymoneyexception.h"
#include "../kmymoneyutils.h"
#include "../kmymoneyglobalsettings.h"
#include "reportdebug.h"
#include "listtable.h"

namespace reports {

  TQStringList ListTable::TableRow::m_sortCriteria;

  // ****************************************************************************
  //
  // Group Iterator
  //
  // ****************************************************************************

  class GroupIterator
  {
    public:
      GroupIterator ( const TQString& _group, const TQString& _subtotal, unsigned _depth ) : m_depth ( _depth ), m_groupField ( _group ), m_subtotalField ( _subtotal ) {}
      GroupIterator ( void ) {}
      void update ( const ListTable::TableRow& _row )
      {
        m_previousGroup = m_currentGroup;
        m_currentGroup = _row[m_groupField];
        if ( isSubtotal() )
        {
          m_previousSubtotal = m_currentSubtotal;
          m_currentSubtotal = MyMoneyMoney();
        }
        m_currentSubtotal += _row[m_subtotalField];
      }

      bool isNewHeader ( void ) const { return ( m_currentGroup != m_previousGroup ); }
      bool isSubtotal ( void ) const { return ( m_currentGroup != m_previousGroup ) && ( !m_previousGroup.isEmpty() ); }
      const MyMoneyMoney& subtotal ( void ) const { return m_previousSubtotal; }
      const MyMoneyMoney& currenttotal ( void ) const { return m_currentSubtotal; }
      unsigned depth ( void ) const { return m_depth; }
      const TQString& name ( void ) const { return m_currentGroup; }
      const TQString& oldName ( void ) const { return m_previousGroup; }
      const TQString& groupField ( void ) const { return m_groupField; }
      const TQString& subtotalField ( void ) const { return m_subtotalField; }
      // ***DV*** HACK make the currentGroup test different but look the same
      void force ( void ) { m_currentGroup += " "; }
    private:
      MyMoneyMoney m_currentSubtotal;
      MyMoneyMoney m_previousSubtotal;
      unsigned m_depth;
      TQString m_currentGroup;
      TQString m_previousGroup;
      TQString m_groupField;
      TQString m_subtotalField;
  };

// ****************************************************************************
//
// ListTable implementation
//
// ****************************************************************************

  bool ListTable::TableRow::operator< ( const TableRow& _compare ) const
  {
    bool result = false;

    TQStringList::const_iterator it_criterion = m_sortCriteria.begin();
    while ( it_criterion != m_sortCriteria.end() )
    {
      if ( this->operator[] ( *it_criterion ) < _compare[ *it_criterion ] )
      {
        result = true;
        break;
      }
      else if ( this->operator[] ( *it_criterion ) > _compare[ *it_criterion ] )
        break;

      ++it_criterion;
    }
    return result;
  }

// needed for KDE < 3.2 implementation of qHeapSort
  bool ListTable::TableRow::operator<= ( const TableRow& _compare ) const
  {
    return ( ! ( _compare < *this ) );
  }

  bool ListTable::TableRow::operator== ( const TableRow& _compare ) const
  {
    return ( ! ( *this < _compare ) && ! ( _compare < *this ) );
  }

  bool ListTable::TableRow::operator> ( const TableRow& _compare ) const
  {
    return ( _compare < *this );
  }

  /**
     * TODO
     *
     * - Collapse 2- & 3- groups when they are identical
     * - Way more test cases (especially splits & transfers)
     * - Option to collapse splits
     * - Option to exclude transfers
     *
   */

  ListTable::ListTable ( const MyMoneyReport& _report ) : m_config ( _report )
  {
  }

  void ListTable::render ( TQString& result, TQString& csv ) const
  {
    MyMoneyMoney grandtotal;
    MyMoneyFile* file = MyMoneyFile::instance();

    result = "";
    csv = "";
    result += TQString ( "<h2 class=\"report\">%1</h2>\n" ).arg ( m_config.name() );
    csv += "\"Report: " + m_config.name() + "\"\n";
      //actual dates of the report
    result += TQString("<div class=\"subtitle\">");
    if(!m_config.fromDate().isNull()) {
      result += i18n("Report date range", "%1 through %2").arg(TDEGlobal::locale()->formatDate(m_config.fromDate(), true)).arg(TDEGlobal::locale()->formatDate(m_config.toDate(), true));
      result += TQString("</div>\n");
      result += TQString("<div class=\"gap\">&nbsp;</div>\n");

      csv += i18n("Report date range", "%1 through %2").arg(TDEGlobal::locale()->formatDate(m_config.fromDate(), true)).arg(TDEGlobal::locale()->formatDate(m_config.toDate(), true));
      csv += TQString("\n");
    }


    result += TQString ( "<div class=\"subtitle\">" );
    if ( m_config.isConvertCurrency() )
    {
      result += i18n ( "All currencies converted to %1" ).arg ( file->baseCurrency().name() );
      csv += i18n ( "All currencies converted to %1\n" ).arg ( file->baseCurrency().name() );
    }
    else
    {
      result += i18n ( "All values shown in %1 unless otherwise noted" ).arg ( file->baseCurrency().name() );
      csv += i18n ( "All values shown in %1 unless otherwise noted\n" ).arg ( file->baseCurrency().name() );
    }
    result += TQString ( "</div>\n" );
    result += TQString ( "<div class=\"gap\">&nbsp;</div>\n" );

    // retrieve the configuration parameters from the report definition.
    // the things that we care about for query reports are:
    // how to group the rows, what columns to display, and what field
    // to subtotal on
    TQStringList groups = TQStringList::split ( ",", m_group );
    TQStringList columns = TQStringList::split ( ",", m_columns );
    columns += m_subtotal;
    TQStringList postcolumns = TQStringList::split ( ",", m_postcolumns );
    columns += postcolumns;

    //
    // Table header
    //
    TQMap<TQString, TQString> i18nHeaders;
    i18nHeaders["postdate"] = i18n ( "Date" );
    i18nHeaders["value"] = i18n ( "Amount" );
    i18nHeaders["number"] = i18n ( "Num" );
    i18nHeaders["payee"] = i18n ( "Payee" );
    i18nHeaders["category"] = i18n ( "Category" );
    i18nHeaders["account"] = i18n ( "Account" );
    i18nHeaders["memo"] = i18n ( "Memo" );
    i18nHeaders["topcategory"] = i18n ( "Top Category" );
    i18nHeaders["categorytype"] = i18n ( "Category Type" );
    i18nHeaders["month"] = i18n ( "Month" );
    i18nHeaders["week"] = i18n ( "Week" );
    i18nHeaders["reconcileflag"] = i18n ( "Reconciled" );
    i18nHeaders["action"] = i18n ( "Action" );
    i18nHeaders["shares"] = i18n ( "Shares" );
    i18nHeaders["price"] = i18n ( "Price" );
    i18nHeaders["latestprice"] = i18n ( "Price" );
    i18nHeaders["netinvvalue"] = i18n ( "Net Value" );
    i18nHeaders["buys"] = i18n ( "Buys" );
    i18nHeaders["sells"] = i18n ( "Sells" );
    i18nHeaders["reinvestincome"] = i18n ( "Dividends Reinvested" );
    i18nHeaders["cashincome"] = i18n ( "Dividends Paid Out" );
    i18nHeaders["startingbal"] = i18n ( "Starting Balance" );
    i18nHeaders["endingbal"] = i18n ( "Ending Balance" );
    i18nHeaders["return"] = i18n ( "Annualized Return" );
    i18nHeaders["returninvestment"] = i18n ( "Return On Investment" );
    i18nHeaders["fees"] = i18n ( "Fees" );
    i18nHeaders["interest"] = i18n ( "Interest" );
    i18nHeaders["payment"] = i18n ( "Payment" );
    i18nHeaders["balance"] = i18n ( "Balance" );
    i18nHeaders["type"] = i18n ( "Type" );
    i18nHeaders["name"] = i18n ( "Name" );
    i18nHeaders["nextduedate"] = i18n ( "Next Due Date" );
    i18nHeaders["occurence"] = i18n ( "Occurence" );
    i18nHeaders["paymenttype"] = i18n ( "Payment Method" );
    i18nHeaders["institution"] = i18n ( "Institution" );
    i18nHeaders["description"] = i18n ( "Description" );
    i18nHeaders["openingdate"] = i18n ( "Opening Date" );
    i18nHeaders["currencyname"] = i18n ( "Currency" );
    i18nHeaders["balancewarning"] = i18n ( "Balance Early Warning" );
    i18nHeaders["maxbalancelimit"] = i18n ( "Balance Max Limit" );
    i18nHeaders["creditwarning"] = i18n ( "Credit Early Warning" );
    i18nHeaders["maxcreditlimit"] = i18n ( "Credit Max Limit" );
    i18nHeaders["tax"] = i18n ( "Tax" );
    i18nHeaders["favorite"] = i18n ( "Preferred" );
    i18nHeaders["loanamount"] = i18n ( "Loan Amount" );
    i18nHeaders["interestrate"] = i18n ( "Interest Rate" );
    i18nHeaders["nextinterestchange"] = i18n ( "Next Interest Change" );
    i18nHeaders["periodicpayment"] = i18n ( "Periodic Payment" );
    i18nHeaders["finalpayment"] = i18n ( "Final Payment" );
    i18nHeaders["currentbalance"] = i18n ( "Current Balance" );

    // the list of columns which represent money, so we can display them correctly
    TQStringList moneyColumns = TQStringList::split ( ",", "value,shares,price,latestprice,netinvvalue,buys,sells,cashincome,reinvestincome,startingbal,fees,interest,payment,balance,balancewarning,maxbalancelimit,creditwarning,maxcreditlimit,loanamount,periodicpayment,finalpayment,currentbalance" );

    // the list of columns which represent shares, which is like money except the
    // transaction currency will not be displayed
    TQStringList sharesColumns = TQStringList::split ( ",", "shares" );

    // the list of columns which represent a percentage, so we can display them correctly
    TQStringList percentColumns = TQStringList::split ( ",", "return,returninvestment,interestrate" );

    // the list of columns which represent dates, so we can display them correctly
    TQStringList dateColumns = TQStringList::split ( ",", "postdate,entrydate,nextduedate,openingdate,nextinterestchange" );

    result += "<table class=\"report\">\n<thead><tr class=\"itemheader\">";

    TQStringList::const_iterator it_column = columns.begin();
    while ( it_column != columns.end() )
    {
      TQString i18nName = i18nHeaders[*it_column];
      if ( i18nName.isEmpty() )
        i18nName = *it_column;
      result += "<th>" + i18nName + "</th>";
      csv += i18nName + ",";
      ++it_column;
    }

    result += "</tr></thead>\n";
    csv = csv.left ( csv.length() - 1 );
    csv += "\n";

    //
    // Set up group iterators
    //
    // There is one active iterator for each level of grouping.
    // As we step through the rows
    // we update the group iterators each time based on the row data.  If
    // the group iterator changes and it had a previous value, we print a
    // subtotal.  Whether or not it had a previous value, we print a group
    // header.  The group iterator keeps track of a subtotal also.

    int depth = 1;
    TQValueList<GroupIterator> groupIteratorList;
    TQStringList::const_iterator it_grouplevel = groups.begin();
    while ( it_grouplevel != groups.end() )
    {
      groupIteratorList += GroupIterator ( ( *it_grouplevel ), m_subtotal, depth++ );
      ++it_grouplevel;
    }

    //
    // Rows
    //

    bool row_odd = true;

    // ***DV***
    MyMoneyMoney startingBalance;
    for ( TQValueList<TableRow>::const_iterator it_row = m_rows.begin();
          it_row != m_rows.end();
          ++it_row ) {

      // the standard fraction is the fraction of an non-cash account in the base currency
      // this could be overridden using the "fraction" element of a row for each row.
      // Currently (2008-02-21) this override is not used at all (ipwizard)
      int fraction = file->baseCurrency().smallestAccountFraction();
      if ( ( *it_row ).find ( "fraction" ) != ( *it_row ).end() )
        fraction = ( *it_row ) ["fraction"].toInt();

      //
      // Process Groups
      //

      // ***DV*** HACK to force a subtotal and header, since this render doesn't
      // always detect a group change for different accounts with the same name
      // (as occurs with the same stock purchased from different investment accts)
      if ( it_row != m_rows.begin() )
        if ( ( ( * it_row ) ["rank"] == "-2" ) && ( ( * it_row ) ["id"] == "A" ) )
          ( groupIteratorList.last() ).force();

      // There's a subtle bug here.  If an earlier group gets a new group,
      // then we need to force all the downstream groups to get one too.

      // Update the group iterators with the current row value
      TQValueList<GroupIterator>::iterator it_group = groupIteratorList.begin();
      while ( it_group != groupIteratorList.end() )
      {
        ( *it_group ).update ( *it_row );
        ++it_group;
      }

      // Do subtotals backwards
      if ( m_config.isConvertCurrency() )
      {
        it_group = groupIteratorList.fromLast();
        while ( it_group != groupIteratorList.end() )
        {
          if ( ( *it_group ).isSubtotal() )
          {
            if ( ( *it_group ).depth() == 1 )
              grandtotal += ( *it_group ).subtotal();
              grandtotal = grandtotal.convert(fraction);

            TQString subtotal_html = ( *it_group ).subtotal().formatMoney ( fraction );
            TQString subtotal_csv = ( *it_group ).subtotal().formatMoney ( fraction, false );

            // ***DV*** HACK fix the side-effiect from .force() method above
            TQString oldName = TQString ( ( *it_group ).oldName() ).stripWhiteSpace();

            result +=
              "<tr class=\"sectionfooter\">"
              "<td class=\"left" + TQString::number ( ( ( *it_group ).depth() - 1 ) ) + "\" "
              "colspan=\"" +
              TQString::number ( columns.count() - 1 - postcolumns.count() ) + "\">" +
              i18n ( "Total" ) + " " + oldName + "</td>"
              "<td>" + subtotal_html + "</td></tr>\n";

            csv +=
              "\"" + i18n ( "Total" ) + " " + oldName + "\",\"" + subtotal_csv + "\"\n";
          }
          --it_group;
        }
      }

      // And headers forwards
      it_group = groupIteratorList.begin();
      while ( it_group != groupIteratorList.end() )
      {
        if ( ( *it_group ).isNewHeader() )
        {
          row_odd = true;
          result += "<tr class=\"sectionheader\">"
                    "<td class=\"left" + TQString::number ( ( ( *it_group ).depth() - 1 ) ) + "\" "
                    "colspan=\"" + TQString::number ( columns.count() ) + "\">" +
                    ( *it_group ).name() + "</td></tr>\n";
          csv += "\"" + ( *it_group ).name() + "\"\n";
        }
        ++it_group;
      }

      //
      // Columns
      //

      // skip the opening and closing balance row,
      // if the balance column is not shown
      if ( ( columns.contains ( "balance" ) == 0 ) && ( ( *it_row ) ["rank"] == "-2" ) )
        continue;

      bool need_label = true;

      // ***DV***
      if ( ( * it_row ) ["rank"] == "0" ) row_odd = ! row_odd;

      if ( ( * it_row ) ["rank"] == "-2" )
        result += TQString ( "<tr class=\"item%1\">" ).arg ( ( * it_row ) ["id"] );
      else
        if ( ( * it_row ) ["rank"] == "1" )
          result += TQString ( "<tr class=\"%1\">" ).arg ( row_odd ? "item1" : "item0" );
        else
          result += TQString ( "<tr class=\"%1\">" ).arg ( row_odd ? "row-odd " : "row-even" );

      TQStringList::const_iterator it_column = columns.begin();
      while ( it_column != columns.end() )
      {
        TQString data = ( *it_row ) [*it_column];

        // ***DV***
        if ( ( * it_row ) ["rank"] == "1" ) {
          if ( * it_column == "value" )
            data = ( * it_row ) ["split"];
          else if ( *it_column == "postdate"
                    || *it_column == "number"
                    || *it_column == "payee"
                    || *it_column == "action"
                    || *it_column == "shares"
                    || *it_column == "price"
                    || *it_column == "nextduedate"
                    || *it_column == "balance"
                    || *it_column == "account"
                    || *it_column == "name" )
            data = "";
        }

        // ***DV***
        if ( ( * it_row ) ["rank"] == "-2" ) {
          if ( *it_column == "balance" ) {
            data = ( * it_row ) ["balance"];
            if ( ( * it_row ) ["id"] == "A" )     // opening balance?
              startingBalance = MyMoneyMoney ( data );
          }

          if ( need_label ) {
            if ( ( * it_column == "payee" ) ||
                 ( * it_column == "category" ) ||
                 ( * it_column == "memo" ) ) {
              if ( ( * it_row ) ["shares"] != "" ) {
                data = ( ( * it_row ) ["id"] == "A" )
                       ? i18n ( "Initial Market Value" )
                       : i18n ( "Ending Market Value" );
              } else {
                data = ( ( * it_row ) ["id"] == "A" )
                       ? i18n ( "Opening Balance" )
                       : i18n ( "Closing Balance" );
              }
              need_label = false;
            }
          }
        }

        // The 'balance' column is calculated at render-time
        // but not printed on split lines
        else if ( *it_column == "balance" && ( * it_row ) ["rank"] == "0" )
        {
          // Take the balance off the deepest group iterator
          data = ( groupIteratorList.back().currenttotal() + startingBalance ).toString();
        }

        // Figure out how to render the value in this column, depending on
        // what its properties are.
        //
        // TODO: This and the i18n headings are handled
        // as a set of parallel vectors.  Would be much better to make a single
        // vector of a properties class.
        if ( sharesColumns.contains ( *it_column ) )
        {
          if ( data.isEmpty() ) {
            result += TQString ( "<td></td>" );
            csv += "\"\",";
          }
          else {
            result += TQString ( "<td>%1</td>" ).arg ( MyMoneyMoney ( data ).formatMoney ( "", 3 ) );
            csv += "\"" + MyMoneyMoney ( data ).formatMoney ( "", 3, false ) + "\",";
          }
        }
        else if ( moneyColumns.contains ( *it_column ) )
        {
          if ( data.isEmpty() ) {
            result += TQString ( "<td%1></td>" )
                      .arg ( ( *it_column == "value" ) ? " class=\"value\"" : "" );
            csv += "\"\",";
          } else if ( MyMoneyMoney( data ) == MyMoneyMoney::autoCalc ) {
            result += TQString ( "<td%1>%2</td>" )
                .arg ( ( *it_column == "value" ) ? " class=\"value\"" : "" )
                .arg (i18n("Calculated"));
            csv += "\""+ i18n("Calculated") +"\",";
          } else if ( *it_column == "price" ) {
            result += TQString ( "<td>%2</td>" )
                .arg ( MyMoneyMoney ( data ).formatMoney ( MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision()) ) );
            csv += "\"" + ( *it_row ) ["currency"] + " " + MyMoneyMoney ( data ).formatMoney ( MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision()), false ) + "\",";
          } else {
            result += TQString ( "<td%1>%2&nbsp;%3</td>" )
                      .arg ( ( *it_column == "value" ) ? " class=\"value\"" : "" )
                      .arg ( ( *it_row ) ["currency"] )
                      .arg ( MyMoneyMoney ( data ).formatMoney ( fraction ) );
            csv += "\"" + ( *it_row ) ["currency"] + " " + MyMoneyMoney ( data ).formatMoney ( fraction, false ) + "\",";
          }
        }
        else if ( percentColumns.contains ( *it_column ) )
        {
          data = ( MyMoneyMoney ( data ) * MyMoneyMoney ( 100, 1 ) ).formatMoney ( fraction );
          result += TQString ( "<td>%1%</td>" ).arg ( data );
          csv += data + "%,";
        }
        else if ( dateColumns.contains ( *it_column ) )
        {
          // do this before we possibly change data
          csv += "\"" + data + "\",";

          // if we have a locale() then use its date formatter
          if ( TDEGlobal::locale() && ! data.isEmpty() ) {
            TQDate qd = TQDate::fromString ( data, Qt::ISODate );
            data = TDEGlobal::locale()->formatDate ( qd, true );
          }
          result += TQString ( "<td class=\"left\">%1</td>" ).arg ( data );
        }
        else
        {
          result += TQString ( "<td class=\"left\">%1</td>" ).arg ( data );
          csv += "\"" + data + "\",";
        }
        ++it_column;
      }

      result += "</tr>\n";
      csv = csv.left ( csv.length() - 1 ); // remove final comma
      csv += "\n";
    }

    //
    // Final group totals
    //

    // Do subtotals backwards
    if ( m_config.isConvertCurrency() )
    {
      int fraction = file->baseCurrency().smallestAccountFraction();
      TQValueList<GroupIterator>::iterator it_group = groupIteratorList.fromLast();
      while ( it_group != groupIteratorList.end() )
      {
        ( *it_group ).update ( TableRow() );

        if ( ( *it_group ).depth() == 1 ) {
          grandtotal += ( *it_group ).subtotal();
          grandtotal = grandtotal.convert(fraction);
        }


        TQString subtotal_html = ( *it_group ).subtotal().formatMoney ( fraction );
        TQString subtotal_csv = ( *it_group ).subtotal().formatMoney ( fraction, false );

        result += "<tr class=\"sectionfooter\">"
                  "<td class=\"left" + TQString::number ( ( *it_group ).depth() - 1 ) + "\" "
                  "colspan=\"" + TQString::number ( columns.count() - 1 - postcolumns.count() ) + "\">" +
                  i18n ( "Total" ) + " " + ( *it_group ).oldName() + "</td>"
                  "<td>" + subtotal_html + "</td></tr>\n";
        csv += "\"" + i18n ( "Total" ) + " " + ( *it_group ).oldName() + "\",\"" + subtotal_csv + "\"\n";
        --it_group;
      }

      //
      // Grand total
      //

      TQString grandtotal_html = grandtotal.formatMoney ( fraction );
      TQString grandtotal_csv = grandtotal.formatMoney ( fraction, false );

      result += "<tr class=\"sectionfooter\">"
                "<td class=\"left0\" "
                "colspan=\"" + TQString::number ( columns.count() - 1 - postcolumns.count() ) + "\">" +
                i18n ( "Grand Total" ) + "</td>"
                "<td>" + grandtotal_html + "</td></tr>\n";
      csv += "\"" + i18n ( "Grand Total" ) + "\",\"" + grandtotal_csv + "\"\n";
    }
    result += "</table>\n";
  }

  TQString ListTable::renderHTML ( void ) const
  {
    TQString html, csv;
    render ( html, csv );
    return html;
  }

  TQString ListTable::renderCSV ( void ) const
  {
    TQString html, csv;
    render ( html, csv );
    return csv;
  }

  void ListTable::dump ( const TQString& file, const TQString& context ) const
  {
    TQFile g ( file );
    g.open ( IO_WriteOnly );

    if ( ! context.isEmpty() )
      TQTextStream ( &g ) << context.arg ( renderHTML() );
    else
      TQTextStream ( &g ) << renderHTML();
    g.close();
  }

  void ListTable::includeInvestmentSubAccounts()
  {
  // if we're not in expert mode, we need to make sure
  // that all stock accounts for the selected investment
  // account are also selected
    TQStringList accountList;
    if(m_config.accounts(accountList)) {
      if(!KMyMoneyGlobalSettings::expertMode()) {
        TQStringList::const_iterator it_a, it_b;
        for(it_a = accountList.begin(); it_a != accountList.end(); ++it_a) {
          MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a);
          if(acc.accountType() == MyMoneyAccount::Investment) {
            for(it_b = acc.accountList().begin(); it_b != acc.accountList().end(); ++it_b) {
              if(!accountList.contains(*it_b)) {
                m_config.addAccount(*it_b);
              }
            }
          }
        }
      }
    }
  }

}
