/***************************************************************************
    copyright            : (C) 2003-2006 by Robby Stephenson
    email                : robby@periapsis.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of version 2 of the GNU General Public License as  *
 *   published by the Free Software Foundation;                            *
 *                                                                         *
 ***************************************************************************/

// this class borrows heavily from kdateedit.h in the tdepim module
// which is Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
// and published under the LGPL

#include "datewidget.h"

#include <kdebug.h>
#include <kcombobox.h>
#include <kpushbutton.h>
#include <kdatepicker.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <tdeglobalsettings.h>
#include <kcalendarsystem.h>

#include <tqvbox.h>
#include <tqlayout.h>

using Tellico::GUI::SpinBox;
using Tellico::GUI::DateWidget;

SpinBox::SpinBox(int min, int max, TQWidget *parent) : TQSpinBox(min, max, 1, parent)
{
  editor()->setAlignment(AlignRight);
  // I want to be able to omit the day
  // an empty string just removes the special value, so set white space
  setSpecialValueText(TQChar(' '));
}

DateWidget::DateWidget(TQWidget* parent_, const char* name_) : TQWidget(parent_, name_) {
  TQHBoxLayout* l = new TQHBoxLayout(this, 0, 4);

  TDELocale* locale = TDEGlobal::locale();

  // 0 allows empty value
  m_daySpin = new SpinBox(0, 31, this);
  l->addWidget(m_daySpin, 1);

  m_monthCombo = new KComboBox(false, this);
  l->addWidget(m_monthCombo, 1);
  // allow empty item
  m_monthCombo->insertItem(TQString());
  TQDate d;
  for(int i = 1; ; ++i) {
    TQString str = locale->calendar()->monthName(i, locale->calendar()->year(d));
    if(str.isNull()) {
      break;
    }
    m_monthCombo->insertItem(str);
  }

  m_yearSpin = new SpinBox(locale->calendar()->minValidYear(),
                           locale->calendar()->maxValidYear(), this);
  l->addWidget(m_yearSpin, 1);

  connect(m_daySpin, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(slotDateChanged()));
  connect(m_monthCombo, TQ_SIGNAL(activated(int)), TQ_SLOT(slotDateChanged()));
  connect(m_yearSpin, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(slotDateChanged()));

  m_dateButton = new KPushButton(this);
  m_dateButton->setIconSet(SmallIconSet(TQString::fromLatin1("date")));
  connect(m_dateButton, TQ_SIGNAL(clicked()), TQ_SLOT(slotShowPicker()));
  l->addWidget(m_dateButton, 0);

  m_frame = new TQVBox(0, 0, WType_Popup);
  m_frame->setFrameStyle(TQFrame::PopupPanel | TQFrame::Raised);
  m_frame->setLineWidth(3);
  m_frame->hide();

  m_picker = new KDatePicker(m_frame, 0); // must include name to get correct constructor
  connect(m_picker, TQ_SIGNAL(dateEntered(TQDate)), TQ_SLOT(slotDateEntered(TQDate)));
  connect(m_picker, TQ_SIGNAL(dateSelected(TQDate)), TQ_SLOT(slotDateSelected(TQDate)));
}

void DateWidget::slotDateChanged() {
  int day = m_daySpin->value();
  day = TQMIN(TQMAX(day, m_daySpin->minValue()), m_daySpin->maxValue());

  int m = m_monthCombo->currentItem();
  m = TQMIN(TQMAX(m, 0), m_monthCombo->count()-1);

  int y = m_yearSpin->value();
  y = TQMIN(TQMAX(y, m_yearSpin->minValue()), m_yearSpin->maxValue());

  // if all are valid, set this date
  if(day > m_daySpin->minValue() && m > 0 && y > m_yearSpin->minValue()) {
    TQDate d(y, m, day);
    setDate(d);
  }
  emit signalModified();
}

TQDate DateWidget::date() const {
  // possible for either day, month, or year to be empty
  // in which case a null date is returned
  int day = m_daySpin->value();
  // min value is the empty one
  if(day == m_daySpin->minValue()) {
    return TQDate();
  }
  int month = m_monthCombo->currentItem();
  if(month == 0) {
    return TQDate();
  }
  int year = m_yearSpin->value();
  if(year == m_yearSpin->minValue()) {
    return TQDate();
  }
  return TQDate(year, month, day);
}

TQString DateWidget::text() const {
  // possible for either day, month, or year to be empty
  // but not all three
  bool empty = true;
  // format is "year-month-day"
  TQString s;
  if(m_yearSpin->value() > m_yearSpin->minValue()) {
    s += TQString::number(m_yearSpin->value());
    empty = false;
  }
  s += '-';
  // first item is empty
  if(m_monthCombo->currentItem() > 0) {
    s += TQString::number(m_monthCombo->currentItem());
    empty = false;
  }
  s += '-';
  if(m_daySpin->value() > m_daySpin->minValue()) {
    s += TQString::number(m_daySpin->value());
    empty = false;
  }
  return empty ? TQString() : s;
}

void DateWidget::setDate(const TQDate& date_) {
  m_daySpin->blockSignals(true);
  m_monthCombo->blockSignals(true);
  m_yearSpin->blockSignals(true);

  const KCalendarSystem * calendar = TDEGlobal::locale()->calendar();
  m_daySpin->setMaxValue(calendar->daysInMonth(date_));
  m_daySpin->setValue(calendar->day(date_));
  m_monthCombo->setCurrentItem(calendar->month(date_)); // don't subtract 1 since there's the blank first item
  m_yearSpin->setValue(calendar->year(date_));

  m_daySpin->blockSignals(false);
  m_monthCombo->blockSignals(false);
  m_yearSpin->blockSignals(false);
}

void DateWidget::setDate(const TQString& date_) {
  m_daySpin->blockSignals(true);
  m_monthCombo->blockSignals(true);
  m_yearSpin->blockSignals(true);

  TQStringList s = TQStringList::split('-', date_, true);
  bool ok = true;
  int y = s.count() > 0 ? s[0].toInt(&ok) : m_yearSpin->minValue();
  if(!ok) {
    y = m_yearSpin->minValue();
    ok = true;
  }
  y = TQMIN(TQMAX(y, m_yearSpin->minValue()), m_yearSpin->maxValue());
  m_yearSpin->setValue(y);

  int m = s.count() > 1 ? s[1].toInt(&ok) : 0;
  if(!ok) {
    m = 0;
    ok = true;
  }
  m = TQMIN(TQMAX(m, 0), m_monthCombo->count()-1);
  m_monthCombo->setCurrentItem(m);

  // need to update number of days in month
  // for now set date to 1
  TQDate date(y, (m == 0 ? 1 : m), 1);
  m_daySpin->blockSignals(true);
  m_daySpin->setMaxValue(TDEGlobal::locale()->calendar()->daysInMonth(date));
  m_daySpin->blockSignals(false);

  int day = s.count() > 2 ? s[2].toInt(&ok) : m_daySpin->minValue();
  if(!ok) {
    day = m_daySpin->minValue();
  }
  day = TQMIN(TQMAX(day, m_daySpin->minValue()), m_daySpin->maxValue());
  m_daySpin->setValue(day);

  m_daySpin->blockSignals(false);
  m_monthCombo->blockSignals(false);
  m_yearSpin->blockSignals(false);

  // if all are valid, set this date
  if(day > m_daySpin->minValue() && m > 0 && y > m_yearSpin->minValue()) {
    TQDate d(y, m, day);
    m_picker->blockSignals(true);
    m_picker->setDate(d);
    m_picker->blockSignals(false);
  }
}

void DateWidget::clear() {
  m_daySpin->blockSignals(true);
  m_monthCombo->blockSignals(true);
  m_yearSpin->blockSignals(true);
  m_picker->blockSignals(true);

  m_daySpin->setValue(m_daySpin->minValue());
  m_monthCombo->setCurrentItem(0);
  m_yearSpin->setValue(m_yearSpin->minValue());
  m_picker->setDate(TQDate::currentDate());

  m_daySpin->blockSignals(false);
  m_monthCombo->blockSignals(false);
  m_yearSpin->blockSignals(false);
  m_picker->blockSignals(false);
}

void DateWidget::slotShowPicker() {
  TQRect desk = TDEGlobalSettings::desktopGeometry(this);
  TQPoint popupPoint = mapToGlobal(TQPoint(0, 0));

  int dateFrameHeight = m_frame->sizeHint().height();
  if(popupPoint.y() + height() + dateFrameHeight > desk.bottom()) {
    popupPoint.setY(popupPoint.y() - dateFrameHeight);
  } else {
    popupPoint.setY(popupPoint.y() + height());
  }
  int dateFrameWidth = m_frame->sizeHint().width();
  if(popupPoint.x() + dateFrameWidth > desk.right()) {
    popupPoint.setX(desk.right() - dateFrameWidth);
  }

  if(popupPoint.x() < desk.left()) {
    popupPoint.setX( desk.left());
  }
  if(popupPoint.y() < desk.top()) {
    popupPoint.setY(desk.top());
  }

  m_frame->move(popupPoint);

  TQDate d = date();
  if(d.isValid()) {
    m_picker->setDate(d);
  }

  m_frame->show();
}

void DateWidget::slotDateSelected(TQDate date_) {
  if(date_.isValid()) {
    setDate(date_);
    emit signalModified();
    m_frame->hide();
  }
}

void DateWidget::slotDateEntered(TQDate date_) {
  if(date_.isValid()) {
    setDate(date_);
    emit signalModified();
  }
}

#include "datewidget.moc"
