/*
    This file is part of libkcal.
    Copyright (c) 2001 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., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <kglobal.h>
#include <klocale.h>
#include <kdebug.h>

#include "todo.h"

using namespace KCal;

Todo::Todo(): Incidence()
{
//  mStatus = TENTATIVE;

  mHasDueDate = false;
  setHasStartDate( false );
  mCompleted = getEvenTime(QDateTime::currentDateTime());
  mHasCompletedDate = false;
  mPercentComplete = 0;
}

Todo::Todo(const Todo &t) : Incidence(t)
{
  mDtDue = t.mDtDue;
  mHasDueDate = t.mHasDueDate;
  mCompleted = t.mCompleted;
  mHasCompletedDate = t.mHasCompletedDate;
  mPercentComplete = t.mPercentComplete;
}

Todo::~Todo()
{

}

Incidence *Todo::clone()
{
  return new Todo(*this);
}

bool Todo::contains ( Todo* from )
{ 

    if ( !from->summary().isEmpty() )
        if (  !summary().startsWith(  from->summary() ))
            return false;
    if ( from->hasStartDate() ) {
        if ( !hasStartDate() )
            return false;
        if ( from->dtStart() != dtStart())
            return false;      
    }
    if ( from->hasDueDate() ){
        if ( !hasDueDate() )
            return false;
        if ( from->dtDue() != dtDue())
            return false;  
    }
    if ( !from->location().isEmpty() )
        if (  !location().startsWith( from->location() ) )
            return false;
    if ( !from->description().isEmpty() )
        if (  !description().startsWith(  from->description() ))
            return false;
     if ( from->alarms().count() ) {
        Alarm *a = from->alarms().first();
        if (  a->enabled()  ){
            if ( !alarms().count() )
                return false;
            Alarm *b = alarms().first();
            if( ! b->enabled() )
                return false;
            if ( ! (a->offset() == b->offset() ))
                return false;
        }
    }
   
    QStringList cat = categories();
    QStringList catFrom = from->categories();
    QString nCat;
    int iii;
    for ( iii = 0; iii < catFrom.count();++iii ) {
        nCat = catFrom[iii];
        if ( !nCat.isEmpty() )
            if ( !cat.contains( nCat )) {
                return false;
            }
    }
    if ( from->isCompleted() ) {
        if ( !isCompleted() )
            return false;
    }
    if( priority() !=  from->priority() )
        return false;


    return true;

}
bool KCal::operator==( const Todo& t1, const Todo& t2 )
{

    bool ret = operator==( (const Incidence&)t1, (const Incidence&)t2 );
    if ( ! ret )
        return false;
    if (  t1.hasDueDate() == t2.hasDueDate() ) {
        if ( t1.hasDueDate() ) {
            if ( t1.doesFloat() == t2.doesFloat() ) {
                if ( t1.doesFloat() ) {
                    if ( t1.dtDue().date() != t2.dtDue().date() )
                        return false;
                } else
                    if ( t1.dtDue() != t2.dtDue() ) 
                        return false;
            } else
                return false;// float !=
        }
        
    } else
        return false;
    if ( t1.percentComplete() != t2.percentComplete() )
        return false;
    if ( t1.isCompleted() ) {
        if (  t1.hasCompletedDate() == t2.hasCompletedDate() ) {
            if ( t1.hasCompletedDate() ) {
                if ( t1.completed() != t2.completed() )
                    return false;
            }
            
        } else
            return false;
    }
    return true;

}

void Todo::setDtDue(const QDateTime &dtDue)
{
  //int diffsecs = mDtDue.secsTo(dtDue);

  /*if (mReadOnly) return;
  const QPtrList<Alarm>& alarms = alarms();
  for (Alarm* alarm = alarms.first(); alarm; alarm = alarms.next()) {
    if (alarm->enabled()) {
      alarm->setTime(alarm->time().addSecs(diffsecs));
    }
  }*/
  mDtDue = getEvenTime(dtDue);

  //kdDebug(5800) << "setDtDue says date is " << mDtDue.toString() << endl;

  /*const QPtrList<Alarm>& alarms = alarms();
  for (Alarm* alarm = alarms.first(); alarm; alarm = alarms.next())
    alarm->setAlarmStart(mDtDue);*/

  updated();
}

QDateTime Todo::dtDue() const
{
  return mDtDue;
}

QString Todo::dtDueTimeStr() const
{
  return KGlobal::locale()->formatTime(mDtDue.time());
}

QString Todo::dtDueDateStr(bool shortfmt) const
{
  return KGlobal::locale()->formatDate(mDtDue.date(),shortfmt);
}

QString Todo::dtDueStr(bool shortfmt) const
{
  return KGlobal::locale()->formatDateTime(mDtDue, shortfmt);
}
// retval 0 : no found
//        1 : due for date found
//        2 : overdue for date found
int Todo::hasDueSubTodoForDate( const QDate & date, bool checkSubtodos  )
{
    int retval = 0;
    if ( isCompleted() )
        return 0;
    if ( hasDueDate() ) {
        if ( dtDue().date() < date )
            return 2;
        // we do not return, because we may find an overdue sub todo
        if ( dtDue().date() == date )
            retval = 1;
    }
    if ( checkSubtodos ) {
        Incidence *aTodo;
        for (aTodo = mRelations.first(); aTodo; aTodo = mRelations.next()) {
            int ret = ((Todo*)aTodo)->hasDueSubTodoForDate( date ,checkSubtodos );
            if ( ret == 2 )
                return 2;
            if ( ret == 1)
                retval = 1;
        }
    }
    return retval;
}
int Todo::hasDueSubTodo( bool checkSubtodos  ) //= true
{  
    return hasDueSubTodoForDate(QDate::currentDate(), checkSubtodos );
}
bool Todo::hasDueDate() const
{
  return mHasDueDate;
}

void Todo::setHasDueDate(bool f)
{
  if (mReadOnly) return;
  mHasDueDate = f;
  updated();
}


#if 0
void Todo::setStatus(const QString &statStr)
{
  if (mReadOnly) return;
  QString ss(statStr.upper());

  if (ss == "X-ACTION")
    mStatus = NEEDS_ACTION;
  else if (ss == "NEEDS ACTION")
    mStatus = NEEDS_ACTION;
  else if (ss == "ACCEPTED")
    mStatus = ACCEPTED;
  else if (ss == "SENT")
    mStatus = SENT;
  else if (ss == "TENTATIVE")
    mStatus = TENTATIVE;
  else if (ss == "CONFIRMED")
    mStatus = CONFIRMED;
  else if (ss == "DECLINED")
    mStatus = DECLINED;
  else if (ss == "COMPLETED")
    mStatus = COMPLETED;
  else if (ss == "DELEGATED")
    mStatus = DELEGATED;

  updated();
}

void Todo::setStatus(int status)
{
  if (mReadOnly) return;
  mStatus = status;
  updated();
}

int Todo::status() const
{
  return mStatus;
}

QString Todo::statusStr() const
{
  switch(mStatus) {
  case NEEDS_ACTION:
    return QString("NEEDS ACTION");
    break;
  case ACCEPTED:
    return QString("ACCEPTED");
    break;
  case SENT:
    return QString("SENT");
    break;
  case TENTATIVE:
    return QString("TENTATIVE");
    break;
  case CONFIRMED:
    return QString("CONFIRMED");
    break;
  case DECLINED:
    return QString("DECLINED");
    break;
  case COMPLETED:
    return QString("COMPLETED");
    break;
  case DELEGATED:
    return QString("DELEGATED");
    break;
  }
  return QString("");
}
#endif

bool Todo::isCompleted() const
{
  if (mPercentComplete == 100) return true;
  else return false;
}

void Todo::setCompleted(bool completed)
{
  if (completed) mPercentComplete = 100;
  else {
      mPercentComplete = 0;
      mHasCompletedDate = false;
  }
  updated();
}

QDateTime Todo::completed() const
{
  return mCompleted;
}

QString Todo::completedStr( bool shortF ) const
{
    return KGlobal::locale()->formatDateTime(mCompleted, shortF);
}

void Todo::setCompleted(const QDateTime &completed)
{
    //qDebug("Todo::setCompleted ");
    if ( mHasCompletedDate ) {
        // qDebug("has completed data - return ");
        return;
    }
  mHasCompletedDate = true;
  mPercentComplete = 100;
  mCompleted = getEvenTime(completed);
  updated();
}

bool Todo::hasCompletedDate() const
{
  return mHasCompletedDate;
}

int Todo::percentComplete() const
{
  return mPercentComplete;
}

void Todo::setPercentComplete(int v)
{
  mPercentComplete = v;
  if ( v != 100 )
      mHasCompletedDate = false;
  updated();
}
QDateTime Todo::getNextAlarmDateTime( bool * ok, int * offset ) const
{
    if ( isCompleted() || ! hasDueDate() || cancelled() ) {
         *ok = false;
         return QDateTime ();
     }
     QDateTime incidenceStart;
     incidenceStart = dtDue(); 
     bool enabled = false;
     Alarm* alarm;
     int off;
     QDateTime alarmStart = QDateTime::currentDateTime().addDays( 3650 );;
    //  if ( QDateTime::currentDateTime() > incidenceStart ){
//          *ok = false;
//          return incidenceStart;
//      }
     for (QPtrListIterator<Alarm> it(mAlarms); (alarm = it.current()) != 0; ++it) {
         if (alarm->enabled()) {
             if ( alarm->hasTime () ) {
                 if ( alarm->time() < alarmStart ) {
                     alarmStart = alarm->time();
                     enabled = true;
                     off = alarmStart.secsTo( incidenceStart );
                 }

             } else {
                 int secs = alarm->startOffset().asSeconds();
                 if ( incidenceStart.addSecs( secs ) < alarmStart ) {
                     alarmStart = incidenceStart.addSecs( secs );
                     enabled = true;
                     off = -secs;
                 }
             }
         }
     }
     if ( enabled ) {
         if ( alarmStart >  QDateTime::currentDateTime()  ) {
             *ok = true;
             * offset = off;
             return alarmStart;
         }
     }
     *ok = false;
     return QDateTime ();

}