/*
    This file is part of libkcal.

    Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include <typeinfo>
#include <stdlib.h>

#include <tqdatetime.h>
#include <tqstring.h>
#include <tqptrlist.h>

#include <tdelocale.h>
#include <kdebug.h>
#include <kurl.h>
#include <tdeio/job.h>
#include <tdestandarddirs.h>

#include <tdeabc/stdaddressbook.h>
#include <tdeabc/locknull.h>

#include "libkcal/vcaldrag.h"
#include "libkcal/vcalformat.h"
#include "libkcal/icalformat.h"
#include "libkcal/exceptions.h"
#include "libkcal/incidence.h"
#include "libkcal/event.h"
#include "libkcal/todo.h"
#include "libkcal/journal.h"
#include "libkcal/filestorage.h"
#include "libkcal/alarm.h"

#include <libemailfunctions/email.h>

#include <tderesources/configwidget.h>

#include "resourcetdeabcconfig.h"

#include "resourcetdeabc.h"

using namespace KCal;

extern "C"
{
  void *init_kcal_tdeabc()
  {
	  TDEGlobal::locale()->insertCatalogue( "kres_birthday" );
    TDEGlobal::locale()->insertCatalogue( "libkcal" );
    return new KRES::PluginFactory<ResourceTDEABC,ResourceTDEABCConfig>();
  }
}

ResourceTDEABC::ResourceTDEABC( const TDEConfig* config )
  : ResourceCalendar( config ), mCalendar( TQString::fromLatin1( "UTC" ) ),
    mAlarmDays( 0 ), mAlarm( true ), mUseCategories( false )
{
  if ( config ) {
    readConfig( config );
  } else {
    setResourceName( i18n( "Birthdays" ) );
  }

  init();
}

ResourceTDEABC::ResourceTDEABC()
  : ResourceCalendar( 0 ), mCalendar( TQString::fromLatin1( "UTC" ) ),
    mAlarmDays( 0 ), mAlarm( true ), mUseCategories( false )
{
  init();
}

ResourceTDEABC::~ResourceTDEABC()
{
  delete mLock;
}

void ResourceTDEABC::init()
{
  setType( "birthdays" );

  setReadOnly( true );

  mLock = new TDEABC::LockNull( false );

  mAddressbook = 0;
}

void ResourceTDEABC::readConfig( const TDEConfig *config )
{
  mAlarmDays = config->readNumEntry( "AlarmDays", 0 );
  mAlarm = config->readBoolEntry( "Alarm", true );
  mCategories = config->readListEntry( "Categories" );
  mUseCategories = config->readBoolEntry( "UseCategories", false );
}

void ResourceTDEABC::writeConfig( TDEConfig *config )
{
  ResourceCalendar::writeConfig( config );
  config->writeEntry( "AlarmDays", mAlarmDays );
  config->writeEntry( "Alarm", mAlarm );
  config->writeEntry( "Categories", mCategories );
  config->writeEntry( "UseCategories", mUseCategories );
}


bool ResourceTDEABC::doOpen()
{
  kdDebug(5800) << "ResourceTDEABC::doOpen()" << endl;

  mAddressbook = TDEABC::StdAddressBook::self( true );
  connect( mAddressbook, TQ_SIGNAL(addressBookChanged(AddressBook*)), TQ_SLOT( reload() ) );

  return true;
}

bool ResourceTDEABC::doLoad()
{
  kdDebug(5800) << "ResourceTDEABC::load()" << endl;

  mCalendar.close();

  // import from tdeabc
  TQString summary;
  TQStringList::ConstIterator strIt;
  const TQStringList::ConstIterator endStrIt = mCategories.end();
  TDEABC::Addressee::List anniversaries;
  TDEABC::Addressee::List::Iterator addrIt;

  TDEABC::AddressBook::Iterator it;
  const TDEABC::AddressBook::Iterator endIt = mAddressbook->end();
  for ( it = mAddressbook->begin(); it != endIt; ++it ) {

    if ( mUseCategories ) {
      bool hasCategory = false;
      TQStringList categories = (*it).categories();
      for ( strIt = mCategories.begin(); strIt != endStrIt; ++strIt )
        if ( categories.contains( *strIt ) ) {
          hasCategory = true;
          break;
        }

      if ( !hasCategory )
        continue;
    }

    TQDate birthdate = (*it).birthday().date();
    TQString name_1, email_1, uid_1;
    if ( birthdate.isValid() ) {
      kdDebug(5800) << "found a birthday " << TQString(birthdate.toString()) << endl;

      name_1 = (*it).nickName();
      email_1 = (*it).fullEmail();
      uid_1 = (*it).uid();
      if (name_1.isEmpty()) name_1 = (*it).realName();
      summary = i18n("%1's birthday").arg( name_1 );


      Event *ev = new Event();
      ev->setUid( uid_1+"_KABC_Birthday");

      ev->setDtStart(birthdate);
      ev->setDtEnd(birthdate);
      ev->setHasEndDate(true);
      ev->setFloats(true);
      ev->setTransparency( Event::Transparent );

      ev->setCustomProperty("KABC", "BIRTHDAY", "YES");
      ev->setCustomProperty("KABC", "UID-1", uid_1 );
      ev->setCustomProperty("KABC", "NAME-1", name_1 );
      ev->setCustomProperty("KABC", "EMAIL-1", email_1 );
      kdDebug(5800) << "ResourceTDEABC::doLoad: uid:" << uid_1 << " name: " << name_1
        << " email: " << email_1 << endl;
      ev->setSummary(summary);

      // Set the recurrence
      Recurrence *vRecurrence = ev->recurrence();
      vRecurrence->setStartDate( birthdate );
      vRecurrence->setYearly( 1 );
      if ( birthdate.month()==2 && birthdate.day()==29 ) {
        vRecurrence->addYearlyDay( 60 );
      }

      ev->clearAlarms();

      if ( mAlarm ) {
        // Set the alarm
        Alarm* vAlarm = ev->newAlarm();
        vAlarm->setText(summary);
        vAlarm->setTime(birthdate);
        // 24 hours before. duration is in seconds.
        vAlarm->setStartOffset( -86400 * mAlarmDays );
        vAlarm->setEnabled(true);
      }

      // insert category
      ev->setCategories(i18n("Birthday"));

      ev->setReadOnly( true );
      mCalendar.addEvent(ev);
      kdDebug(5800) << "imported " << TQString(birthdate.toString()) << endl;
    }

    TQString anniversary_string = (*it).custom( "KADDRESSBOOK", "X-Anniversary" );
    if (anniversary_string.isEmpty() )
      continue;
    TQDateTime anniversary = TQDate::fromString( anniversary_string, TQt::ISODate );
    if ( !anniversary.isValid() )
      continue;

    TQString name = (*it).custom( "KADDRESSBOOK", "X-SpousesName" );
    if ( name.isEmpty() )
      anniversaries.append( *it );
    else {
      bool found = false;
      for ( addrIt = anniversaries.begin(); addrIt != anniversaries.end(); ++addrIt ) {
        if ( name == (*addrIt).realName() ) {
          TQDate spouseAnniversary =
            TQDate::fromString( (*addrIt).custom( "KADDRESSBOOK", "X-Anniversary" ), TQt::ISODate );
          if ( anniversary == TQDateTime(spouseAnniversary) ) {
            found = true;
            break;

          }
        }
      }

      if ( !found )
        anniversaries.append( *it );
    }
  }

  for ( addrIt = anniversaries.begin(); addrIt != anniversaries.end(); ++addrIt ) {
    TQDate anniversary = TQDate::fromString( (*addrIt).custom( "KADDRESSBOOK", "X-Anniversary" ), TQt::ISODate );
    kdDebug(5800) << "found a anniversary " << TQString(anniversary.toString()) << endl;
    TQString name;
    TQString name_1 = (*addrIt).nickName();
    TQString uid_1 = (*addrIt).uid();
    TQString email_1 = (*addrIt).fullEmail();
    if ( name_1.isEmpty() )
      name_1 = (*addrIt).realName();


    TQString spouseName = (*addrIt).custom( "KADDRESSBOOK", "X-SpousesName" );
    TQString name_2,email_2,uid_2;
    if ( !spouseName.isEmpty() ) {
      TQString tname, temail;
      KPIM::getNameAndMail( spouseName, tname, temail );
      tname = KPIM::quoteNameIfNecessary( tname );
      if ( ( tname[0] == '"' ) && ( tname[tname.length() - 1] == '"' ) ) {
        tname.remove( 0, 1 );
        tname.truncate( tname.length() - 1 );
      }
      TDEABC::Addressee spouse;
      spouse.setNameFromString( tname );
      name_2 = spouse.nickName();
      uid_2 = spouse.uid();
      email_2 = spouse.fullEmail();
      if ( name_2.isEmpty() ) {
        name_2 = spouse.realName();
      }
      summary = i18n("insert names of both spouses",
                     "%1's & %2's anniversary").arg( name_1 ).arg( name_2 );
    } else {
      summary = i18n("only one spouse in addressbook, insert the name",
                     "%1's anniversary").arg( name_1 );
    }

    Event *ev = new Event();
    ev->setUid( uid_1+"_KABC_Anniversary" );

    ev->setDtStart(anniversary);
    ev->setDtEnd(anniversary);
    ev->setHasEndDate(true);
    ev->setFloats(true);

    ev->setSummary(summary);

    ev->setCustomProperty( "KABC", "BIRTHDAY", "YES" );

    ev->setCustomProperty( "KABC", "UID-1", uid_1 );
    ev->setCustomProperty( "KABC", "NAME-1", name_1 );
    ev->setCustomProperty( "KABC", "EMAIL-1", email_1 );
    ev->setCustomProperty( "KABC", "ANNIVERSARY", "YES" );
    if ( !spouseName.isEmpty() ) {
      ev->setCustomProperty("KABC", "UID-2", uid_2 );
      ev->setCustomProperty("KABC", "NAME-2", spouseName );
      ev->setCustomProperty("KABC", "EMAIL-2", email_2 );
    }
    // Set the recurrence
    Recurrence *vRecurrence = ev->recurrence();
    vRecurrence->setStartDate( anniversary );
    vRecurrence->setYearly( 1 );
    if ( anniversary.month()==2 && anniversary.day()==29 ) {
      vRecurrence->addYearlyDay( 60 );
    }

    ev->clearAlarms();

    if ( mAlarm ) {
      // Set the alarm
      Alarm* vAlarm = ev->newAlarm();
      vAlarm->setText(summary);
      vAlarm->setTime(anniversary);
      // 24 hours before. duration is in seconds.
      vAlarm->setStartOffset( -86400 * mAlarmDays );
      vAlarm->setEnabled(true);
    }

    // insert category
    ev->setCategories(i18n("Anniversary"));

    ev->setReadOnly( true );
    mCalendar.addEvent(ev);
    kdDebug(5800) << "imported " << TQString(anniversary.toString()) << endl;
  }

  return true;
}

void ResourceTDEABC::setAlarm( bool a )
{
  mAlarm = a;
}

bool ResourceTDEABC::alarm()
{
  return mAlarm;
}

void ResourceTDEABC::setAlarmDays( int ad )
{
  mAlarmDays = ad;
}

int ResourceTDEABC::alarmDays()
{
  return mAlarmDays;
}

void ResourceTDEABC::setCategories( const TQStringList &categories )
{
  mCategories = categories;
}

TQStringList ResourceTDEABC::categories() const
{
  return mCategories;
}

void ResourceTDEABC::setUseCategories( bool useCategories )
{
  mUseCategories = useCategories;
}

bool ResourceTDEABC::useCategories() const
{
  return mUseCategories;
}

bool ResourceTDEABC::doSave()
{
  // is always read only!
  return true;
}

bool ResourceTDEABC::isSaving()
{
  return false;
}

TDEABC::Lock *ResourceTDEABC::lock()
{
  return mLock;
}


bool ResourceTDEABC::addEvent( Event * )
{
  return false;
}

bool ResourceTDEABC::addEvent( Event *, const TQString & )
{
  return false;
}

bool ResourceTDEABC::deleteEvent( Event * )
{
  return false;
}


Event *ResourceTDEABC::event( const TQString &uid )
{
  return mCalendar.event( uid );
}

Event::List ResourceTDEABC::rawEventsForDate( const TQDate &date,
                                             EventSortField sortField,
                                             SortDirection sortDirection )
{
  return mCalendar.rawEventsForDate( date, sortField, sortDirection );
}

Event::List ResourceTDEABC::rawEvents( const TQDate &start, const TQDate &end,
                                          bool inclusive )
{
  return mCalendar.rawEvents( start, end, inclusive );
}

Event::List ResourceTDEABC::rawEventsForDate(const TQDateTime &qdt)
{
  return mCalendar.rawEventsForDate( qdt.date() );
}

Event::List ResourceTDEABC::rawEvents( EventSortField sortField, SortDirection sortDirection )
{
  return mCalendar.rawEvents( sortField, sortDirection );
}

bool ResourceTDEABC::addTodo( Todo * )
{
  return false;
}

bool ResourceTDEABC::addTodo( Todo *, const TQString & )
{
  return false;
}

bool ResourceTDEABC::deleteTodo( Todo * )
{
  return false;
}


Todo::List ResourceTDEABC::rawTodos( TodoSortField sortField, SortDirection sortDirection )
{
  return mCalendar.rawTodos( sortField, sortDirection );
}

Todo *ResourceTDEABC::todo( const TQString &uid )
{
  return mCalendar.todo( uid );
}

Todo::List ResourceTDEABC::rawTodosForDate( const TQDate &date )
{
  return mCalendar.rawTodosForDate( date );
}


bool ResourceTDEABC::addJournal( Journal * )
{
  return false;
}

bool ResourceTDEABC::addJournal( Journal *, const TQString & )
{
  return false;
}

bool ResourceTDEABC::deleteJournal( Journal * )
{
  return false;
}

Journal *ResourceTDEABC::journal(const TQString &uid)
{
  return mCalendar.journal( uid );
}

Journal::List ResourceTDEABC::rawJournals( JournalSortField sortField, SortDirection sortDirection )
{
  return mCalendar.rawJournals( sortField, sortDirection );
}

Journal::List ResourceTDEABC::rawJournalsForDate( const TQDate &date )
{
  return mCalendar.rawJournalsForDate( date );
}

Alarm::List ResourceTDEABC::alarmsTo( const TQDateTime &to )
{
  return mCalendar.alarmsTo( to );
}

Alarm::List ResourceTDEABC::alarms( const TQDateTime &from, const TQDateTime &to )
{
//  kdDebug(5800) << "ResourceTDEABC::alarms(" << from.toString() << " - " << to.toString() << ")\n";

  return mCalendar.alarms( from, to );
}

void ResourceTDEABC::dump() const
{
  ResourceCalendar::dump();
}

void ResourceTDEABC::reload()
{
  load();
  emit resourceChanged( this );
}

void ResourceTDEABC::setTimeZoneId( const TQString& tzid )
{
  mCalendar.setTimeZoneId( tzid );
}

#include "resourcetdeabc.moc"
