/***************************************************************************
                          showrecord.cpp  -  description
                             -------------------
    begin                : Mon Dec 3 2001
    copyright            : (C) 2001 by Eggert Ehmke
    email                : eggert.ehmke@berlin.de
 ***************************************************************************/

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

int const ShowRecord::continueShowHeaders( 0 );
int const ShowRecord::cancelShowHeaders( 1 );

ShowRecord::ShowRecord()
{
  //set auto delete to true. This is a function of the parent class, which deletes
  //all items when the list is deleted or cleared.
  setAutoDelete( true );
}

ShowRecord::~ShowRecord()
{
}

void ShowRecord::saveOptions( QDomDocument& doc, QDomElement& parent )
{
  //Loop over all mail items
  for( ShowRecordElem* pElem = first(); pElem; pElem = next() )
  {
    //call the method of the mail to save it
    pElem->saveOptions( doc, parent );
  }
}

void ShowRecord::readStoredMails( QDomElement& parent )
{
  //clear the list
  clear();

  //get first DOM node (mail)
  QDomNode n = parent.firstChild();

  //iterate over all mail items stored in the given account
  while( !n.isNull() )
  {
    //get element of the current node
    QDomElement e = n.toElement();

    //create mail object
    ShowRecordElem* pElem = new ShowRecordElem();

    //store the currently read mail data in the new object
    pElem->readOptions( e );

    //store the new mail object in this list
    append( pElem );

    //get next DOM node
    n = n.nextSibling();
  }
}

bool ShowRecord::hasSelectedMails( )
{
  bool selected = false;    //TRUE when a selected mail was found
  ShowRecordElem* mail;     //mail which we want to check

  //get first mail
  mail = first();

  //iterate over all mails until we have found a selected mail
  while( mail != NULL && !selected )
  {
    //check the current mail
    selected = mail->isSelected();

    //get next mail
    mail = next();
  }

  return selected;
}

MailNumberList_Type ShowRecord::getSelectedMails( )
{
  MailNumberList_Type list;                     //contains the numbers of selected mails
  ShowRecordElem* mail;                         //mail from which we want to get the number (if selected)
  QPtrListIterator<ShowRecordElem> it( *this ); //iterator for the mail list

  //iterate over all mails
  while( ( mail = it.current() ) != NULL )
  {
    //increment iterator to next mail
    ++it;

    //if current mail is selected append its number to the mail number list
    if( mail->isSelected() )
      list.append( mail->number() );
  }

  return list;
}

void ShowRecord::removeMail( int number )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail

  //looking for the mail with the number 'number'
  while( ( mail = it.current() ) != NULL )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given number, remove it
    if( mail->number() == number )
      remove( mail );
  }
}

QStringList ShowRecord::getSelectedSubjects( ) const
{
  QStringList subjects;                           //contains the subjects
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail

  //iterate over all mails
  while( ( mail = it.current() ) != NULL )
  {
    //increment iterator to next mail
    ++it;

    //if the mail is selected, append subject to list
    if( mail->isSelected() )
      subjects.append( mail->subject() );
  }

  return subjects;
}

QString ShowRecord::getSenderOf( int number ) const
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found
  QString sender;                                 //sender of the wanted mail

  //looking for the mail with the number 'number'
  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given number, remove it
    if( mail->number() == number )
    {
      sender = mail->from();
      found = true;
    }
  }
  return sender;
}

QString ShowRecord::getDateOf( int number ) const
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found
  QString date;                                   //sent date of the wanted mail

  //looking for the mail with the number 'number'
  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given number, remove it
    if( mail->number() == number )
    {
      date = mail->date();
      found = true;
    }
  }
  return date;

}

QString ShowRecord::getSizeOf( int number ) const
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found
  QString size;                                   //size of the wanted mail

  //looking for the mail with the number 'number'
  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given number, remove it
    if( mail->number() == number )
    {
      size = mail->strSizePrefix();
      found = true;
    }
  }
  return size;

}

QString ShowRecord::getSubjectOf( int number ) const
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found
  QString subject;                                //subject of the wanted mail

  //looking for the mail with the number 'number'
  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given number, get the subject
    if( mail->number() == number )
    {
      subject = mail->subject();
      found = true;
    }
  }
  return subject;

}

QString ShowRecord::decodeMailBody( QByteArray body, int number, bool preferHTML ) const
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found
  QString mailbody;                               //decoded mail

  //looking for the mail with the number 'number'
  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given number, decode the mail
    if( mail->number() == number )
    {
      mailbody = mail->decodeMailBody( body, preferHTML );
      found = true;
    }
  }
  return mailbody;

}

bool ShowRecord::hasMail( QString uid )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found

  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //compare the uid
    if( mail->uidl() == uid )
    {
     found = true;
    }
  }
  return found;
}

void ShowRecord::appendNewMail( int number, QString uid, bool isNew )
{
  //create new mail
  ShowRecordElem* newMail = new ShowRecordElem( number, uid, isNew );

  //append new mail
  if( newMail != NULL )
    append( newMail );
}

void ShowRecord::printMailList( )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail

  while( ( mail = it.current() ) )
  {
    //increment iterator to next mail
    ++it;

    //print mail
    cout << mail->number() << " - UID: " << mail->uidl() << "; Size: " << mail->size() << "; Subject: " << mail->subject() << "; New: " << mail->isNew() << endl;
  }

}

void ShowRecord::setSize( int number, long size )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found

  //looking for the mail with the number 'number'
  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given number, decode the mail
    if( mail->number() == number )
    {
      mail->setSize( size );
      found = true;
    }
  }
}

Types::MailNumberList_Type ShowRecord::getNewMails( )
{
  MailNumberList_Type list;                     //contains the numbers of the new mails
  ShowRecordElem* mail;                         //mail from which we want to get the number (if new)
  QPtrListIterator<ShowRecordElem> it( *this ); //iterator for the mail list

  //iterate over all mails
  while( ( mail = it.current() ) != NULL )
  {
    //increment iterator to next mail
    ++it;

    //if current mail is new append its number to the mail number list
    if( mail->isNew() )
      list.append( mail->number() );
  }

  return list;
}

void ShowRecord::setHeader( int number, QString header )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found

  //looking for the mail with the number 'number'
  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given number, set the header
    if( mail->number() == number )
    {
      mail->setHeader( header );
      found = true;
    }
  }
}

QStringList ShowRecord::getUIDsOfOldMails( )
{
  QStringList list;                             //contains the UIDs of the old mails
  ShowRecordElem* mail;                         //mail from which we want to get the uid (if old)
  QPtrListIterator<ShowRecordElem> it( *this ); //iterator for the mail list

  //iterate over all mails
  while( ( mail = it.current() ) != NULL )
  {
    //increment iterator to next mail
    ++it;

    //if current mail is new append its number to the mail number list
    if( !mail->isNew() )
      list.append( mail->uidl() );
  }

  return list;
}

QString ShowRecord::getHeaderOf( QString uid )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found
  QString header;                                 //header of the wanted mail

  //looking for the mail with the UID 'uid'
  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given uid, get the header
    if( mail->uidl() == uid )
    {
      header = mail->header();
      found = true;
    }
  }
  return header;
}

void ShowRecord::setHeader( QString uid, QString header )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found

  //looking for the mail with the UID 'uid'
  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given UID, set the header
    if( mail->uidl() == uid )
    {
      mail->setHeader( header );
      found = true;
    }
  }
}

int ShowRecord::getNumberNewMails( )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  int number = 0;                                 //number of new mails

  while( ( mail = it.current() ) )
  {
    //increment iterator to next mail
    ++it;

    //increment number, if this mail is new
    if( mail->isNew() )
      number++;
  }

  return number;
}

int ShowRecord::getNumberMails( )
{
  return count();
}

long ShowRecord::getTotalSize( )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  long size = 0;                                   //total size of all mails

  while( ( mail = it.current() ) )
  {
    //increment iterator to next mail
    ++it;

    size += mail->size();
  }

  return size;
}

void ShowRecord::fillMailListView( KshowmailView * view, QString & account )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail

  //iterate over all mails and order the mail to create a list view item
  while( ( mail = it.current() ) )
  {
    //increment iterator to next mail
    ++it;

    //insert list view item
    QString number = QString( "%1" ).arg( mail->number() );
    QString from = mail->from();
    QString to = mail->to();
    QString subject = mail->subject();
    QString date = mail->date();
    QString size = QString( "%1" ).arg( mail->size() );
    QString content = mail->content();
    QString state = mail->state();
    QString time = mail->strUnixTime();
    mail->setViewItem( view->insertMail( number, account, from, to, subject, date, size, content, state, time ) );
  }

}

int ShowRecord::showSelectedHeaders( QString& account )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  int showNextHeader = ShowRecordElem::continueShowHeaders; //return value of ShowRecordElem::showHeader()

  while( ( mail = it.current() ) && showNextHeader == ShowRecordElem::continueShowHeaders )
  {
    //increment iterator to next mail
    ++it;

    //order the mail to show its header
    if( mail->isSelected() )
      showNextHeader = mail->showHeader( account );
  }

  return showNextHeader == ShowRecordElem::continueShowHeaders ? ShowRecord::continueShowHeaders : ShowRecord::cancelShowHeaders;
}

bool ShowRecord::isNew( QString uid ) const
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found
  bool newMail = false;                           //at time we have not found it, therefore the return value is false

  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //compare the uid
    if( mail->uidl() == uid )
    {
      found = true;
      newMail = mail->isNew();
    }
  }

  return newMail;
}

void ShowRecord::applyHeaderFilter( HeaderFilter * filter, QString account, MailNumberList_Type& deleteList, MailToDownloadMap_Type& downloadList, int& nmbIgnoredMails, FilterLog* log )
{

  MailNumberList_Type mailsToIgnore;  //this list holds the numbers of all mails, which shall be ignored

    //Loop over all mails in this list
  for( ShowRecordElem* pElem = first(); pElem; pElem = next() )
  {
    //apply the filters to the current mail
    QString mailbox;
    FilterAction_Type action = pElem->applyHeaderFilter( filter, account, mailbox, log );

    //do recommend action
    //we don't need to do everything for action MARK, because ShowRecordElem::applyHeaderFilter() marks the mail entry itself
    struct DownloadActionParams_Type params;
    switch( action )
    {
      case FActDelete     : deleteList.append( pElem->number() ); break;
      case FActMove       : params.action = FActMove;
                            params.mailbox = mailbox;
                            downloadList.insert( pElem->number(), params );
                            break;
      case FActIgnore     : mailsToIgnore.append( pElem->number() ); break;
      case FActSpamcheck  : params.action = FActSpamcheck;
                            downloadList.insert( pElem->number(), params );
      default          : break;
    }
  }

  //remove all mails which shall be ignored from the mail list
  nmbIgnoredMails = mailsToIgnore.count();
  MailNumberList_Type::iterator it;
  for ( it = mailsToIgnore.begin(); it != mailsToIgnore.end(); ++it )
    removeMail( *it );


}

void ShowRecord::writeToMoveLog( FilterLog * log, int number, QString account, QString mailbox )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found

  //looking for the mail with the number 'number'
  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given number, set the header
    if( mail->number() == number )
    {
      mail->writeToMoveLog( log, account, mailbox );
      found = true;
    }
  }
}

void ShowRecord::writeToDeleteLog( FilterLog * log, int number, QString account )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found

  //looking for the mail with the number 'number'
  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given number, set the header
    if( mail->number() == number )
    {
      mail->writeToDeleteLog( log, account );
      found = true;
    }
  }
}

void ShowRecord::setMarkAtNextViewRefresh( int number )
{
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail
  bool found = false;                             //True, when the wanted mail was found

  //looking for the mail with the number 'number'
  while( ( mail = it.current() ) != NULL && !found )
  {
    //increment iterator to next mail
    ++it;

    //if the current mail has the given number, set the header
    if( mail->number() == number )
    {
      mail->setMarkAtNextViewRefresh();
      found = true;
    }
  }
}

QStringList ShowRecord::getSelectedSenders( ) const
{
  QStringList senders;                           //contains the senders
  QPtrListIterator<ShowRecordElem> it( *this );   //iterator for the mail list
  ShowRecordElem* mail;                           //current mail

  //iterate over all mails
  while( ( mail = it.current() ) != NULL )
  {
    //increment iterator to next mail
    ++it;

    //if the mail is selected, append subject to list
    if( mail->isSelected() )
      senders.append( mail->from() );
  }

  return senders;
}
