/**
 * SchemaCalendarBase.java This file was generated by XMLSpy 2006sp2 Enterprise
 * Edition. YOU SHOULD NOT MODIFY THIS FILE, BECAUSE IT WILL BE OVERWRITTEN WHEN
 * YOU RE-RUN CODE GENERATION. Refer to the XMLSpy Documentation for further
 * details. http://www.altova.com/xmlspy
 */

package com.jmex.model.collada.types;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public abstract class SchemaCalendarBase implements SchemaTypeCalendar {
    public static final int TZ_MISSING = 0;
    public static final int TZ_UTC = 1;
    public static final int TZ_OFFSET = 2;

    protected int year;
    protected int month;
    protected int day;
    protected int hour;
    protected int minute;
    protected int second;
    protected double partsecond; // 0.0 <= partsecond < 1.0
    protected int hasTZ;
    protected int offsetTZ; // offset in minutes
    protected boolean isempty;

    public SchemaCalendarBase() {
        setEmpty();
    }

    public void setNull() {
        setEmpty();
    }

    public void setEmpty() {
        isempty = true;
        setInternalValues(0, 0, 0, 0, 0, 0, 0.0, TZ_MISSING, 0);
    }

    public boolean equals(Object obj) {
        if (!(obj instanceof SchemaCalendarBase))
            return false;
        SchemaCalendarBase dt = (SchemaCalendarBase) obj;
        if (!(year == dt.year))
            return false;
        if (!(month == dt.month))
            return false;
        if (!(day == dt.day))
            return false;
        if (!(hour == dt.hour))
            return false;
        if (!(minute == dt.minute))
            return false;
        if (!(second == dt.second))
            return false;
        if (!(partsecond == dt.partsecond))
            return false;
        if (!(hasTZ == dt.hasTZ))
            return false;
        if (!(offsetTZ == dt.offsetTZ))
            return false;
        return true;
    }

    public int hashCode() {
        return (int) Double.doubleToLongBits(getApproximatedTotal());
    }

    public String toDateString() {
        StringBuffer s = new StringBuffer();
        s.append(new DecimalFormat("0000").format(year));
        s.append("-");
        s.append(new DecimalFormat("00").format(month));
        s.append("-");
        s.append(new DecimalFormat("00").format(day));
        return s.toString();
    }

    public String toTimeString() {
        StringBuffer s = new StringBuffer();
        s.append(new DecimalFormat("00").format(hour));
        s.append(":");
        s.append(new DecimalFormat("00").format(minute));
        s.append(":");
        s.append(new DecimalFormat("00").format(second));
        if (partsecond > 0 && partsecond < 1) {
            String sPartSecond = new DecimalFormat("0.0###############")
                    .format(partsecond);
            s.append(".");
            s.append(sPartSecond.substring(2, sPartSecond.length()));
        }
        if (hasTZ == TZ_UTC) {
            s.append("Z");
        } else if (hasTZ == TZ_OFFSET) {
            int absOffsetTZ = offsetTZ;
            if (offsetTZ < 0) {
                s.append("-");
                absOffsetTZ = -offsetTZ;
            } else
                s.append("+");
            s.append(new DecimalFormat("00").format(absOffsetTZ / 60));
            s.append(":");
            s.append(new DecimalFormat("00").format(absOffsetTZ % 60));
        }
        return s.toString();
    }

    public int length() {
        return toString().length();
    }

    public boolean booleanValue() {
        return true;
    }

    public boolean isEmpty() {
        return isempty;
    }

    public boolean isNull() {
        return isEmpty();
    }

    public int compareTo(Object obj) {
        return compareTo((SchemaCalendarBase) obj);
    }

    public int compareTo(SchemaCalendarBase obj) {
        return (int) (getApproximatedTotal() - obj.getApproximatedTotal());
    }

    protected void parseDate(String newvalue) throws StringParseException {
        if (newvalue.length() == 0)
            isempty = true;
        else if (newvalue.length() < 10)
            throw new StringParseException("date-part of string is too short",
                    0);
        else {
            try {
                int nStart = 0;
                if (newvalue.substring(0, 1).equals("-"))
                    nStart = 1;
                year = Integer.parseInt(newvalue.substring(0, nStart + 4));
                if (!newvalue.substring(nStart + 4, nStart + 5).equals("-"))
                    throw new StringParseException("invalid date format", 2);
                month = Integer.parseInt(newvalue.substring(nStart + 5,
                        nStart + 7));
                if (!newvalue.substring(nStart + 7, nStart + 8).equals("-"))
                    throw new StringParseException("invalid date format", 2);
                day = Integer.parseInt(newvalue.substring(nStart + 8, newvalue
                        .length()));
            } catch (NumberFormatException e) {
                throw new StringParseException("invalid date format", 2);
            }
            isempty = false;
        }
    }

    protected void parseTime(String newvalue) throws StringParseException {
        if (newvalue.length() < 8)
            throw new StringParseException("time-part of string is too short",
                    0);
        try {
            int nStart = 0;
            hour = Integer.parseInt(newvalue.substring(nStart, nStart + 2));
            if (!newvalue.substring(nStart + 2, nStart + 3).equals(":"))
                throw new StringParseException("invalid date format", 2);
            minute = Integer.parseInt(newvalue
                    .substring(nStart + 3, nStart + 5));
            if (!newvalue.substring(nStart + 5, nStart + 6).equals(":"))
                throw new StringParseException("invalid date format", 2);
            second = Integer.parseInt(newvalue
                    .substring(nStart + 6, nStart + 8));
            int nTZStartPosition = nStart + 8;
            partsecond = 0;
            if (newvalue.length() > (nStart + 8)) {
                nStart = nTZStartPosition;
                int nEnd = newvalue.length();
                int nMSecEnd = newvalue.indexOf("Z", nStart);
                if (nMSecEnd > -1 && nMSecEnd < nEnd)
                    nEnd = nMSecEnd;
                nMSecEnd = newvalue.indexOf("+", nStart);
                if (nMSecEnd > -1 && nMSecEnd < nEnd)
                    nEnd = nMSecEnd;
                nMSecEnd = newvalue.indexOf("-", nStart);
                if (nMSecEnd > -1 && nMSecEnd < nEnd)
                    nEnd = nMSecEnd;
                nTZStartPosition = nEnd;
                partsecond = Double.parseDouble("0"
                        + newvalue.substring(nStart, nEnd));
            }
            hasTZ = TZ_MISSING;
            offsetTZ = 0;
            if (newvalue.length() > nTZStartPosition
                    && newvalue.substring(nTZStartPosition,
                            nTZStartPosition + 1).equals("Z"))
                hasTZ = TZ_UTC;
            else if (newvalue.length() == nTZStartPosition + 6) {
                hasTZ = TZ_OFFSET;
                offsetTZ = Integer.parseInt(newvalue.substring(
                        nTZStartPosition + 1, nTZStartPosition + 3))
                        * 60
                        + Integer.parseInt(newvalue.substring(
                                nTZStartPosition + 4, nTZStartPosition + 6));
                if (newvalue.substring(nTZStartPosition, nTZStartPosition + 1)
                        .equals("-"))
                    offsetTZ = -offsetTZ;
            }
        } catch (NumberFormatException e) {
            throw new StringParseException("invalid number format", 2);
        }
        isempty = false;
    }

    public double getApproximatedTotal() {
        // approximated because month is approximated to have always 31 days.
        return second
                + 60.0
                * (minute + 60.0 * (hour + 24.0 * (day + 31.0 * (month + 12.0 * year))))
                + partsecond;
    }

    public Date getDate() {
        String s = toDateString() + " " + toTimeString();
        try {
            return (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(s));
        } catch (java.text.ParseException e) {
            throw new StringParseException("Could not convert to date.", 0);
        }
    }

    protected void setInternalValues(int newyear, int newmonth, int newday,
            int newhour, int newminute, int newsecond, double newpartsecond,
            int newhasTZ, int newoffsetTZ) {
        year = newyear;
        month = newmonth;
        day = newday;
        hour = newhour;
        minute = newminute;
        second = newsecond;
        partsecond = newpartsecond;
        hasTZ = newhasTZ;
        offsetTZ = newoffsetTZ;
        isempty = false;
    }

    // ---------- interface SchemaTypeCalendar ----------
    public SchemaDuration durationValue() {
        throw new TypesIncompatibleException(this, new SchemaDuration("PT"));
    }

}
