org.pentaho.mantle.client.dialogs.scheduling.ScheduleEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.mantle.client.dialogs.scheduling.ScheduleEditor.java

Source

/*!
 * This program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
 * Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 * or from the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * Copyright (c) 2002-2017 Pentaho Corporation..  All rights reserved.
 */

package org.pentaho.mantle.client.dialogs.scheduling;

import org.pentaho.gwt.widgets.client.controls.TimePicker;
import org.pentaho.gwt.widgets.client.ui.ICallback;
import org.pentaho.gwt.widgets.client.ui.IChangeHandler;
import org.pentaho.gwt.widgets.client.utils.CronExpression;
import org.pentaho.gwt.widgets.client.utils.CronParseException;
import org.pentaho.gwt.widgets.client.utils.CronParser;
import org.pentaho.gwt.widgets.client.utils.EnumException;
import org.pentaho.gwt.widgets.client.utils.TimeUtil.TimeOfDay;
import org.pentaho.gwt.widgets.client.wizards.AbstractWizardDialog.ScheduleDialogType;
import org.pentaho.mantle.client.dialogs.scheduling.RecurrenceEditor.TemporalValue;
import org.pentaho.mantle.client.messages.Messages;

import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CaptionPanel;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.datepicker.client.CalendarUtil;

/**
 * @author Steven Barkdull
 */
public class ScheduleEditor extends VerticalPanel implements IChangeHandler {

    private static final int DEFAULT_START_HOUR = 12; //$NON-NLS-1$
    private static final int DEFAULT_START_MINUTE = 0; //$NON-NLS-1$

    public static enum ENDS_TYPE {
        TIME, DURATION
    }

    public static class DurationValues {
        public int days = 0;

        public int hours = 0;

        public int minutes = 0;
    }

    public static enum TIME {
        MILLISECOND(1), SECOND(MILLISECOND.time * 1000), MINUTE(SECOND.time * 60), HOUR(MINUTE.time * 60), DAY(
                HOUR.time * 24);

        private long time;

        TIME(long time) {
            this.time = time;
        }

        public long getTime() {
            return time;
        }
    }

    protected static final String SCHEDULE_DROPDOWN_ARROW = "schedule-dropdown-arrow";

    protected static final String RECURRENCE_LABEL = "reccurence-label";

    protected static final String SCHEDULE_LABEL = "schedule-label"; //$NON-NLS-1$

    protected static final String SCHEDULE_EDITOR_CAPTION_PANEL = "schedule-editor-caption-panel"; //$NON-NLS-1$

    protected static final String BLOCKOUT_SELECT = "blockout-select";

    protected static final String BLOCKOUT_LABEL = "blockout-label";

    public enum ScheduleType {
        //@formatter:off
        RUN_ONCE(0, Messages.getString("schedule.runOnce")), SECONDS(1,
                Messages.getString("schedule.seconds")), MINUTES(2, Messages.getString("schedule.minutes")), HOURS(
                        3, Messages.getString("schedule.hours")), DAILY(4,
                                Messages.getString("schedule.daily")), WEEKLY(5,
                                        Messages.getString("schedule.weekly")), MONTHLY(6,
                                                Messages.getString("schedule.monthly")), YEARLY(7,
                                                        Messages.getString("schedule.yearly")), CRON(8,
                                                                Messages.getString("schedule.cron"));
        //@formatter:on

        private ScheduleType(int value, String name) {
            this.value = value;
            this.name = name;
        }

        private final int value;

        private final String name;

        private static ScheduleType[] scheduleValue = { RUN_ONCE, SECONDS, MINUTES, HOURS, DAILY, WEEKLY, MONTHLY,
                YEARLY, CRON };

        public int value() {
            return value;
        }

        @Override
        public String toString() {
            return name;
        }

        public static ScheduleType get(int idx) {
            return scheduleValue[idx];
        }

        public static int length() {
            return scheduleValue.length;
        }

        public static ScheduleType stringToScheduleType(String strSchedule) throws EnumException {
            for (ScheduleType v : EnumSet.range(ScheduleType.RUN_ONCE, ScheduleType.CRON)) {
                if (v.toString().equals(strSchedule)) {
                    return v;
                }
            }
            throw new EnumException(Messages.getString("schedule.invalidTemporalValue", scheduleValue.toString()));
        }
    } /* end enum */

    protected RunOnceEditor runOnceEditor = null;

    protected RecurrenceEditor recurrenceEditor = null;

    protected CronEditor cronEditor = null;

    // TODO sbarkdull, can this be static?
    private final Map<ScheduleType, Panel> scheduleTypeMap = new HashMap<ScheduleType, Panel>();

    private final Map<TemporalValue, ScheduleType> temporalValueToScheduleTypeMap = createTemporalValueToScheduleTypeMap();

    private final Map<ScheduleType, TemporalValue> scheduleTypeToTemporalValueMap = createScheduleTypeMapToTemporalValue();

    protected ListBox scheduleCombo = null;

    private ICallback<IChangeHandler> onChangeHandler = null;

    private boolean isBlockoutDialog = false;

    private TimePicker startTimePicker = null;

    protected TimePicker blockoutEndTimePicker = null;

    private Widget startTimePanel = null;

    private RadioButton endTimeRadioButton = null;

    private RadioButton durationRadioButton = null;

    protected ListBox daysListBox = null;

    protected ListBox hoursListBox = null;

    protected ListBox minutesListBox = null;

    protected Button blockoutCheckButton = new Button(Messages.getString("schedule.viewBlockoutTimes"));

    protected ListBox timeZonePicker = null;

    private final Date defaultDate = initDefaultDate();

    @SuppressWarnings("deprecation")
    private Date initDefaultDate() {
        Date date = new Date();
        date.setHours(DEFAULT_START_HOUR);
        date.setMinutes(DEFAULT_START_MINUTE);
        CalendarUtil.addDaysToDate(date, 1);
        return date;
    }

    public ScheduleEditor(ScheduleDialogType type) {
        super();
        isBlockoutDialog = (type == ScheduleDialogType.BLOCKOUT);
        startTimePicker = new TimePicker();

        setStylePrimaryName("scheduleEditor"); //$NON-NLS-1$

        scheduleCombo = createScheduleCombo();
        Label l = new Label(Messages.getString("schedule.recurrenceColon"));
        l.getElement().setId(RECURRENCE_LABEL);
        l.setStyleName(SCHEDULE_LABEL);
        add(l);
        add(scheduleCombo);

        SimplePanel hspacer = new SimplePanel();
        hspacer.setWidth("100px"); //$NON-NLS-1$

        if (!isBlockoutDialog) {
            startTimePanel = createStartTimePanel();
            add(startTimePanel);
        } else {

            // Blockout End TimePicker
            Date blockoutEndDate = new Date(defaultDate.getTime());
            addMinutes(defaultDate, 1);
            blockoutEndTimePicker = new TimePicker();
            blockoutEndTimePicker = new TimePicker();
            blockoutEndTimePicker.setTime(blockoutEndDate);

            // Blockout End Caption Panel
            blockoutEndTimePicker.getElement().getStyle().setDisplay(Display.NONE);

            final String[] daysList = new String[365];
            final String[] hoursList = new String[24];
            final String[] minutesList = new String[60];

            // Populate list
            for (Integer i = 0; i < 365; i++) {
                String iStr = i.toString();
                daysList[i] = iStr;

                if (i < 60) {
                    minutesList[i] = iStr;
                    if (i < 24) {
                        hoursList[i] = iStr;
                    }
                }
            }

            // Units of time Drop Down
            daysListBox = new ListBox();
            daysListBox.getElement().setId("daysListBox"); //$NON-NLS-1$
            daysListBox.addStyleName(BLOCKOUT_SELECT);
            populateListItems(daysListBox, daysList, 0, 365);

            final Label daysLabel = new Label(Messages.getString("schedule.dayOrDays"));
            daysLabel.addStyleName(BLOCKOUT_LABEL);
            daysLabel.getElement().setAttribute("for", daysListBox.getElement().getId()); //$NON-NLS-1$

            hoursListBox = new ListBox();
            hoursListBox.getElement().setId("hoursListBox"); //$NON-NLS-1$
            hoursListBox.addStyleName(BLOCKOUT_SELECT);
            populateListItems(hoursListBox, hoursList, 0, 24);

            final Label hoursLabel = new Label(Messages.getString("schedule.hourOrHours"));
            hoursLabel.addStyleName(BLOCKOUT_LABEL);
            hoursLabel.getElement().setAttribute("for", hoursListBox.getElement().getId()); //$NON-NLS-1$

            minutesListBox = new ListBox();
            minutesListBox.getElement().setId("minutesListBox"); //$NON-NLS-1$
            minutesListBox.addStyleName(BLOCKOUT_SELECT);
            populateListItems(minutesListBox, minutesList, 0, 60);
            minutesListBox.setSelectedIndex(1); // default value for Validator

            final Label minutesLabel = new Label(Messages.getString("schedule.minuteOrMinutes"));
            minutesLabel.addStyleName(BLOCKOUT_LABEL);
            minutesLabel.getElement().setAttribute("for", minutesListBox.getElement().getId()); //$NON-NLS-1$

            final HorizontalPanel durationPanel = new HorizontalPanel();
            durationPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
            durationPanel.setSpacing(blockoutEndTimePicker.getSpacing());
            durationPanel.add(daysListBox);
            durationPanel.add(daysLabel);
            durationPanel.add(hoursListBox);
            durationPanel.add(hoursLabel);
            durationPanel.add(minutesListBox);
            durationPanel.add(minutesLabel);

            // Bind change handler
            scheduleCombo.addChangeHandler(new ChangeHandler() {

                @Override
                public void onChange(ChangeEvent event) {
                    String scheduleType = scheduleCombo.getItemText(scheduleCombo.getSelectedIndex());

                    if (ScheduleType.RUN_ONCE.toString().equals(scheduleType)) {
                        show(true, daysListBox, daysLabel, hoursListBox, hoursLabel, minutesListBox, minutesLabel);

                        populateListItems(daysListBox, daysList, 0, 365);
                        populateListItems(hoursListBox, hoursList, 0, 24);
                        populateListItems(minutesListBox, minutesList, 0, 60);

                    } else if (ScheduleType.HOURS.toString().equals(scheduleType)) {
                        hide(true, daysListBox, daysLabel, hoursListBox, hoursLabel);
                        show(true, minutesListBox, minutesLabel);

                        populateListItems(minutesListBox, minutesList, 0, 60);

                    } else if (ScheduleType.DAILY.toString().equals(scheduleType)) {
                        hide(true, daysListBox, daysLabel);
                        show(true, hoursListBox, hoursLabel, minutesListBox, minutesLabel);

                        populateListItems(hoursListBox, hoursList, 0, 24);
                        populateListItems(minutesListBox, minutesList, 0, 60);

                    } else if (ScheduleType.WEEKLY.toString().equals(scheduleType)) {
                        show(true, daysListBox, daysLabel, hoursListBox, hoursLabel, minutesListBox, minutesLabel);

                        populateListItems(daysListBox, daysList, 0, 7);
                        populateListItems(hoursListBox, hoursList, 0, 24);
                        populateListItems(minutesListBox, minutesList, 0, 60);

                    } else if (ScheduleType.MONTHLY.toString().equals(scheduleType)) {
                        show(true, daysListBox, daysLabel, hoursListBox, hoursLabel, minutesListBox, minutesLabel);

                        populateListItems(daysListBox, daysList, 0, 28);
                        populateListItems(hoursListBox, hoursList, 0, 24);
                        populateListItems(minutesListBox, minutesList, 0, 60);

                    } else if (ScheduleType.YEARLY.toString().equals(scheduleType)) {
                        show(true, daysListBox, daysLabel, hoursListBox, hoursLabel, minutesListBox, minutesLabel);

                        populateListItems(daysListBox, daysList, 0, 365);
                        populateListItems(hoursListBox, hoursList, 0, 24);
                        populateListItems(minutesListBox, minutesList, 0, 60);
                    }
                }
            });

            /*
             * Radio Buttons for duration
             */
            durationRadioButton = new RadioButton("durationRadioGroup", "durationRadioButton"); //$NON-NLS-1$ //$NON-NLS-2$
            durationRadioButton.setText(Messages.getString("schedule.duration"));
            durationRadioButton.setValue(Boolean.TRUE);
            durationRadioButton.addClickHandler(new ClickHandler() {

                @Override
                public void onClick(ClickEvent event) {
                    blockoutEndTimePicker.getElement().getStyle().setDisplay(Display.NONE);
                    durationPanel.getElement().getStyle().clearDisplay();
                }
            });

            endTimeRadioButton = new RadioButton("durationRadioGroup", "endTimeRadioButton"); //$NON-NLS-1$ //$NON-NLS-2$
            endTimeRadioButton.setText(Messages.getString("schedule.endTime"));
            endTimeRadioButton.addClickHandler(new ClickHandler() {

                @Override
                public void onClick(ClickEvent event) {
                    blockoutEndTimePicker.getElement().getStyle().clearDisplay();
                    durationPanel.getElement().getStyle().setDisplay(Display.NONE);
                }
            });

            // Radio Buttons Panel
            HorizontalPanel radioButtonsPanel = new HorizontalPanel();
            radioButtonsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
            radioButtonsPanel.getElement().setId("radio-buttons-panel");
            radioButtonsPanel.add(durationRadioButton);
            radioButtonsPanel.add(endTimeRadioButton);

            // Ends Panel
            VerticalPanel endsPanel = new VerticalPanel();
            endsPanel.add(radioButtonsPanel);
            endsPanel.add(blockoutEndTimePicker);
            endsPanel.add(durationPanel);

            // Blockout period
            CaptionPanel blockoutStartCaptionPanel = new CaptionPanel(Messages.getString("schedule.startTime"));
            blockoutStartCaptionPanel.setStyleName(SCHEDULE_EDITOR_CAPTION_PANEL);
            HorizontalPanel blockoutStartPanel = new HorizontalPanel();
            blockoutStartPanel.getElement().setId("blockout-start-panel");
            blockoutStartPanel.add(getStartTimePicker());
            timeZonePicker = new ListBox();
            timeZonePicker.setStyleName("timeZonePicker");
            timeZonePicker.setVisibleItemCount(1);
            blockoutStartPanel.add(timeZonePicker);
            timeZonePicker.getElement().getParentElement().getStyle().setPaddingTop(5, Unit.PX);

            blockoutStartCaptionPanel.add(blockoutStartPanel);
            populateTimeZonePicker();

            // Ends Caption Panel
            CaptionPanel endCaptionPanel = new CaptionPanel(Messages.getString("schedule.endsCaptionTitle"));
            endCaptionPanel.setStyleName(SCHEDULE_EDITOR_CAPTION_PANEL);
            endCaptionPanel.add(endsPanel);

            VerticalPanel blockoutPanel = new VerticalPanel();
            blockoutPanel.setWidth("100%"); //$NON-NLS-1$
            blockoutPanel.add(blockoutStartCaptionPanel);
            blockoutPanel.add(endCaptionPanel);

            add(blockoutPanel);
        }

        VerticalPanel vp = new VerticalPanel();
        vp.setWidth("100%"); //$NON-NLS-1$
        add(vp);
        setCellHeight(vp, "100%"); //$NON-NLS-1$

        runOnceEditor = new RunOnceEditor(startTimePicker);
        vp.add(runOnceEditor);
        scheduleTypeMap.put(ScheduleType.RUN_ONCE, runOnceEditor);
        runOnceEditor.setVisible(true);

        recurrenceEditor = new RecurrenceEditor(startTimePicker);
        vp.add(recurrenceEditor);
        scheduleTypeMap.put(ScheduleType.SECONDS, recurrenceEditor);
        scheduleTypeMap.put(ScheduleType.MINUTES, recurrenceEditor);
        scheduleTypeMap.put(ScheduleType.HOURS, recurrenceEditor);
        scheduleTypeMap.put(ScheduleType.DAILY, recurrenceEditor);
        scheduleTypeMap.put(ScheduleType.WEEKLY, recurrenceEditor);
        scheduleTypeMap.put(ScheduleType.MONTHLY, recurrenceEditor);
        scheduleTypeMap.put(ScheduleType.YEARLY, recurrenceEditor);
        recurrenceEditor.setVisible(false);

        cronEditor = new CronEditor();
        scheduleTypeMap.put(ScheduleType.CRON, cronEditor);
        cronEditor.setVisible(false);

        if (!isBlockoutDialog) {
            vp.add(cronEditor);

            VerticalPanel blockoutButtonPanel = new VerticalPanel();
            blockoutButtonPanel.setWidth("100%"); //$NON-NLS-1$
            // blockoutButtonPanel.setHeight("30%");
            blockoutButtonPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
            blockoutButtonPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);

            // We want to add a button to check for blockout conflicts
            blockoutCheckButton.setStyleName("pentaho-button"); //$NON-NLS-1$
            blockoutCheckButton.getElement().setId("blockout-check-button"); //$NON-NLS-1$
            blockoutCheckButton.setVisible(false);

            hspacer.setHeight("50px"); //$NON-NLS-1$
            blockoutButtonPanel.add(hspacer);
            blockoutButtonPanel.add(blockoutCheckButton);

            vp.add(hspacer);
            add(blockoutButtonPanel);
        }

        reset(defaultDate);

        configureOnChangeHandler();
    }

    @SuppressWarnings("deprecation")
    private void addMinutes(Date date, int count) {
        date.setMinutes(date.getMinutes() + count);
    }

    private void show(boolean applyToParent, UIObject... objs) {
        for (UIObject obj : objs) {
            Element ele = obj.getElement();
            if (applyToParent) {
                ele = ele.getParentElement();
            }
            ele.getStyle().clearDisplay();
        }
    }

    private void hide(boolean applyToParent, UIObject... objs) {
        for (UIObject obj : objs) {
            Element ele = obj.getElement();
            if (applyToParent) {
                ele = ele.getParentElement();
            }
            ele.getStyle().setDisplay(Display.NONE);
        }
    }

    private void populateListItems(ListBox listBox, String[] arr, int startIndex, int howMany) {

        // Clear items
        listBox.clear();

        // Add itesm
        int endIndex = startIndex + howMany;
        for (int i = startIndex; i < endIndex; i++) {
            listBox.addItem(arr[i]);
        }
    }

    private void populateTimeZonePicker() {

        String url = ScheduleHelper.getFullyQualifiedURL() + "api/system/timezones"; //$NON-NLS-1$
        RequestBuilder timeZonesRequest = new RequestBuilder(RequestBuilder.GET, url);
        timeZonesRequest.setHeader("accept", "application/json"); //$NON-NLS-1$ //$NON-NLS-2$
        timeZonesRequest.setHeader("If-Modified-Since", "01 Jan 1970 00:00:00 GMT");
        try {
            timeZonesRequest.sendRequest(null, new RequestCallback() {

                @Override
                public void onResponseReceived(Request request, Response response) {
                    timeZonePicker.clear();
                    String responseText = response.getText();
                    JSONValue value = JSONParser.parseLenient(responseText);
                    JSONObject object = value.isObject();
                    value = object.get("timeZones");
                    JSONValue serverTZvalue = object.get("serverTzId");
                    JSONString serverTZIdString = serverTZvalue.isString();
                    String serverTZId = serverTZIdString.stringValue();
                    object = value.isObject();
                    value = object.get("entry");
                    JSONArray timeZonesJSONArray = value.isArray();
                    for (int i = 0; i < timeZonesJSONArray.size(); i++) {
                        JSONValue entryValue = timeZonesJSONArray.get(i);
                        JSONObject entryObject = entryValue.isObject();
                        JSONValue keyValue = entryObject.get("key");
                        JSONValue theValue = entryObject.get("value");
                        String key = keyValue.isString().stringValue();
                        String valueForKey = theValue.isString().stringValue();
                        timeZonePicker.addItem(valueForKey, key);
                    }
                    for (int i = 0; i < timeZonePicker.getItemCount(); i++) {
                        if (timeZonePicker.getValue(i).equalsIgnoreCase(serverTZId)) {
                            timeZonePicker.setSelectedIndex(i);
                            break;
                        }
                    }
                }

                @Override
                public void onError(Request request, Throwable exception) {
                    // TODO Auto-generated method stub

                }

            });
        } catch (RequestException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public ListBox getTimeZonePicker() {
        return timeZonePicker;
    }

    public void setBlockoutButtonHandler(final ClickHandler handler) {
        blockoutCheckButton.addClickHandler(handler);
    }

    public Button getBlockoutCheckButton() {
        return blockoutCheckButton;
    }

    public TimePicker getStartTimePicker() {
        return startTimePicker;
    }

    public TimePicker getBlockoutEndTimePicker() {
        return blockoutEndTimePicker;
    }

    public ENDS_TYPE getBlockoutEndsType() {
        return durationRadioButton.getValue() ? ENDS_TYPE.DURATION : ENDS_TYPE.TIME;
    }

    public DurationValues getDurationValues() {
        DurationValues vals = new DurationValues();

        String displayNone = Display.NONE.getCssName();

        // Days
        if (!displayNone.equals(daysListBox.getElement().getStyle().getDisplay())) {
            vals.days = Integer.parseInt(daysListBox.getItemText(daysListBox.getSelectedIndex()));
        }

        // Hours
        if (!displayNone.equals(hoursListBox.getElement().getStyle().getDisplay())) {
            vals.hours = Integer.parseInt(hoursListBox.getItemText(hoursListBox.getSelectedIndex()));
        }

        // Minutes
        if (!displayNone.equals(minutesListBox.getElement().getStyle().getDisplay())) {
            vals.minutes = Integer.parseInt(minutesListBox.getItemText(minutesListBox.getSelectedIndex()));
        }

        return vals;
    }

    public void setDurationFields(long duration) {

        long remainder = duration;

        long days = remainder / TIME.DAY.getTime();
        remainder -= days * TIME.DAY.getTime();

        long hours = remainder / TIME.HOUR.getTime();
        remainder -= hours * TIME.HOUR.getTime();

        long minutes = remainder / TIME.MINUTE.getTime();

        daysListBox.setSelectedIndex(new Long(days).intValue());
        hoursListBox.setSelectedIndex(new Long(hours).intValue());
        minutesListBox.setSelectedIndex(new Long(minutes).intValue());

        // Set valid end time if range is within 24hrs
        if (duration < TIME.DAY.getTime()) {
            boolean isPM = hours >= 12;
            blockoutEndTimePicker.setHour(new Long(hours + (isPM ? -12 : 0)).toString());
            blockoutEndTimePicker.setMinute(new Long(minutes).toString());
            blockoutEndTimePicker.setTimeOfDay(isPM ? TimeOfDay.PM : TimeOfDay.AM);
        }
    }

    protected Widget createStartTimePanel() {
        CaptionPanel startTimeGB = new CaptionPanel(Messages.getString("schedule.startTime"));
        startTimeGB.setStyleName(SCHEDULE_EDITOR_CAPTION_PANEL);

        startTimeGB.add(getStartTimePicker());

        return startTimeGB;
    }

    public void reset(Date now) {
        runOnceEditor.reset(now);
        recurrenceEditor.reset(now);
        cronEditor.reset(now);

        setScheduleType(ScheduleType.RUN_ONCE);
    }

    public String getCronString() {
        switch (getScheduleType()) {
        case RUN_ONCE:
            return null;
        case SECONDS: // fall through
        case MINUTES: // fall through
        case HOURS: // fall through
        case DAILY: // fall through
        case WEEKLY: // fall through
        case MONTHLY: // fall through
        case YEARLY:
            return recurrenceEditor.getCronString();
        case CRON:
            return cronEditor.getCronString();
        default:
            throw new RuntimeException(Messages.getString("schedule.invalidRunType", getScheduleType().toString()));
        }
    }

    /**
     * 
     * @param cronStr
     * @throws CronParseException
     *           if cronStr is not a valid CRON string.
     */
    public void setCronString(String cronStr) throws CronParseException {

        // Try original simplistic parser...
        CronParser cp = new CronParser(cronStr);
        String recurrenceStr = null;
        try {
            recurrenceStr = cp.parseToRecurrenceString(); // throws CronParseException
        } catch (CronParseException e) {
            if (!CronExpression.isValidExpression(cronStr)) { // Parse with proper expression parser
                throw e;
            }
            recurrenceStr = null; // valid cronstring, not parse-able to recurrence string
        }

        if (null != recurrenceStr) {
            recurrenceEditor.inititalizeWithRecurrenceString(recurrenceStr);
            TemporalValue tv = recurrenceEditor.getTemporalState();
            ScheduleType rt = temporalValueToScheduleType(tv);
            setScheduleType(rt);
        } else {
            // its a cron string that cannot be parsed into a recurrence string, switch to cron string editor.
            setScheduleType(ScheduleType.CRON);
        }

        cronEditor.setCronString(cronStr);
    }

    /**
     * 
     * @return null if the selected schedule does not support repeat-in-seconds, otherwise return the number of seconds
     *         between schedule execution.
     * @throws RuntimeException
     *           if the temporal value is invalid. This condition occurs as a result of programmer error.
     */
    public Long getRepeatInSecs() throws RuntimeException {
        return recurrenceEditor.getRepeatInSecs();
    }

    public void setRepeatInSecs(Integer repeatInSecs) {
        recurrenceEditor.inititalizeWithRepeatInSecs(repeatInSecs);
        TemporalValue tv = recurrenceEditor.getTemporalState();
        ScheduleType rt = temporalValueToScheduleType(tv);
        setScheduleType(rt);
    }

    private ListBox createScheduleCombo() {
        final ScheduleEditor localThis = this;
        ListBox lb = new ListBox();
        lb.setVisibleItemCount(1);
        //lb.setStyleName("scheduleCombo"); //$NON-NLS-1$
        lb.addChangeHandler(new ChangeHandler() {

            @Override
            public void onChange(ChangeEvent event) {
                localThis.handleScheduleChange();
            }
        });

        // add all schedule types to the combobox
        for (ScheduleType schedType : EnumSet.range(ScheduleType.RUN_ONCE, ScheduleType.CRON)) {
            if (!isBlockoutDialog || (schedType != ScheduleType.CRON && schedType != ScheduleType.SECONDS
                    && schedType != ScheduleType.MINUTES && schedType != ScheduleType.HOURS)) {
                lb.addItem(schedType.toString());
            }
        }
        lb.setItemSelected(0, true);
        lb.getElement().setId("schedule-main-gwt-listbox");
        lb.setStyleName(SCHEDULE_DROPDOWN_ARROW);

        return lb;
    }

    public ScheduleType getScheduleType() {
        String selectedValue = scheduleCombo.getValue(scheduleCombo.getSelectedIndex());
        return ScheduleType.stringToScheduleType(selectedValue);
    }

    public void setScheduleType(ScheduleType scheduleType) {
        int itemCount = scheduleCombo.getItemCount();
        for (int i = 0; i < itemCount; i++) {
            String itemText = scheduleCombo.getItemText(i);
            if (itemText.equals(scheduleType.toString())) {
                scheduleCombo.setSelectedIndex(i);
            }
        }
        selectScheduleTypeEditor(scheduleType);
    }

    /**
     * NOTE: should only ever be used by validators. This is a backdoor into this class that shouldn't be here, do not use
     * this method unless you are validating.
     * 
     * @return DateRangeEditor
     */
    public RecurrenceEditor getRecurrenceEditor() {
        return recurrenceEditor;
    }

    /**
     * NOTE: should only ever be used by validators. This is a backdoor into this class that shouldn't be here, do not use
     * this method unless you are validating.
     * 
     * @return DateRangeEditor
     */
    public CronEditor getCronEditor() {
        return cronEditor;
    }

    /**
     * NOTE: should only ever be used by validators. This is a backdoor into this class that shouldn't be here, do not use
     * this method unless you are validating.
     * 
     * @return DateRangeEditor
     */

    public RunOnceEditor getRunOnceEditor() {
        return runOnceEditor;
    }

    public void setStartTime(String startTime) {
        runOnceEditor.setStartTime(startTime);
        recurrenceEditor.setStartTime(startTime);
    }

    public void setBlockoutEndTime(String endTime) {
        blockoutEndTimePicker.setTime(endTime);
    }

    public String getStartTime() {
        switch (getScheduleType()) {
        case RUN_ONCE:
            return runOnceEditor.getStartTime();
        case SECONDS: // fall through
        case MINUTES: // fall through
        case HOURS: // fall through
        case DAILY: // fall through
        case WEEKLY: // fall through
        case MONTHLY: // fall through
        case YEARLY:
            return recurrenceEditor.getStartTime();
        case CRON:
            return cronEditor.getStartTime();
        default:
            throw new RuntimeException(Messages.getString("schedule.invalidRunType", getScheduleType().toString()));
        }
    }

    public void setStartDate(Date startDate) {
        runOnceEditor.setStartDate(startDate);
        recurrenceEditor.setStartDate(startDate);
        cronEditor.setStartDate(startDate);
    }

    @SuppressWarnings("deprecation")
    public Date getStartDate() {
        switch (getScheduleType()) {
        case RUN_ONCE:
            Date startDate = runOnceEditor.getStartDate();
            String startTime = runOnceEditor.getStartTime();
            String[] times = startTime.split(":"); //$NON-NLS-1$
            int hour = Integer.parseInt(times[0]);
            int minute = Integer.parseInt(times[1]);
            if (startTime.indexOf(TimeOfDay.PM.toString()) >= 0) { //$NON-NLS-1$
                hour += 12;
            }

            startDate.setHours(hour);
            startDate.setMinutes(minute);
            startDate.setSeconds(0);
            return startDate;
        case SECONDS: // fall through
        case MINUTES: // fall through
        case HOURS: // fall through
        case DAILY: // fall through
        case WEEKLY: // fall through
        case MONTHLY: // fall through
        case YEARLY:
            return recurrenceEditor.getStartDate();
        case CRON:
            return cronEditor.getStartDate();
        default:
            throw new RuntimeException(Messages.getString("schedule.invalidRunType", getScheduleType().toString()));
        }
    }

    public void setEndDate(Date endDate) {
        recurrenceEditor.setEndDate(endDate);
        cronEditor.setEndDate(endDate);
    }

    public Date getEndDate() {
        switch (getScheduleType()) {
        case RUN_ONCE:
            return null;
        case SECONDS: // fall through
        case MINUTES: // fall through
        case HOURS: // fall through
        case DAILY: // fall through
        case WEEKLY: // fall through
        case MONTHLY: // fall through
        case YEARLY:
            return recurrenceEditor.getEndDate();
        case CRON:
            return cronEditor.getEndDate();
        default:
            throw new RuntimeException(Messages.getString("schedule.invalidRunType", getScheduleType().toString()));
        }
    }

    public void setNoEndDate() {
        recurrenceEditor.setNoEndDate();
        cronEditor.setNoEndDate();
    }

    public void setEndBy() {
        cronEditor.setEndBy();
        recurrenceEditor.setEndBy();
    }

    private void handleScheduleChange() throws EnumException {
        ScheduleType schedType = getScheduleType();
        selectScheduleTypeEditor(schedType);
    }

    protected void selectScheduleTypeEditor(ScheduleType scheduleType) {
        // if we are switching to cron type, then hide the start time panel
        if ((isBlockoutDialog == false) && (startTimePanel != null)) {
            if (scheduleType == ScheduleType.CRON) {
                startTimePanel.setVisible(false);
            } else {
                startTimePanel.setVisible(true);
            }
        }

        // hide all panels
        for (Map.Entry<ScheduleType, Panel> me : scheduleTypeMap.entrySet()) {
            me.getValue().setVisible(false);
        }
        // show the selected panel
        Panel p = scheduleTypeMap.get(scheduleType);
        p.setVisible(true);

        TemporalValue tv = scheduleTypeToTemporalValue(scheduleType);
        if (null != tv) {
            // force the recurrence editor to display the appropriate ui
            recurrenceEditor.setTemporalState(tv);
        }
    }

    private static Map<TemporalValue, ScheduleType> createTemporalValueToScheduleTypeMap() {
        Map<TemporalValue, ScheduleType> m = new HashMap<TemporalValue, ScheduleType>();

        m.put(TemporalValue.SECONDS, ScheduleType.SECONDS);
        m.put(TemporalValue.MINUTES, ScheduleType.MINUTES);
        m.put(TemporalValue.HOURS, ScheduleType.HOURS);
        m.put(TemporalValue.DAILY, ScheduleType.DAILY);
        m.put(TemporalValue.WEEKLY, ScheduleType.WEEKLY);
        m.put(TemporalValue.MONTHLY, ScheduleType.MONTHLY);
        m.put(TemporalValue.YEARLY, ScheduleType.YEARLY);

        return m;
    }

    private static Map<ScheduleType, TemporalValue> createScheduleTypeMapToTemporalValue() {
        Map<ScheduleType, TemporalValue> m = new HashMap<ScheduleType, TemporalValue>();

        m.put(ScheduleType.SECONDS, TemporalValue.SECONDS);
        m.put(ScheduleType.MINUTES, TemporalValue.MINUTES);
        m.put(ScheduleType.HOURS, TemporalValue.HOURS);
        m.put(ScheduleType.DAILY, TemporalValue.DAILY);
        m.put(ScheduleType.WEEKLY, TemporalValue.WEEKLY);
        m.put(ScheduleType.MONTHLY, TemporalValue.MONTHLY);
        m.put(ScheduleType.YEARLY, TemporalValue.YEARLY);

        return m;
    }

    protected ScheduleType temporalValueToScheduleType(TemporalValue tv) {
        return temporalValueToScheduleTypeMap.get(tv);
    }

    private TemporalValue scheduleTypeToTemporalValue(ScheduleType st) {
        return scheduleTypeToTemporalValueMap.get(st);
    }

    @Override
    public void setOnChangeHandler(ICallback<IChangeHandler> handler) {
        onChangeHandler = handler;
    }

    protected void changeHandler() {
        if (null != onChangeHandler) {
            onChangeHandler.onHandle(this);
        }
    }

    private void configureOnChangeHandler() {
        final ScheduleEditor localThis = this;

        ICallback<IChangeHandler> handler = new ICallback<IChangeHandler>() {
            @Override
            public void onHandle(IChangeHandler o) {
                localThis.changeHandler();
            }
        };

        ChangeHandler changeHandler = new ChangeHandler() {
            @Override
            public void onChange(ChangeEvent event) {
                localThis.changeHandler();
            }
        };

        ClickHandler clickHandler = new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                localThis.changeHandler();
            }
        };

        scheduleCombo.addChangeHandler(changeHandler);
        runOnceEditor.setOnChangeHandler(handler);
        recurrenceEditor.setOnChangeHandler(handler);
        cronEditor.setOnChangeHandler(handler);

        if (daysListBox != null) {
            daysListBox.addChangeHandler(changeHandler);
        }
        if (hoursListBox != null) {
            hoursListBox.addChangeHandler(changeHandler);
        }
        if (minutesListBox != null) {
            minutesListBox.addChangeHandler(changeHandler);
        }

        if (startTimePicker != null) {
            startTimePicker.setOnChangeHandler(handler);
        }
        if (blockoutEndTimePicker != null) {
            blockoutEndTimePicker.setOnChangeHandler(handler);
        }

        if (durationRadioButton != null) {
            durationRadioButton.addClickHandler(clickHandler);
        }
        if (endTimeRadioButton != null) {
            endTimeRadioButton.addClickHandler(clickHandler);
        }
    }

    public boolean isBlockoutDialog() {
        return isBlockoutDialog;
    }
}