// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2007 Koen Deforche, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef WCALENDAR_H_
#define WCALENDAR_H_

#include <WCompositeWidget>
#include <WDate>
#include <set>

namespace boost {
  namespace gregorian {
    class date;
  }
}

namespace Wt {

class WTable;
class WComboBox;
class WInPlaceEdit;
template <typename T> class WSignalMapper;

/*! \class WCalendar WCalendar WCalendar
 *  \brief A calendar.
 *
 * The calendar provides navigation by month and year, and indicates the
 * current day.
 *
 * A single or multiple days may be selected on the calendar, and you
 * may listen for changes in the selection using the selectionChanged
 * signal.
 *
 * Internationalization may be provided by indicating i18n == true in the 
 * constructor, and providing the appropriate messages for months and days
 * in your message resource bundle.
 *
 * The look can be overridden using the following style class selectors:
 * <pre>
TABLE.Wt-cal-table        : The table

TD.Wt-cal-header          : Header cell (week day)
TD.Wt-cal-header-weekend  : Header cell (weekend day)

TABLE.Wt-cal-table TD     : In-month day cell
TD.Wt-cal-oom             : Out-of-month day cell
TD.Wt-cal-sel             : Selected day cell
TD.Wt-cal-now             : Today day cell
 * </pre>
 */
class WT_API WCalendar : public WCompositeWidget
{
public:
  /*! \brief Create a new calendar.
   *
   * Constructs a new calendar, with optional support for internationalization.
   * The calendar shows the current day, and has an empty selection.
   */
  WCalendar(bool i18n = false, WContainerWidget *parent = 0);

  /*! \brief Configure single or multiple selection mode.
   */
  void setMultipleSelection(bool multiple);

  /*! \brief Browse to the same month in the previous year.
   */
  void browseToPreviousYear();

  /*! \brief Browse to the previous month.
   */
  void browseToPreviousMonth();

  /*! \brief Browse to the same month in the next year.
   */
  void browseToNextYear();

  /*! \brief Browse to the next month.
   */
  void browseToNextMonth();

  /*! \brief Browse to a date.
   */
  void browseTo(const WDate& date);

  /*! \brief Current month displayed
   */
  int currentMonth() const { return currentMonth_; }

  /*! \brief Current year displayed
   */
  int currentYear() const { return currentYear_; }

  /*! \brief Clear the current selection.
   */
  void clearSelection();

  /*! \brief Select a date.
   */
  void select(const WDate& date);

  /*! \brief Select multiple dates.
   */
  void select(const std::set<WDate>& dates);

  /*! \brief Get the current selection.
   */
  const std::set<WDate>& selection() const { return selection_; }

  /*! \brief Signal emitted when the user changes the selection.
   */
  Signal<void> selectionChanged;

  /*! \brief Signal emitted when the user has double clicked on a date.
   *
   * This is only available when not in multiple selection mode.
   */
  Signal<void> selected;

private:
  bool              i18n_;
  bool              multipleSelection_;
  int               currentYear_;
  int               currentMonth_;
  std::set<WDate>   selection_;

  WContainerWidget                    *layout_;
  WComboBox                           *monthEdit_;
  WInPlaceEdit                        *yearEdit_;
  WTable                              *calendar_;
  WSignalMapper<std::pair<int, int> > *cellClickMapper_;
  WSignalMapper<std::pair<int, int> > *cellDblClickMapper_;

  void create();
  void renderMonth(bool create = false);

  void monthChanged(int newMonth);
  void yearChanged(WString newYear);
  boost::gregorian::date dateForCell(int week, int dayOfWeek);
  bool isSelected(const WDate& d) const;

  void cellClicked(std::pair<int, int>);

  bool selectInCurrentMonth(const boost::gregorian::date& dt);

  void cellDblClicked(std::pair<int, int>);

  static const char *days_[];
  static const char *months_[];
};

}

#endif // WCALENDAR_H_
