package com.sandbox.client;

import java.util.Date;
import java.util.LinkedHashMap;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.types.TimeUnit;
import com.smartgwt.client.util.DateDisplayFormatter;
import com.smartgwt.client.util.DateParser;
import com.smartgwt.client.util.DateUtil;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.RelativeDateItem;
import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
import com.smartgwt.client.widgets.layout.HLayout;

public class Sandbox2 implements EntryPoint {
    private RelativeDateItem dateItemField;
    public static final String DATE_ONLY_FORMAT = "yyyy-MM-dd";
    public static final String DATE_ONLY_FORMAT_ISO = "yyyyMMdd";
    public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_TIME_FORMAT_Z = "yyyy-MM-dd HH:mm:ss Z";
    public static final String DATE_TIME_FORMAT_ISO8601_Z = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZ";
    public static final String DATE_TIME_FORMAT_ISO8601 = "yyyy-MM-dd'T'HH:mm:ss.SSS";

    private final static LinkedHashMap<String, String> theDatePresets = new LinkedHashMap<String, String>();

    private final DateTimeFormat dateFormatter = DateTimeFormat.getFormat(DATE_TIME_FORMAT_Z);

    static {
        theDatePresets.put("$now", "Now");
        theDatePresets.put("$today", "Today");
        theDatePresets.put("$yesterday", "Yesterday");
        theDatePresets.put("$tomorrow", "Tomorrow");
        theDatePresets.put("-1w", "Current day of last week");
        theDatePresets.put("+1w", "Current day of next week");
        theDatePresets.put("+1m", "Current day of next month");
        theDatePresets.put("-1m", "Current day of last month");
    }

    @Override
    public void onModuleLoad() {
        HLayout layout = new HLayout();

        changeDateFormat();

        DynamicForm form = new DynamicForm();

        form.setFields(getDateItem());
        layout.addMember(form);
        layout.draw();
    }

    private void changeDateFormat() {
        DateUtil.setShortDatetimeDisplayFormatter(new DateDisplayFormatter() {
            public String format(Date date) {
                if (date == null) {
                    GWT.log("date is null");
                    return null;
                }
                String dateStr = dateFormatter.format(date);
                GWT.log("Short - Formatted date: (" + date + ") -> " + dateStr);
                return dateStr;
            }
        });

        DateUtil.setNormalDatetimeDisplayFormatter(new DateDisplayFormatter() {
            public String format(Date date) {
                if (date == null) {
                    GWT.log("date is null");
                    return null;
                }
                String dateStr = dateFormatter.format(date);
                GWT.log("Normal - Formatted date: (" + date + ") -> " + dateStr);
                return dateStr;
            }
        });

        DateUtil.setDateParser(new DateParser() {
            @Override
            public Date parse(String dateString) {
                return parseDate(dateString);
            }
        });

    }

    private RelativeDateItem getDateItem() {
        if (dateItemField == null) {
            dateItemField = new RelativeDateItem("some_date");
            dateItemField.setTitle("Test Date Time");
            dateItemField.setShowFutureOptions(false);
            dateItemField.setShowPastOptions(true);
            dateItemField.setTimeUnitOptions(getTimeOptions());
            dateItemField.setDefaultQuantity(1);
            dateItemField.setPresetOptions(theDatePresets);
            dateItemField.setOverflow(Overflow.VISIBLE);
            dateItemField.setType("datetime");
            dateItemField.setWrapTitle(Boolean.FALSE);

            dateItemField.addChangedHandler(new ChangedHandler() {
                @Override
                public void onChanged(ChangedEvent event) {
                    SC.logWarn("Start ChangedHandler");
                }
            });
        }

        return dateItemField;
    }

    private TimeUnit[] getTimeOptions() {
        TimeUnit[] units = new TimeUnit[5];
        units[0] = TimeUnit.HOUR;
        units[1] = TimeUnit.DAY;
        units[2] = TimeUnit.WEEK;
        units[3] = TimeUnit.MONTH;
        units[4] = TimeUnit.YEAR;
        return units;
    }

    public static String getLengthMatchingDatePattern(String dateString) {
        if (dateString == null) return null;
        int len = dateString.length();
        if (len == DATE_TIME_FORMAT_Z.length() + 4) return DATE_TIME_FORMAT_Z;
        if (len == DATE_ONLY_FORMAT.length()) return DATE_ONLY_FORMAT;
        if (len == DATE_ONLY_FORMAT_ISO.length()) return DATE_ONLY_FORMAT_ISO;
        if (len == DATE_TIME_FORMAT.length()) return DATE_TIME_FORMAT;
        return DATE_TIME_FORMAT_Z;
    }

    public static DateTimeFormat getLengthMatchingDateFormatter(String dateString) {
        if (dateString == null) return null;
        int len = dateString.length();
        if (len > 11 && dateString.charAt(10) == 'T') {
            if (len == 23) {
                return DateTimeFormat.getFormat(DATE_TIME_FORMAT_ISO8601);
            }
            return DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.ISO_8601);
        }
        String formatPattern = getLengthMatchingDatePattern(dateString);
        return DateTimeFormat.getFormat(formatPattern);
    }

    public static Date parseDate(String dateString) {
        if (dateString == null) return null;

        dateString = scrubDateString(dateString);
        Date date = null;
        DateTimeFormat formatter = null;
        // Attempt to parse the date using length matching algorithm
        try {
            formatter = getLengthMatchingDateFormatter(dateString);
            date = formatter.parse(dateString);
            GWT.log("Parsed String (" + dateString + ")  using pattern (" + formatter.getPattern() + ") into Date ("
                + date + ")");
            return date;
        } catch (Exception e) {
            GWT.log("FAILED to parsed: " + dateString);
        }

        if (date == null) {
            try {
                // try ISO 8601 format
                formatter = DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.ISO_8601);
                GWT.log("Attempting to parse: using format: " + formatter.getPattern());
                date = formatter.parse(dateString);
            } catch (Exception e) {}
        }

        if (date == null) {
            try {
                // try ISO 8601 format with timezone
                formatter = DateTimeFormat.getFormat(DATE_TIME_FORMAT_ISO8601_Z);
                GWT.log("Attempting to parse: using format: " + formatter.getPattern());
                date = formatter.parse(dateString);
            } catch (Exception e) {}
        }

        if (date == null) {
            try {
                // try ISO 8601 format without timezone
                formatter = DateTimeFormat.getFormat(DATE_TIME_FORMAT_ISO8601);
                GWT.log("Attempting to parse: using format: " + formatter.getPattern());
                date = formatter.parse(dateString);
            } catch (Exception e) {}
        }

        if (date == null) {
            try {
                // try Opswise format with timezone
                formatter = DateTimeFormat.getFormat(DATE_TIME_FORMAT_Z);
                GWT.log("Attempting to parse: using format: " + formatter.getPattern());
                date = formatter.parse(dateString);
            } catch (Exception e) {}
        }

        if (date == null) {
            try {
                // try Opswise format without timezone
                formatter = DateTimeFormat.getFormat(DATE_TIME_FORMAT);
                GWT.log("Attempting to parse: using format: " + formatter.getPattern());
                date = formatter.parse(dateString);
            } catch (Exception e) {}
        }

        if (date == null) {
            try {
                // try just date
                formatter = DateTimeFormat.getFormat(DATE_ONLY_FORMAT);
                GWT.log("Attempting to parse: using format: " + formatter.getPattern());
                date = formatter.parse(dateString);
            } catch (Exception e) {}
        }

        if (date == null) {
            try {
                // try just date
                formatter = DateTimeFormat.getFormat(DATE_ONLY_FORMAT_ISO);
                GWT.log("Attempting to parse: using format: " + formatter.getPattern());
                date = formatter.parse(dateString);
            } catch (Exception e) {}
        }

        if (date != null) {
            GWT.log("Parsed String (" + dateString + ")  using pattern (" + formatter.getPattern() + ") into Date ("
                + date + ")");
        }
        return date;
    }

    public static String scrubDateString(String dateString) {
        if (dateString == null) return dateString;
        dateString = dateString.trim();
        int len = dateString.length();
        if (len == 23 && dateString.charAt(10) == 'T') return dateString + "+00:00";
        return dateString;
    }

}
