package com.test.client;

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

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;
import com.smartgwt.client.core.Rectangle;
import com.smartgwt.client.data.DataSource;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.fields.DataSourceDateTimeField;
import com.smartgwt.client.data.fields.DataSourceEnumField;
import com.smartgwt.client.data.fields.DataSourceTextField;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.ListGridComponent;
import com.smartgwt.client.types.ListGridEditEvent;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.types.RowEndEditAction;
import com.smartgwt.client.types.SelectionStyle;
import com.smartgwt.client.types.TimeDisplayFormat;
import com.smartgwt.client.widgets.Button;
import com.smartgwt.client.widgets.Dialog;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.FormItemIcon;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.events.IconClickEvent;
import com.smartgwt.client.widgets.form.fields.events.IconClickHandler;
import com.smartgwt.client.widgets.grid.CellFormatter;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
import com.smartgwt.client.widgets.toolbar.ToolStripButton;

public class SGWT_test implements EntryPoint
{
  /**
   * The message displayed to the user when the server cannot be reached or
   * returns an error.
   */
  // private static final String SERVER_ERROR = "An error occurred while "
  // + "attempting to contact the server. Please check your network "
  // + "connection and try again.";
  /**
   * This is the entry point method.
   */

  @Override
  public void onModuleLoad()
  {

    final String schedId = "666";
        
    final ListGrid siGrid = new ListGrid();
    siGrid.setLayoutAlign(Alignment.CENTER);
    siGrid.setEmptyCellValue("Unknown");
    siGrid.setShowHeader(true);
    siGrid.setShowDetailFields(false);
    siGrid.setLeaveScrollbarGap(false);
    siGrid.setDataPageSize(10);
    siGrid.setCanResizeFields(true);
    //
    // Table Size: All of the width
    //  and height as needed
    //
    siGrid.setWidth("20%");
    siGrid.setHeight(10);
    siGrid.setMargin(12);
    siGrid.setOverflow(Overflow.VISIBLE);
    siGrid.setBodyOverflow(Overflow.VISIBLE);
    //
    // Turn off mouse over and selected row color changes
    //
    siGrid.setAlternateRecordStyles(false);
    siGrid.setShowRollOver(true);
    //
    // Edit
    //
    siGrid.setCanEdit(true);
    siGrid.setEditEvent(ListGridEditEvent.NONE);
    siGrid.setListEndEditAction(RowEndEditAction.NONE);
    siGrid.setSaveByCell(false);
    siGrid.setSelectionType(SelectionStyle.SINGLE);
    siGrid.setShowSelectedStyle(true);
    //
    siGrid.setAutoSaveEdits(true);
    //
    siGrid.setDataSource(siDS);
    siGrid.setAutoFetchData(true);
    
    final ListGridField id = new ListGridField("id");
    id.setHidden(true);
    
    final ListGridField sid = new ListGridField("sched_id");
    sid.setHidden(true);
    
    final ListGridField alldays = new ListGridField("alldays");
    alldays.setHidden(true);
    
    final ListGridField dow = new ListGridField("dow", "Day");
    dow.setCellFormatter(new CellFormatter(){
     @Override
     public String format(Object value, ListGridRecord record, int rowNum,
          int colNum) {
       String dow = (String) value;
       String alldays = record.getAttributeAsString("alldays");
       if (dow == null && alldays != null && alldays.equals("1"))
         dow = "All Days";
       return dow;
     }
    });
    
    /*
     * Add callback for the jobs update flag 
     */    
    final ListGridField time = new ListGridField("time", "Time");
    time.setEditorType(new ScheduleSiTimeItem("time"));
    
    siGrid.setFields(id, sid, alldays, dow, time);
    
    final ToolStrip gridEditControls = new ToolStrip();
    gridEditControls.setWidth100();
    gridEditControls.setHeight(24);

    final LayoutSpacer spacer = new LayoutSpacer();
    spacer.setWidth("*");

    final ToolStripButton editButton = new ToolStripButton();
    editButton.setIcon("icon_edit.png");
    editButton.setPrompt("Edit Selected Instance");
    editButton.addClickHandler(new ClickHandler()
    {
      @Override
      public void onClick(ClickEvent event)
      {
        /*
         * Editing an existing record works fine.
         */
        ListGridRecord editRecord = siGrid.getSelectedRecord();
        if (editRecord == null)
          return;
        dow.setCanEdit(false);
        siGrid.startEditing(siGrid.getDataAsRecordList().indexOf(editRecord), 1, false);
      }
    });

    final ToolStripButton addButton = new ToolStripButton();
    addButton.setIcon("icon_add.png");
    addButton.setPrompt("Add New Instance");
    addButton.addClickHandler(new ClickHandler()
    {
      @Override
      public void onClick(ClickEvent event)
      {
        /*
         * NOTE
         * If you add a new record and select a time
         * the form item will display the time when set.
         * When you hit a carriage return to store the
         * record, the grid comes back with "Unknown".
         * 
         * If you edit the existing record and then
         * add a new record, it works. For some reason
         * the new record gets initialized with a date
         * object having a date of the beginning of the
         * epoch.
         * 
         * e.g. ShowDialog got value: Thu Jan 01 00:00:00 EST 1970
         * 
         * Now matter what time is selected, this date persists
         * in the list grid. This leads me to believe the grid
         * is not retrieving the date from the FormItem.
         * 
         */
        Map<String, String> sidVal = new HashMap<String, String>();
        sidVal.put("sched_id", schedId);
        dow.setCanEdit(true);
        siGrid.startEditingNew(sidVal);
        /*
         * NOTE
         * You can comment out the "startEditingNew"
         * code above and use this to seed a date.
         * The problem here is that whatever time
         * you change in the picker is ignored
         *
         */
        /*
        ListGridRecord lgr = new ListGridRecord();
        lgr.setAttribute("time", new Date());
        lgr.setAttribute("sched_id", schedId);
        siGrid.startEditingNew(lgr);
        */
      }
    });

    final ToolStripButton removeButton = new ToolStripButton();
    removeButton.setIcon("icon_delete.png");
    removeButton.setPrompt("Remove Selected Instance");
    removeButton.addClickHandler(new ClickHandler()
    {
      @Override
      public void onClick(ClickEvent event)
      {
        siGrid.removeSelectedData();
      }
    });

    gridEditControls.setMembers(spacer, addButton,
        removeButton, editButton);

    siGrid.setGridComponents(new Object[] { ListGridComponent.HEADER,
        ListGridComponent.BODY, gridEditControls });
    
    siGrid.draw();
  }

  public interface CallbackHandler<T> {
    public void handle(T object);
  }

  private  class ScheduleSiTimeItem extends TextItem
  {

    private ScheduleSiTimeSelector timeChooser = null;
    private FormItem editItem = null;

    @SuppressWarnings("unused")
    public ScheduleSiTimeItem(JavaScriptObject jsObj)
    {
      super(jsObj);
      init();
    }

    public ScheduleSiTimeItem(String name)
    {
      super(name);
      init();
    }

    private void init()
    {
      this.setType("datetime");
      this.setTimeFormatter(TimeDisplayFormat.TOSHORTTIME);

      final FormItemIcon fi = new FormItemIcon();
      fi.setSrc("clock.png");
      fi.setHeight(20);
      fi.setWidth(20);
      this.setIcons(fi);

      this.addIconClickHandler(new IconClickHandler()
      {
        @Override
        public void onIconClick(IconClickEvent event)
        {
          editItem = event.getItem();
          if (editItem != null)
          {
            Rectangle iconRect = editItem.getIconPageRect(event.getIcon());
            showDialog(iconRect.getLeft(), iconRect.getTop());
          }
        }
      });

      timeChooser = new ScheduleSiTimeSelector();
      timeChooser.addDateCallbackHandler(new CallbackHandler<Date>()
      {
        @Override
        public void handle(Date object)
        {
          setValueAsDate(object);
        }
      });
    }
 
    public void setValueAsDate(Date date)
    {
      System.out.println("Setting date on editItem: "+date);
      editItem.setValue(date);
    }

    private void showDialog(int left, int top)
    {
      Date date = null;
      if (editItem.getValue() == null)
      {
        date = new Date();
      }
      else
      {
        System.out.println("ShowDialog got value: "+editItem.getValue());
        date = (Date) editItem.getValue();
      }
      timeChooser.setData(date);
      timeChooser.show();
      timeChooser.moveTo(left, top);
    }
  }
  
  private class ScheduleSiTimeSelector extends Dialog
  {

    private Date stashDate;
    private CallbackHandler<Date> dateHandler;
    
    private SelectItem ampmSelect;
    private SelectItem hourSelect;
    private SelectItem minuteSelect;

    private final DateTimeFormat dfDateTime = DateTimeFormat
        .getFormat("yyyy/MM/dd h:m:s a");
    private final DateTimeFormat dfDate = 
        DateTimeFormat.getFormat("yyyy/MM/dd");
    private final DateTimeFormat dfHour = DateTimeFormat.getFormat("h");
    private final DateTimeFormat dfMinute = DateTimeFormat.getFormat("m");
    private final DateTimeFormat dfAmpm = DateTimeFormat.getFormat("a");

    public ScheduleSiTimeSelector()
    {
      super();

      setAutoCenter(true);
      setIsModal(true);
      setShowHeader(true);
      setShowEdges(true);
      setMargin(0);
      setPadding(0);
      setEdgeSize(10);
      setWidth(300);
      setHeight(200);
      setDismissOnEscape(true);
      setDismissOnOutsideClick(true);
      setShowToolbar(false);
      setTitle("Select Build Execution Time");

      Map<String, Integer> bodyDefaults = new HashMap<String, Integer>();
      bodyDefaults.put("layoutLeftMargin", 5);
      setBodyDefaults(bodyDefaults);

      VLayout vlayout1 = new VLayout(5);
      vlayout1.setMembersMargin(5);
      vlayout1.setWidth100();
      
      LayoutSpacer spacer = new LayoutSpacer();
      spacer.setHeight(5);
      spacer.setWidth100();

      DynamicForm selForm = new DynamicForm();
      selForm.setWidth100();
      selForm.setTitleWidth(100);
      selForm.setAlign(Alignment.CENTER);
      hourSelect = createSelector("Hour", 1, 12, false);
      minuteSelect = createSelector("Minute", 0, 59, true);
      ampmSelect = createSelector("Meridian", 0, 0, false);
      
      selForm.setFields(hourSelect, minuteSelect, ampmSelect);
      
      HLayout hlayout1 = new HLayout(5);
      hlayout1.setWidth100();
      hlayout1.setAlign(Alignment.CENTER);

      Button set = new Button("Set");
      set.addClickHandler(new ClickHandler()
      {
        @Override
        public void onClick(ClickEvent event)
        {
          if (dateHandler != null)
          {
            dateHandler.handle(getData());
          }
          hide();
        }
      });

      Button cancel = new Button("Cancel");
      cancel.addClickHandler(new ClickHandler()
      {
        @Override
        public void onClick(ClickEvent event)
        {
          hide();
        }
      });
      
      hlayout1.setMembers(set, cancel);

      vlayout1.setMembers(spacer, selForm, spacer, hlayout1);
      
      addItem(vlayout1);
    }

    public Date getData()
    {
      String dateString = dfDate.format(stashDate) + " "
          + hourSelect.getValue() + ":" 
          + minuteSelect.getValue()
          + ":0 " + ampmSelect.getValue();
      
      System.out.println("Returning dateString: "+dateString);

      return dfDateTime.parse(dateString);
    }

    public void setData(Date date)
    {
      stashDate = date;
      hourSelect.setValue(dfHour.format(date));
      minuteSelect.setValue(dfMinute.format(date));
      ampmSelect.setValue(dfAmpm.format(date));
    }

    public void addDateCallbackHandler(CallbackHandler<Date> handler)
    {
      this.dateHandler = handler;
    }

    private SelectItem createSelector(String title, Integer min, 
        Integer max, Boolean pad)
    {
      SelectItem si = new SelectItem();
      if (max != 0)
      {
        LinkedHashMap<String, String>smap = 
          new LinkedHashMap<String, String>();
        for (Integer i = min; i <= max; i++)
        {
          String k = (pad 
              ? NumberFormat.getFormat("00").format(i) : i.toString());
          smap.put(i.toString(), k);
        }
        si.setValueMap(smap);
      }
      else
      {
        si.setValueMap("AM", "PM");
      }
         
      si.setTitle("<b>" + title + "</b>");
      si.setWidth(50);
      si.setAllowEmptyValue(false);
      si.setDefaultToFirstOption(true);
      
      return si;
    }
  }

  final DataSource siDS = new DataSource(){{

    setID("SchedInstDS");
      
    DataSourceTextField id = new DataSourceTextField("id");
    id.setHidden(true);
    id.setPrimaryKey(true);

    DataSourceTextField sid = new DataSourceTextField("sched_id");
    sid.setHidden(true);

    DataSourceTextField alldays = new DataSourceTextField("alldays");
    alldays.setHidden(true);

    DataSourceEnumField dow = new DataSourceEnumField("dow", "Day");
    dow.setValueMap("All Days", "Sunday", "Monday", "Tuesday", "Wednesday",
          "Thursday", "Friday", "Saturday");
    dow.setRequired(true);

    DataSourceDateTimeField time = new DataSourceDateTimeField("time");
    time.setTimeFormatter(TimeDisplayFormat.TOSHORTTIME);
    time.setRequired(true);

    setFields(id, sid, alldays, dow, time);

    Date recDate = DateTimeFormat
        .getFormat("yyyy-MM-dd H:m:s").parse("2012-08-12 8:0:0");
    
    Record rec = new Record();
    rec.setAttribute("id", "123");
    rec.setAttribute("sched_id", "666");
    rec.setAttribute("alldays", "1");
    rec.setAttribute("time", recDate);
    
    Record[] testData = {rec};
    
    setTestData(testData);
    setClientOnly(true);
  }};
}
