/*
    This file is part of libkcal.

    Copyright (c) 2001-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 <tdeglobal.h>
#include <tdelocale.h>
#include <kdebug.h>

#include "todo.h"

using namespace KCal;

Todo::Todo()
{
  mHasDueDate = false;
  mHasStartDate = false;

  mHasCompletedDate = false;
  mPercentComplete = 0;
}

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

Todo::~Todo()
{
}

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


Todo& Todo::operator=( const Todo &t )
{
  Incidence::operator=( t );
  mDtDue = t.mDtDue;
  mHasDueDate = t.mHasDueDate;
  mHasStartDate = t.mHasStartDate;
  mCompleted = t.mCompleted;
  mHasCompletedDate = t.mHasCompletedDate;
  mPercentComplete = t.mPercentComplete;
  mDtRecurrence = t.mDtRecurrence;
  return *this;
}

bool Todo::operator==( const Todo& t2 ) const
{
    return
        static_cast<const Incidence&>(*this) == static_cast<const Incidence&>(t2) &&
        dtDue() == t2.dtDue() &&
        hasDueDate() == t2.hasDueDate() &&
        hasStartDate() == t2.hasStartDate() &&
        completed() == t2.completed() &&
        hasCompletedDate() == t2.hasCompletedDate() &&
        percentComplete() == t2.percentComplete();
}

void Todo::setDtDue(const TQDateTime &dtDue, bool first )
{
  //int diffsecs = mDtDue.secsTo(dtDue);

  /*if (mReadOnly) return;
  const Alarm::List& alarms = alarms();
  for (Alarm* alarm = alarms.first(); alarm; alarm = alarms.next()) {
    if (alarm->enabled()) {
      alarm->setTime(alarm->time().addSecs(diffsecs));
    }
  }*/
  if( doesRecur() && !first ) {
    mDtRecurrence = dtDue;
  } else {
    mDtDue = dtDue;
    // TODO: This doesn't seem right...
    recurrence()->setStartDateTime( dtDue );
    recurrence()->setFloats( doesFloat() );
  }

  if ( doesRecur() && dtDue < recurrence()->startDateTime() )
    setDtStart( dtDue );

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

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

  updated();
}

TQDateTime Todo::dtDue( bool first ) const
{
  if ( doesRecur() && !first && mDtRecurrence.isValid() ) {
    return mDtRecurrence;
  } else if ( hasDueDate() ) {
    return mDtDue;
  } else {
    return TQDateTime();
  }
}

TQString Todo::dtDueTimeStr() const
{
  return TDEGlobal::locale()->formatTime( dtDue(!doesRecur()).time() );
}

TQString Todo::dtDueDateStr(bool shortfmt) const
{
  return TDEGlobal::locale()->formatDate(dtDue( !doesRecur() ).date(),shortfmt);
}

// TODO: Add shortfmt param!!!
TQString Todo::dtDueStr() const
{
  return TDEGlobal::locale()->formatDateTime( dtDue( !doesRecur() ) );
}

bool Todo::hasDueDate() const
{
  return mHasDueDate;
}

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


bool Todo::hasStartDate() const
{
  return mHasStartDate;
}

void Todo::setHasStartDate(bool f)
{
  if (mReadOnly) return;

  if ( doesRecur() && !f ) {
    if ( !comments().grep("NoStartDate").count() )
      addComment("NoStartDate"); //TODO: --> custom flag?
  } else {
    TQString s("NoStartDate");
    removeComment(s);
  }
  mHasStartDate = f;
  updated();
}

TQDateTime Todo::dtStart( bool first ) const
{
  if ( doesRecur() && !first ) {
    TQDateTime dt = mDtRecurrence.addDays( dtDue( true ).daysTo( IncidenceBase::dtStart() ) );

    // We want the dtStart's time, not dtDue's
    dt.setTime( IncidenceBase::dtStart().time() );
    return dt;
  } else if ( hasStartDate() ) {
    return IncidenceBase::dtStart();
  } else {
    return TQDateTime();
  }
}

void Todo::setDtStart( const TQDateTime &dtStart )
{
  // TODO: This doesn't seem right (rfc 2445/6 says, recurrence is calculated from the dtstart...)
  if ( doesRecur() ) {
    recurrence()->setStartDateTime( mDtDue );
    recurrence()->setFloats( doesFloat() );
  }
  IncidenceBase::setDtStart( dtStart );
}

TQString Todo::dtStartTimeStr( bool first ) const
{
  return TDEGlobal::locale()->formatTime(dtStart(first).time());
}

TQString Todo::dtStartDateStr(bool shortfmt, bool first) const
{
  return TDEGlobal::locale()->formatDate(dtStart(first).date(),shortfmt);
}

TQString Todo::dtStartStr(bool first) const
{
  return TDEGlobal::locale()->formatDateTime(dtStart(first));
}

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;
    mCompleted = TQDateTime();
  }
  updated();
}

TQDateTime Todo::completed() const
{
  if ( hasCompletedDate() )
    return mCompleted;
  else
    return TQDateTime();
}

TQString Todo::completedStr() const
{
  return TDEGlobal::locale()->formatDateTime(mCompleted);
}

void Todo::setCompleted(const TQDateTime &completed)
{
  if( !recurTodo() ) {
    mHasCompletedDate = true;
    mPercentComplete = 100;
    mCompleted = 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;
    mCompleted = TQDateTime();
  }

  updated();
}

void Todo::setDtRecurrence( const TQDateTime &dt )
{
  mDtRecurrence = dt;
}

TQDateTime Todo::dtRecurrence() const
{
  return mDtRecurrence.isValid() ? mDtRecurrence : mDtDue;
}

bool Todo::recursOn( const TQDate &date ) const
{
  TQDate today = TQDate::currentDate();
  return ( Incidence::recursOn(date) &&
           !( date < today && mDtRecurrence.date() < today &&
              mDtRecurrence > recurrence()->startDateTime() ) );
}

bool Todo::recurTodo()
{
  if ( doesRecur() ) {
    Recurrence *r = recurrence();
    TQDateTime endDateTime = r->endDateTime();
    TQDateTime nextDate = r->getNextDateTime( dtDue() );

    if ( ( r->duration() == -1 || ( nextDate.isValid() && endDateTime.isValid()
           && nextDate <= endDateTime ) ) ) {

      while ( !recursAt( nextDate ) || nextDate <= TQDateTime::currentDateTime() ) {

        if ( !nextDate.isValid() ||
             ( nextDate > endDateTime && r->duration() != -1 ) ) {
          return false;
        }

        nextDate = r->getNextDateTime( nextDate );
      }

      setDtDue( nextDate );
      setCompleted( false );
      setRevision( revision() + 1 );

      return true;
    }
  }

  return false;
}

bool Todo::isOverdue() const
{
  bool inPast = doesFloat() ? dtDue().date() < TQDate::currentDate()
                            : dtDue() < TQDateTime::currentDateTime();
  return ( inPast && !isCompleted() );
}
