/***************************************************************************
 GanttLanguage.java  -  description
 -------------------
 begin                : jan 2003
 copyright            : (C) 2003 by Thomas Alexandre
 email                : alexthomas(at)ganttproject.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

package net.sourceforge.ganttproject.language;

import java.awt.ComponentOrientation;
import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.EventListener;
import java.util.EventObject;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.TimeZone;

import javax.swing.UIManager;

import net.sourceforge.ganttproject.GanttCalendar;
import net.sourceforge.ganttproject.gui.options.model.DefaultDateOption;
import net.sourceforge.ganttproject.gui.options.model.GPOption;
import net.sourceforge.ganttproject.gui.options.model.GPOptionGroup;
import net.sourceforge.ganttproject.time.gregorian.GregorianCalendar;

/**
 * Class for the language
 */
public class GanttLanguage {

    public class Event extends EventObject {
        public Event(GanttLanguage language) {
            super(language);
        }

        public GanttLanguage getLanguage() {
            return (GanttLanguage) getSource();
        }

    }

    public interface Listener extends EventListener {
        public void languageChanged(Event event);
    }

    private static GanttLanguage ganttLanguage = null;

    private ArrayList myListeners = new ArrayList();

    public static GanttLanguage getInstance() {
        if (ganttLanguage == null) {
            ganttLanguage = new GanttLanguage();
        }
        return ganttLanguage;
    }

    Locale currentLocale = null;

    ResourceBundle i18n = null;

    SimpleDateFormat currentDateFormat = null;
    public DateFormat getMediumDateFormat() {
        return currentDateFormat;
    }

    SimpleDateFormat shortCurrentDateFormat = null;
    public DateFormat getShortDateFormat() {
        return shortCurrentDateFormat;
    }
    
    SimpleDateFormat myLongFormat;
    public DateFormat getLongDateFormat() {
        return myLongFormat;
    }
    
    DateFormat myTimeFormat = null;

    //private DateFormat myTimeFormat;

    private DefaultDateOption myDayStartOption;
    private DefaultDateOption myDayEndOption;
    private GPOptionGroup myBusinessHoursGroup;
    
    public static final String MISSING_RESOURCE = "Missing Resource";

    private GanttLanguage() {
        setLocale(Locale.getDefault());
        int defaultTimezoneOffset = TimeZone.getDefault().getRawOffset() + TimeZone.getDefault().getDSTSavings();

        Calendar c = Calendar.getInstance();
        TimeZone utc = TimeZone.getTimeZone("UTC");
        utc.setRawOffset(defaultTimezoneOffset);
        TimeZone.setDefault(utc);
        
        {
            c = newCalendar();
            c.clear();
            c.set(Calendar.HOUR, 9);
            myDayStartOption = new DefaultDateOption("projectwizard.dayStart", c.getTime()) 
            {
                @Override
                public DateFormat getDateFormat() {
                    return GanttLanguage.this.getTimeFormat();
                }
            };
            c.set(Calendar.HOUR, 18);
            myDayEndOption = new DefaultDateOption("projectwizard.dayEnd", c.getTime()) 
            {
                @Override
                public DateFormat getDateFormat() {
                    return GanttLanguage.this.getTimeFormat();
                }
            };
        }
        myBusinessHoursGroup = new GPOptionGroup("projectwizard.businessHours", new GPOption[] {myDayStartOption, myDayEndOption});
    }

    public void setLocale(Locale locale) {
        
        currentLocale = locale;
        Locale.setDefault(locale);
        currentDateFormat = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.MEDIUM,
                currentLocale);
        shortCurrentDateFormat = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT,
                currentLocale);
        myTimeFormat = DateFormat.getTimeInstance(DateFormat.SHORT, currentLocale);
        myLongFormat = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.LONG, locale);
        UIManager.put("JXDatePicker.longFormat", myLongFormat.toPattern());
        UIManager.put("JXDatePicker.mediumFormat", currentDateFormat.toPattern());
        UIManager.put("JXDatePicker.shortFormat", shortCurrentDateFormat.toPattern());
        UIManager.put("JXDatePicker.numColumns", new Integer(10));
        String[] dayShortNames = new String[7];
        for (int i=0; i<7; i++) {
            dayShortNames[i] = getDay(i).substring(0, 1);
        }
        UIManager.put("JXMonthView.daysOfTheWeek", dayShortNames);
        String resourceBase = System.getProperty(
                "org.ganttproject.resourcebase", "language/i18n");
        i18n = ResourceBundle.getBundle(resourceBase, currentLocale);
        fireLanguageChanged();
    }

    /**
     * Return the current Locale.
     * 
     * @return The current Locale.
     */
    public Locale getLocale() {
        return currentLocale;
    }

    public DateFormat getTimeFormat() {
        return myTimeFormat;
    }
    /**
     * Return the current DateFormat.
     * 
     * @return The current DateFormat.
     */
    public DateFormat getDateFormat() {
        return currentDateFormat;
    }

    public String formatDate(GanttCalendar date) {
        return currentDateFormat.format(date.getTime());
    }

    public String formatShortDate(GanttCalendar date)
    {
        return shortCurrentDateFormat.format(date.getTime());
    }
    
    public String formatTime(GanttCalendar date) {
        return myTimeFormat.format(date.getTime());
    }

    public GanttCalendar parseDate(String date) throws ParseException {
        Calendar tmp = Calendar.getInstance(currentLocale);
        tmp.setTime(currentDateFormat.parse(date));
        return new GanttCalendar(tmp.get(Calendar.YEAR), tmp
                .get(Calendar.MONTH), tmp.get(Calendar.DATE));
    }

    public String getMonth(int m) {
        GregorianCalendar month = new GregorianCalendar(2000, m, 1);
        SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM",
                this.currentLocale);
        StringBuffer result = new StringBuffer();
        result = dateFormat.format(month.getTime(), result, new FieldPosition(
                DateFormat.MONTH_FIELD));
        return result.toString();
    }

    public String getDay(int d) {
        GregorianCalendar day = new GregorianCalendar(2000, 1, 1);
        while (day.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
            day.add(Calendar.DATE, 1);
        }
        day.add(Calendar.DATE, d);

        SimpleDateFormat dateFormat = new SimpleDateFormat("EEE",
                this.currentLocale);
        StringBuffer result = new StringBuffer();
        result = dateFormat.format(day.getTime(), result, new FieldPosition(
                DateFormat.DAY_OF_WEEK_FIELD));
        return result.toString();
    }

    public String getText(String key) {
        try {
            return i18n.getString(key);
        } catch (MissingResourceException e) {
            return MISSING_RESOURCE + " '" + key + "'";
        }
    };

    public ComponentOrientation getComponentOrientation() {
        return ComponentOrientation.getOrientation(currentLocale);
    }

    public void addListener(Listener listener) {
        myListeners.add(listener);
    }

    public void removeListener(Listener listener) {
        myListeners.remove(listener);
    }

    private void fireLanguageChanged() {
        Event event = new Event(this);
        for (int i = 0; i < myListeners.size(); i++) {
            Listener next = (Listener) myListeners.get(i);
            next.languageChanged(event);
        }
    }

    public SimpleDateFormat createDateFormat(String string) {
        return new SimpleDateFormat(string, currentLocale);
    }

    public String correctLabel(String label) {
        int index = label.indexOf('$');
        if (index != -1 && label.length() - index > 1) {
            label = label.substring(0, index).concat(label.substring(++index));
        }
        return label;
    }

    public Calendar newCalendar() {
        return (Calendar) Calendar.getInstance(getLocale()).clone();
    }

    public Date getBusinessHoursStart() {
        return myDayStartOption.getValue();
    }
    public Date getBusinessHoursEnd() {
        return myDayEndOption.getValue();
    }

    public GPOptionGroup[] getL10NOptions() {
        return new GPOptionGroup[] {getBusinessHoursOptions()};
    }

    public GPOptionGroup getBusinessHoursOptions() {
        return myBusinessHoursGroup;
    }
}
