package com.google.sampling.experiential.client;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.sampling.experiential.shared.EventDAO;
import com.google.sampling.experiential.shared.ExperimentDAO;
import com.google.sampling.experiential.shared.InputDAO;
import com.google.sampling.experiential.shared.MapServiceAsync;
import com.google.sampling.experiential.shared.Output;

public abstract class AbstractExperimentExecutorPanel extends Composite {

  protected VerticalPanel mainPanel;
  protected ExperimentDAO experiment;
  protected List<InputExecutorPanel> inputsPanelsList;
  protected MapServiceAsync mapService;
  protected ExperimentListener experimentListener;

  public AbstractExperimentExecutorPanel(ExperimentListener experimentListener, 
                                         ExperimentDAO experiment, MapServiceAsync mapService) {
    this.experiment = experiment;
    this.mapService = mapService;
    this.experimentListener = experimentListener;
    inputsPanelsList = new ArrayList<InputExecutorPanel>();
    createLayout();
  }

  protected void createLayout() {
    createMainPanel();
    createExperimentHeader();    
    renderInputItems();    
    renderSaveButton();
    renderCancelButton();
  }

  protected abstract void renderInputItems();

  protected void createExperimentHeader() {
    Label label = new Label(experiment.getTitle());
    label.setStyleName("paco-HTML-Large");
    mainPanel.add(label);
  }

  private void createMainPanel() {
    mainPanel = new VerticalPanel();
    mainPanel.setSpacing(2);
    initWidget(mainPanel);
  }

  protected void renderSaveButton() {
    Button saveButton = new Button("Save");
    mainPanel.add(saveButton);
    saveButton.addClickHandler(new ClickHandler() {
      
      @Override
      public void onClick(ClickEvent event) {
        saveResponse();
      }
    });    
  }

  private void renderCancelButton() {
    Button cancelButton = new Button("Cancel");
    mainPanel.add(cancelButton);
    cancelButton.addClickHandler(new ClickHandler() {
      
      @Override
      public void onClick(ClickEvent event) {
        experimentListener.eventFired(ExperimentListener.EXPERIMENT_RESPONSE_CANCELED_CODE, experiment, true);
      }
    });    
  }

  protected void saveResponse() {
    EventDAO event = createEvent();    
    addOutputsToEvent(event);
    postEventToServer(event);
  }

  protected void postEventToServer(EventDAO event) {
    AsyncCallback<Void> asyncCallback = new AsyncCallback<Void>(){
  
      @Override
      public void onFailure(Throwable caught) {
        Window.alert("Could not save your response. Please try again.\n" + caught.getMessage());        
      }
  
      @Override
      public void onSuccess(Void result) {
        Window.alert("Success!");        
        experimentListener.eventFired(ExperimentListener.EXPERIMENT_RESPONSE_CODE, experiment, true);
      }
      
    };
    mapService.saveEvent(event, asyncCallback);    
  }

  protected void addOutputsToEvent(EventDAO event) {
    Map<String, String> outputs = new HashMap<String, String>();    
    for (int i=0; i < inputsPanelsList.size(); i++) {
      InputExecutorPanel inputPanel = inputsPanelsList.get(i);
      Output output = inputPanel.getValue();      
      outputs.put(output.getName(), output.getValue());
    }
    event.setWhat(outputs);
  }

  protected EventDAO createEvent() {
    EventDAO event = new EventDAO();
    event.setResponseTime(new Date());
    event.setExperimentName(experiment.getTitle());
    event.setExperimentId(experiment.getId());
    return event;
  }

}
@@ -483,24 +483,78 @@
 .Composite;%0A
+import com.google.gwt.user.client.ui.HorizontalPanel;%0A
 import com.g
@@ -1723,26 +1723,113 @@
 utItems();  
+%0A
   
+  HorizontalPanel buttonPanel = new HorizontalPanel();%0A    mainPanel.add(buttonPanel);
 %0A    renderS
@@ -1834,24 +1834,35 @@
 rSaveButton(
+buttonPanel
 );%0A    rende
@@ -1875,16 +1875,27 @@
 lButton(
+buttonPanel
 );%0A  %7D%0A%0A
@@ -2274,24 +2274,51 @@
 rSaveButton(
+HorizontalPanel buttonPanel
 ) %7B%0A    Butt
@@ -2349,35 +2349,37 @@
 on(%22Save%22);%0A    
-mai
+butto
 nPanel.add(saveB
@@ -2590,16 +2590,43 @@
 lButton(
+HorizontalPanel buttonPanel
 ) %7B%0A    
@@ -2665,35 +2665,37 @@
 (%22Cancel%22);%0A    
-mai
+butto
 nPanel.add(cance

clean up save cancel button layout