package com.tempusnova.lib.gwt;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.kohls.gae.client.gwt.forms.DisabledForms;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.ResultSet;
import com.smartgwt.client.rpc.RPCCallback;
import com.smartgwt.client.rpc.RPCManager;
import com.smartgwt.client.rpc.RPCRequest;
import com.smartgwt.client.rpc.RPCResponse;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.FetchMode;
import com.smartgwt.client.types.PromptStyle;
import com.smartgwt.client.types.RPCTransport;
import com.smartgwt.client.types.SortDirection;
import com.smartgwt.client.util.JSOHelper;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Button;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.events.CloseClickEvent;
import com.smartgwt.client.widgets.events.CloseClickHandler;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.grid.events.RecordDoubleClickEvent;
import com.smartgwt.client.widgets.grid.events.RecordDoubleClickHandler;
import com.smartgwt.client.widgets.grid.events.RowContextClickEvent;
import com.smartgwt.client.widgets.grid.events.RowContextClickHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.Layout;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
import com.smartgwt.client.widgets.toolbar.ToolStripButton;
import com.tempusnova.lib.gwt.BaseDS.AnnotationInfo;
import com.tempusnova.lib.gwt.BaseDS.EntityInfo;

public class EntityGridPane extends EntityLayout implements RecordDoubleClickHandler, RowContextClickHandler
{
  UIInfo info;
  protected EntityListGrid listGrid;
  FilterSortBuilderDialog filterBuilder;

  public EntityGridPane(final UIInfo info)
  {
    info.getDataSource().setWillHandleAdvancedCriteria(true);
    this.info = info;
    final EntityInfo entityInfo = info.getDataSource().getEntityInfo();
    boolean isDisabled = DisabledForms.getEnums().contains(entityInfo.getName().toUpperCase());

    final int pageSize;
    if (entityInfo.hasAnnotation("PageSize"))
    {
      AnnotationInfo a = entityInfo.getAnnotation("PageSize");
      pageSize = (Integer) a.getAttribute("size");
    }
    else
      pageSize = 100;

    listGrid = new EntityListGrid() {
      {
        ResultSet resultSet = new ResultSet();
        resultSet.setUseClientFiltering(false);
        resultSet.setUseClientSorting(false);
        setDataProperties(resultSet);

        setDataPageSize(pageSize);
        setDataFetchMode(FetchMode.PAGED);
        setFilterOnKeypress(false);
        setAutoFetchData(false);
        setCanSort(false);
      }
    };

    listGrid.addRecordDoubleClickHandler(this);
    listGrid.addRowContextClickHandler(this);
    listGrid.setSortDirection(SortDirection.DESCENDING);
    listGrid.setFetchWhenOpened(true);

    List<ListGridField> listGridFields = new ArrayList<ListGridField>();
    for (ListGridField lgf : info.getListGridFields())
    {
      listGridFields.add(lgf);
      // Sort by created date
      if ("created".equals(lgf.getName()))
        listGrid.setSortField("created");
    }

    listGrid.setDataSource(info.getDataSource(), listGridFields.toArray(new ListGridField[0]));

    ToolStripButton selectAllButton = new ToolStripButton("Select All");
    selectAllButton.setAutoFit(true);
    selectAllButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event)
      {
        if (listGrid.getRecordList() != null && listGrid.getRecordList().isCreated() && !listGrid.getRecordList().isEmpty())
        {
          if (listGrid.getResultSet().allMatchingRowsCached() || listGrid.getResultSet().allRowsCached())
          {
            listGrid.selectRecords(listGrid.getRecords());
          }
          else
          {
            int recordCount = listGrid.getRecordList().getLength();
            for (int i=0; i < recordCount; i++)
            {
              if (!listGrid.getResultSet().rowIsLoaded(i) && i > 0)
              {
                Record[] records = listGrid.getRecordList().getRange(0, i); 
                listGrid.selectRecords(records);
                break;
              }
            }
          }
        }
      }
    });
    
    ToolStripButton wakeupButton = new ToolStripButton();
    if (entityInfo.hasAnnotation("Wakeup") || entityInfo.hasAnnotation("Remind"))
    {
      if (entityInfo.hasAnnotation("Wakeup"))
        wakeupButton.setTitle((String) entityInfo.getAnnotation("Wakeup").getAttribute("buttonLabel"));
      else if (entityInfo.hasAnnotation("Remind"))
        wakeupButton.setTitle((String) entityInfo.getAnnotation("Remind").getAttribute("buttonLabel"));
      wakeupButton.setAutoFit(true);
      wakeupButton.addClickHandler(new ClickHandler() {
        @Override
        public void onClick(ClickEvent event)
        {
          StringBuilder s = new StringBuilder();
          final ListGridRecord[] records = listGrid.getSelectedRecords();
          if (records != null && records.length > 0)
          {
            for (ListGridRecord r : records)
            {
              s.append(r.getAttribute("id"));
              s.append(",");
            }
            if (s.length() > 0)
              s.deleteCharAt(s.lastIndexOf(","));
          }
          else
          {
            SC.say("Please select at least one form in the grid to perform this operation.");
            return;
          }
          
          String entity = entityInfo.getName();
          String ids = s.toString();
          
          RPCRequest request = new RPCRequest();
          request.setSendNoQueue(true);
          request.setUseSimpleHttp(true);
          request.setWillHandleError(true);
          request.setShowPrompt(true);
          request.setPromptStyle(PromptStyle.CURSOR);
          request.setActionURL("/entitywaker");
          request.setTransport(RPCTransport.XMLHTTPREQUEST);
          Map<String,String> params = new HashMap<String,String>();
          params.put("entity", entity);
          params.put("ids", ids);
          request.setParams(params);

          RPCManager.sendRequest(request, new RPCCallback () {
            @Override
            public void execute(RPCResponse response, Object rawData, RPCRequest request)
            {
              if (response.getStatus() == RPCResponse.STATUS_SUCCESS)
              {
                JavaScriptObject resp = JSOHelper.eval((String) rawData);
                int entitiesWoken = JSOHelper.getAttributeAsInt(resp, "entitiesWoken");
                SC.say(entitiesWoken + " of " + records.length + " selected requests were processed successfully.");
              }
              else
              {
                SC.say("An error occurred while processing "+records.length+" selected requests, please try again.");
              }
            }
          });
        }
      });
    }

    ToolStripButton reloadButton = new ToolStripButton("Refresh");
    reloadButton.setAutoFit(true);
    reloadButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event)
      {
        final ResultSet rs = listGrid.getResultSet();
        if (rs != null)
        {
          rs.invalidateCache();
        }
        else
          listGrid.fetchData();
      }
    });

    ToolStripButton exportButton = new ToolStripButton("Export");
    exportButton.setAutoFit(true);
    exportButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event)
      {
        Window w = new EntityExportDesignerDialog(listGrid);
        w.show();
      }
    });

    ToolStripButton stateChangeButton = new ToolStripButton("State Change");
    stateChangeButton.setAutoFit(true);
    stateChangeButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event)
      {
        Record[] selectedRecords = listGrid.getSelectedRecords();
        if (selectedRecords == null || selectedRecords.length == 0)
          return;
        Map<String,String> commonToStates = null;
        List<Record> recordList = Arrays.asList(selectedRecords);
        Iterator<Record> it = recordList.iterator();
        do
        {
          Map<String,String> toStates = new HashMap<String,String>();
          Record r = it.next();
          Record workflowStatus = r.getAttributeAsRecord("workflowStatus");
          Record[] nextTransitions = workflowStatus.getAttributeAsRecordArray("nextTransitions");
          for (Record t : nextTransitions)
            toStates.put(t.getAttribute("to"),t.getAttribute("name"));
          if (commonToStates == null)
            commonToStates = toStates;
          else
            commonToStates.keySet().retainAll(toStates.keySet());
          if (commonToStates.isEmpty())
          {
            SC.say("No common state transitions found");
            return;
          }
        } while (it.hasNext());

        new BulkStateChangeDialog(EntityGridPane.this.info.getDataSource(),commonToStates,selectedRecords).show();
      }
    });

    ToolStripButton localButton = new ToolStripButton("Filter/Sort Current View");
    localButton.setAutoFit(true);
    localButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event)
      {
        showLocalEntityGrid();
      }
    });

    ToolStripButton filterButton = new ToolStripButton("New Search");
    filterButton.setAutoFit(true);
    filterButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event)
      {
        if (filterBuilder == null)
          new FilterSortBuilderDialog(listGrid, entityInfo).show();
        else
          filterBuilder.show();
      }
    });

    final Label dsName = new Label();
    dsName.setContents("<b>"+listGrid.getDataSource().getTitle()+"</b>");
    dsName.setWrap(false);
    dsName.setAutoFit(true);

    ToolStrip toolStrip = new ToolStrip();
    toolStrip.setWidth100();
    toolStrip.addSpacer(5);
    toolStrip.addMember(dsName);
    toolStrip.addFill();
    toolStrip.addButton(selectAllButton);
    
    if (entityInfo.hasAnnotation("Workflow") &&
        (Boolean) entityInfo.getAnnotation("Workflow").getAttribute("_isAdmin") &&
        (entityInfo.hasAnnotation("Wakeup") || entityInfo.hasAnnotation("Remind")))
    {
      toolStrip.addButton(wakeupButton);
    }
    toolStrip.addButton(stateChangeButton);
    toolStrip.addButton(exportButton);
    toolStrip.addButton(localButton);
    toolStrip.addButton(reloadButton);
    toolStrip.addButton(filterButton);

    final Label gridStatus = new Label();
    gridStatus.setContents("");
    gridStatus.setWrap(false);
    gridStatus.setAutoFit(true);

    ToolStrip footer = new ToolStrip();
    footer.setWidth100();
    footer.addSpacer(5);
    footer.addMember(gridStatus);

    // Edit buttons setup
    IButton copyButton = new IButton("Copy");
    IButton newButton = new IButton("New");
    newButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event)
      {
        createNewEntity();
      }
    });

    if (entityInfo.hasAnnotation("Workflow"))
    {
      @SuppressWarnings("unchecked")
      List<String> createTrans = (List<String>) info.getDataSource().getEntityInfo().getAnnotation("Workflow").getAttribute("_createTransitions");
      if (createTrans.isEmpty())
      {
        newButton.disable();
        copyButton.disable();
      }
    }
    if(isDisabled) {
      newButton.disable();
      copyButton.disable();
    }
    if (!entityInfo.hasAnnotation("DisableCopying"))
    {
      copyButton.addClickHandler(new ClickHandler() {
        @Override
        public void onClick(ClickEvent event)
        {
          Record selected = listGrid.getSelectedRecord();
          if (selected != null)
          {
            copyExistingEntity(selected, entityInfo);
          }
        }
      });
    }

    IButton editButton = new IButton("Detail");
    editButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event)
      {
        Record selected = listGrid.getSelectedRecord();
        if (selected != null)
        {
          editExistingEntity(selected);
        }
      }
    });

    IButton deleteButton = new IButton("Delete");
    deleteButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event)
      {
        delete();
      }
    });

    IButton printButton = new IButton("Print Preview");
    printButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event)
      {
        print();
      }
    });
    
    HLayout buttonLayout = new HLayout(5);
    buttonLayout.setAlign(Alignment.RIGHT);
    buttonLayout.addMember(newButton);
    if (!entityInfo.hasAnnotation("DisableCopying"))
      buttonLayout.addMember(copyButton);
    buttonLayout.addMember(editButton);
    buttonLayout.addMember(printButton);
    buttonLayout.addMember(deleteButton);

    addMember(toolStrip);
    addMember(listGrid);
    addMember(footer);
    addMember(buttonLayout);
  }

  protected void delete()
  {
    ListGridRecord[] records = listGrid.getSelectedRecords();
    if (records.length == 0)
      return;

    int nbrOfRecords = records.length;
    String[] creators = new String[nbrOfRecords];

    for (int i = 0; i < nbrOfRecords; i++)
    {
      ListGridRecord record = records[i];
      String creator = record.getAttribute("creator");

      if (creator == null || creator.trim().equals(""))
        creator = null;

      creators[i] = creator;
    }

    final Window window = new Window();
    window.setAutoCenter(true);
    window.setTitle("Warning");
    window.setWidth(300);
    window.setHeight(140);
    window.setShowMinimizeButton(false);
    window.setIsModal(true);
    window.setShowModalMask(true);
    window.addCloseClickHandler(new CloseClickHandler() {
      @Override
      public void onCloseClick(CloseClickEvent event)
      {
        window.hide();
      }
    });

    Label label = null;
    if (listGrid.getSelectedRecords().length > 1)
    {
      label = new Label("Are you sure you want delete the "+ listGrid.getSelectedRecords().length +" selected forms?");
    }
    else
    {
      label = new Label("Are you sure you want to delete this form created by " + creators[0] + "?");
    }

    label.setWrap(true);
    label.setHeight(25);
    label.setAlign(Alignment.CENTER);

    Button cancelButton = new Button("Cancel");
    cancelButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event)
      {
        window.hide();
      }
    });

    Button continueButton = new Button("Yes");
    continueButton.setLeft(165);
    continueButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event)
      {
        window.hide();
        listGrid.removeSelectedData();
      }
    });

    Layout buttonLayout = new Layout();
    buttonLayout.addChild(cancelButton);
    buttonLayout.addChild(continueButton);
    buttonLayout.setHeight(continueButton.getHeight());
    buttonLayout.setTop(50);

    VLayout contentsLayout = new VLayout();
    contentsLayout.setLeft(10);
    contentsLayout.setTop(40);
    contentsLayout.setHeight(buttonLayout.getHeight() + label.getHeight());
    contentsLayout.setWidth(window.getWidth() - 35);
    contentsLayout.addMember(label);
    contentsLayout.addChild(buttonLayout);

    window.addChild(contentsLayout);
    window.show();
  }
  
  protected void print()
  {
    ListGridRecord[] records = listGrid.getSelectedRecords();
    if (records.length == 0)
      return;
    
    String entity = info.getDataSource().getID();
    StringBuilder s = new StringBuilder();
    for (ListGridRecord r : records)
    {
      s.append(r.getAttribute("id"));
      s.append(",");
    }
    if (s.length() > 0)
      s.deleteCharAt(s.lastIndexOf(","));
    
    com.google.gwt.user.client.Window.open(GWT.getHostPageBaseURL() + "printPreview?entity=" + entity + "&ids="+s.toString(), "Print", "");
  }
  
  protected void showLocalEntityGrid()
  {
    if (listGrid.getRecordList() != null && listGrid.getRecordList().isCreated() && !listGrid.getRecordList().isEmpty())
    {
      if (listGrid.isGrouped())
      {
        new LocalEntityGridPane(info, listGrid.getRecords()).show();
      }
      else if (listGrid.getResultSet().allMatchingRowsCached() || listGrid.getResultSet().allRowsCached())
      {
        new LocalEntityGridPane(info, listGrid.getRecords()).show();
      }
      else
      {
        int recordCount = listGrid.getRecordList().getLength();
        for (int i=0; i < recordCount; i++)
        {
          if (!listGrid.getResultSet().rowIsLoaded(i) && i > 0)
          {
            Record[] records = listGrid.getRecordList().getRange(0, i); 
            new LocalEntityGridPane(info, records).show();
            break;
          }
        }
      }
    }
    else
      SC.say("There are no forms available to view in Local mode.");
  }

  @Override
  public void onRowContextClick(RowContextClickEvent event)
  {
    event.cancel();
  }

  @Override
  public void onRecordDoubleClick(RecordDoubleClickEvent event)
  {
    editExistingEntity(event.getRecord());
  }
  
  public EntityListGrid getListGrid()
  {
    return listGrid;
  }

  protected void createNewEntity()
  {
    new EntityFormWindow(info).show();
  }

  private void copyExistingEntity(Record record, EntityInfo entityInfo)
  {
    new EntityFormWindow(info, listGrid.createCopy(record, entityInfo), true).show();
  }

  protected void editExistingEntity(Record record)
  {
    new EntityFormWindow(info, record).show();
  }
}
