/*
 * Java-Gnome Bindings Library
 *
 * Copyright 1998-2004 the Java-Gnome Team, all rights reserved.
 *
 * The Java-Gnome bindings library is free software distributed under
 * the terms of the GNU Library General Public License version 2.
 */

package org.gnu.gtk;

import java.util.Vector;

import org.gnu.glib.EventMap;
import org.gnu.glib.EventType;
import org.gnu.glib.GObject;
import org.gnu.glib.Type;
import org.gnu.gtk.event.CalendarEvent;
import org.gnu.gtk.event.CalendarListener;
import org.gnu.glib.Handle;

/**
 * A Calendar is a widget that displays a calendar one month at a time.
 *
 * @deprecated This class is part of the java-gnome 2.x family of libraries,
 *             which, due to their inefficiency and complexity, are no longer
 *             being maintained and have been abandoned by the java-gnome
 *             project. This class may in the future have an equivalent in
 *             java-gnome 4.0, try looking for
 *             <code>org.gnome.gtk.Calendar</code>.
 *             You should be aware that there is a considerably different API
 *             in the new library: the architecture is completely different
 *             and most notably internals are no longer exposed to public view.
 */
public class Calendar extends Widget {

    /**
     * Create a new Calendar object with the current date selected.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public Calendar() {
        super(gtk_calendar_new());
    }

    /**
     * Construct a calendar using a handle to a native resource.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public Calendar(Handle handle) {
        super(handle);
    }

    /**
     * Internal static factory method to be used by Java-Gnome only.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public static Calendar getCalendar(Handle handle) {
        if (handle == null) {
            return null;
        }

        Calendar obj = (Calendar) GObject.getGObjectFromHandle(handle);

        if (obj == null) {
            obj = new Calendar(handle);
        }

        return obj;
    }

    /**
     * Shifts the calendar to a different month.
     * 
     * @param month
     *            The month to select. This value is zero based.
     * @param year
     *            The year the month is in.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public void selectMonth(int month, int year) {
        Calendar.gtk_calendar_select_month(getHandle(), month, year);
    }

    /**
     * Selects a day from the current month.
     * 
     * @param day
     *            A day number between 1 and 31, or 0 to unselect the currently
     *            selected day.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public void selectDay(int day) {
        Calendar.gtk_calendar_select_day(getHandle(), day);
    }

    /**
     * Places a visual marker on a particular day.
     * 
     * @param day
     *            The day number to mark between 1 and 31.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public void markDay(int day) {
        Calendar.gtk_calendar_mark_day(getHandle(), day);
    }

    /**
     * Removes the visual marker from a particular day.
     * 
     * @param day
     *            The day number to unmark between 1 and 31.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public void unmarkDay(int day) {
        Calendar.gtk_calendar_unmark_day(getHandle(), day);
    }

    /**
     * Remove all visual marks.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public void clearMarks() {
        Calendar.gtk_calendar_clear_marks(getHandle());
    }

    /**
     * Sets the display options (whether to display the heading and the month
     * headings.
     * 
     * @param displayOptions
     *            The options to set.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public void setDisplayOptions(CalendarDisplayOptions displayOptions) {
        gtk_calendar_set_display_options(getHandle(), displayOptions.getValue());
    }

    /**
     * Gets the display options (whether to display the heading and the month
     * headings.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public CalendarDisplayOptions getDisplayOptions() {
        return CalendarDisplayOptions
                .intern(gtk_calendar_get_display_options(getHandle()));
    }

    /**
     * Gets the selected date from a Calendar.
     * <p>
     * <i>Historical note: getDate() used to return java.util.Calendar. This
     * caused some class library implementations to fault in their entire
     * TimeZone subsystems which led to a very deep bug on some architectures.
     * This method was therefore changed as of libgtk-java 2.10 to the int[3]
     * implementation here.</i>
     * </p>
     * 
     * @return a three wide array of integers: the array at [0] is the year (4
     *         digits), the array at [1] is the month (range from 1-12), and the
     *         array at [2] is the numeric day (range from 1-{28,29,30,31}).
     * @since 2.10
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public int[] getDate() {
        int[] in = new int[3];
        int[] out = new int[3];

        Calendar.gtk_calendar_get_date(getHandle(), in);

        // necessary to use intermediate variables otherwise you can get memory
        // problems.
        int year = in[0];
        int month = in[1] + 1;
        int day = in[2];

        out[0] = year;
        out[1] = month;
        out[2] = day;

        return out;
    }

    /**
     * Locks the display of the Calendar until it is thawed with the
     * <code>thaw()</code> method.
     * 
     * @deprecated
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public void freeze() {
        Calendar.gtk_calendar_freeze(getHandle());
    }

    /**
     * Defrosts a Calendar. All changes made since the last
     * <code>freeze()</code> are displayed.
     * 
     * @deprecated
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public void thaw() {
        Calendar.gtk_calendar_thaw(getHandle());
    }

    /***************************************************************************
     * EVENT LISTENERS
     **************************************************************************/

    /**
     * Listeners for handling calendar events
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    private Vector calendarListeners = null;

    /**
     * Register an object to handle calendar events.
     * 
     * @see org.gnu.gtk.event.CalendarListener
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public void addListener(CalendarListener listener) {
        // Don't add the listener a second time if it is in the Vector.
        int i = findListener(calendarListeners, listener);
        if (i == -1) {
            if (null == calendarListeners) {
                evtMap.initialize(this, CalendarEvent.Type.DAY_SELECTED);
                evtMap.initialize(this,
                        CalendarEvent.Type.DAY_SELECTED_DOUBLE_CLICK);
                evtMap.initialize(this, CalendarEvent.Type.MONTH_CHANGED_NEXT);
                evtMap.initialize(this, CalendarEvent.Type.MONTH_CHANGED_PREV);
                evtMap.initialize(this, CalendarEvent.Type.YEAR_CHANGED_NEXT);
                evtMap.initialize(this, CalendarEvent.Type.YEAR_CHANGED_PREV);
                calendarListeners = new Vector();
            }
            calendarListeners.addElement(listener);
        }
    }

    /**
     * Removes a listener
     * 
     * @see #addListener(CalendarListener)
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public void removeListener(CalendarListener listener) {
        int i = findListener(calendarListeners, listener);
        if (i > -1) {
            calendarListeners.remove(i);
        }
        if (0 == calendarListeners.size()) {
            evtMap.uninitialize(this, CalendarEvent.Type.DAY_SELECTED);
            evtMap.uninitialize(this,
                    CalendarEvent.Type.DAY_SELECTED_DOUBLE_CLICK);
            evtMap.uninitialize(this, CalendarEvent.Type.MONTH_CHANGED_NEXT);
            evtMap.uninitialize(this, CalendarEvent.Type.MONTH_CHANGED_PREV);
            evtMap.uninitialize(this, CalendarEvent.Type.YEAR_CHANGED_NEXT);
            evtMap.uninitialize(this, CalendarEvent.Type.YEAR_CHANGED_PREV);
            calendarListeners = null;
        }
    }

    private void fireCalendarEvent(CalendarEvent event) {
        if (null == calendarListeners) {
            return;
        }
        int size = calendarListeners.size();
        int i = 0;
        while (i < size) {
            CalendarListener cl = (CalendarListener) calendarListeners
                    .elementAt(i);
            cl.calendarEvent(event);
            i++;
        }
    }

    private void handleDaySelected() {
        fireCalendarEvent(new CalendarEvent(this,
                CalendarEvent.Type.DAY_SELECTED));
    }

    private void handleDaySelectedDC() {
        fireCalendarEvent(new CalendarEvent(this,
                CalendarEvent.Type.DAY_SELECTED_DOUBLE_CLICK));
    }

    private void handleNextMonth() {
        fireCalendarEvent(new CalendarEvent(this,
                CalendarEvent.Type.MONTH_CHANGED_NEXT));
    }

    private void handlePrevMonth() {
        fireCalendarEvent(new CalendarEvent(this,
                CalendarEvent.Type.MONTH_CHANGED_PREV));
    }

    private void handleNextYear() {
        fireCalendarEvent(new CalendarEvent(this,
                CalendarEvent.Type.YEAR_CHANGED_NEXT));
    }

    private void handlePrevYear() {
        fireCalendarEvent(new CalendarEvent(this,
                CalendarEvent.Type.YEAR_CHANGED_PREV));
    }

    public Class getEventListenerClass(String signal) {
        Class cls = evtMap.getEventListenerClass(signal);
        if (cls == null)
            cls = super.getEventListenerClass(signal);
        return cls;
    }

    public EventType getEventType(String signal) {
        EventType et = evtMap.getEventType(signal);
        if (et == null)
            et = super.getEventType(signal);
        return et;
    }

    private static EventMap evtMap = new EventMap();
    static {
        addEvents(evtMap);
    }

    /**
     * Implementation method to build an EventMap for this widget class. Not
     * useful (or supported) for application use.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    private static void addEvents(EventMap anEvtMap) {
        anEvtMap.addEvent("day_selected", "handleDaySelected",
                CalendarEvent.Type.DAY_SELECTED, CalendarListener.class);
        anEvtMap.addEvent("day_selected_double_click", "handleDaySelectedDC",
                CalendarEvent.Type.DAY_SELECTED_DOUBLE_CLICK,
                CalendarListener.class);
        anEvtMap.addEvent("next_year", "handleNextYear",
                CalendarEvent.Type.YEAR_CHANGED_NEXT, CalendarListener.class);
        anEvtMap.addEvent("prev_year", "handlePrevYear",
                CalendarEvent.Type.YEAR_CHANGED_PREV, CalendarListener.class);
        anEvtMap.addEvent("next_month", "handleNextMonth",
                CalendarEvent.Type.MONTH_CHANGED_NEXT, CalendarListener.class);
        anEvtMap.addEvent("prev_month", "handlePrevMonth",
                CalendarEvent.Type.MONTH_CHANGED_PREV, CalendarListener.class);
    }

    /**
     * Retrieve the runtime type used by the GLib library.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public static Type getType() {
        return new Type(gtk_calendar_get_type());
    }

    native static final protected int gtk_calendar_get_type();

    native static final protected Handle gtk_calendar_new();

    native static final protected int gtk_calendar_select_month(
            Handle calendar, int month, int year);

    native static final protected void gtk_calendar_select_day(Handle calendar,
            int day);

    native static final protected int gtk_calendar_mark_day(Handle calendar,
            int day);

    native static final protected int gtk_calendar_unmark_day(Handle calendar,
            int day);

    native static final protected void gtk_calendar_clear_marks(Handle calendar);

    native static final protected void gtk_calendar_set_display_options(
            Handle calendar, int flags);

    native static final protected int gtk_calendar_get_display_options(
            Handle calendar);

    native static final private void gtk_calendar_get_date(Handle calendar,
            int[] triple);

    native static final protected void gtk_calendar_freeze(Handle calendar);

    native static final protected void gtk_calendar_thaw(Handle calendar);

    /*
     * Deprecated functions. native static final private void
     * gtk_calendar_display_options(Handle calendar, int flags);
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
}
