/*
 * Copyright (C) 2008-2009 GLAD!! (ITO Yoshiichi)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package jp.sourceforge.glad.calendar.text;

import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;

import jp.sourceforge.glad.calendar.CalendarConsts;
import jp.sourceforge.glad.calendar.util.ISOTimeZone;

/**
 * 
 * @author GLAD!!
 */
public class ISODateFormatSymbols extends DateFormatSymbols {

    private static final long serialVersionUID = -4362340578224494952L;

    static final String[] SHORT_MONTHS = {
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""
    };

    static final String[] WEEKDAYS = {
        "", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
    };

    static final String[] SHORT_WEEKDAYS = {
        "", "7", "1", "2", "3", "4", "5", "6"
    };

    static final String[][] ZONE_STRINGS = {};

    final Set<String> timeZoneIds = new HashSet<String>();

    public ISODateFormatSymbols() {
        this(Locale.getDefault());
    }

    public ISODateFormatSymbols(TimeZone... zones) {
        this(Locale.getDefault(), zones);
    }

    public ISODateFormatSymbols(Locale locale) {
        this(locale, TimeZone.getDefault(),
                CalendarConsts.JST,
                CalendarConsts.UTC);
    }

    public ISODateFormatSymbols(Locale locale, TimeZone... zones) {
        super(locale);
        super.setShortMonths(SHORT_MONTHS.clone());
        super.setWeekdays(WEEKDAYS.clone());
        super.setShortWeekdays(SHORT_WEEKDAYS.clone());
        super.setZoneStrings(ZONE_STRINGS);
        addZoneStrings(zones);
    }

    @Override
    public void setEras(String[] newEras) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void setMonths(String[] newMonths) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void setShortMonths(String[] newShortMonths) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void setWeekdays(String[] newWeekdays) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void setShortWeekdays(String[] newShortWeekdays) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void setAmPmStrings(String[] newAmpms) {
        super.setAmPmStrings(newAmpms);
    }

    @Override
    public void setZoneStrings(String[][] newZoneStrings) {
        timeZoneIds.clear();
        super.setZoneStrings(newZoneStrings);
        for (String[] info : newZoneStrings) {
            timeZoneIds.add(info[0]);
        }
    }

    public ISODateFormatSymbols addZoneStrings(String[]... zoneStrings) {
        if (zoneStrings.length == 0) {
            return this;
        }
        Map<String, String[]> map = new LinkedHashMap<String, String[]>();
        for (String[] info : zoneStrings) {
            String id = info[0];
            if (!timeZoneIds.contains(id) && !map.containsKey(id)) {
                map.put(id, info);
            }
        }
        if (map.isEmpty()) {
            return this;
        }
        String[][] oldZoneStrings = getZoneStrings();
        int index = oldZoneStrings.length;
        String[][] newZoneStrings = new String[index + map.size()][];
        System.arraycopy(oldZoneStrings, 0, newZoneStrings, 0, index);
        for (String[] info : map.values()) {
            newZoneStrings[index++] = info;
        }
        super.setZoneStrings(newZoneStrings);
        timeZoneIds.addAll(map.keySet());
        return this;
    }

    public ISODateFormatSymbols addZoneStrings(int offset) {
        addZoneStrings(ISOTimeZone.getInstance(offset));
        return this;
    }

    public ISODateFormatSymbols addZoneStrings(String id) {
        addZoneStrings(TimeZone.getTimeZone(id));
        return this;
    }

    public ISODateFormatSymbols addZoneStrings(TimeZone... zones) {
        if (zones.length == 0) {
            return this;
        }
        List<String[]> list = new ArrayList<String[]>();
        for (TimeZone zone: zones) {
            if (zone instanceof ISOTimeZone) {
                list.add(toZoneStrings(zone.getID(), (ISOTimeZone) zone));
            } else {
                ISOTimeZone iso = ISOTimeZone.getInstance(zone);
                list.add(toZoneStrings(iso.getID(), iso));
                list.add(toZoneStrings(zone.getID(), iso));
            }
        }
        String[][] zoneStrings = list.toArray(new String[list.size()][]);
        addZoneStrings(zoneStrings);
        return this;
    }

    static String[] toZoneStrings(String id, ISOTimeZone zone) {
        return new String[] {
            id,
            zone.getDisplayName(TimeZone.LONG),
            zone.getDisplayName(TimeZone.SHORT),
            zone.getDisplayName(TimeZone.LONG),
            zone.getDisplayName(TimeZone.SHORT)
        };
    }

    @Override
    public void setLocalPatternChars(String newLocalPatternChars) {
        throw new UnsupportedOperationException();
    }

    @Override
    public ISODateFormatSymbols clone() {
        return (ISODateFormatSymbols) super.clone();
    }

}
