package org.inria.bmajwatcher.client.ui.scheduler;


import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.inria.bmajwatcher.client.i18n.BmajWatcherConstants;
import org.inria.bmajwatcher.client.services.BiomajLauncherServiceAsync;
import org.inria.bmajwatcher.client.services.SchedulingServiceAsync;
import org.inria.bmajwatcher.client.services.UserManagerServiceAsync;
import org.inria.bmajwatcher.client.ui.BankGridDataSource;
import org.inria.bmajwatcher.client.ui.confirmation.MessagePanel;
import org.inria.bmajwatcher.client.ui.styles.MainCss;
import org.inria.bmajwatcher.client.ui.styles.Resources;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
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.Image;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.MultipleAppearance;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.types.TimeFormatter;
import com.smartgwt.client.types.VisibilityMode;
import com.smartgwt.client.util.BooleanCallback;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.ImgButton;
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.DropEvent;
import com.smartgwt.client.widgets.events.DropHandler;
import com.smartgwt.client.widgets.events.DropOutEvent;
import com.smartgwt.client.widgets.events.DropOutHandler;
import com.smartgwt.client.widgets.events.DropOverEvent;
import com.smartgwt.client.widgets.events.DropOverHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.CheckboxItem;
import com.smartgwt.client.widgets.form.fields.RadioGroupItem;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.StaticTextItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.TimeItem;
import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
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.grid.events.CellContextClickEvent;
import com.smartgwt.client.widgets.grid.events.CellContextClickHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.SectionStack;
import com.smartgwt.client.widgets.layout.SectionStackSection;
import com.smartgwt.client.widgets.menu.Menu;
import com.smartgwt.client.widgets.menu.MenuItem;
import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;

/**
 * Creates the component that handles biomaj scheduled executions.
 * 
 * @author rsabas
 *
 */
public class Scheduler {

	private SectionStack tasks;
	private ListGrid mainGrid;
	private HorizontalPanel buttonPanel;
	private ScrollPanel container;
	
	private static final short NEW_TASK = 0;
	private static final short EDIT_TASK = 1;
	
	private final int MIN_HEIGHT = 446;
	
	private String login;
	
	private SchedulingServiceAsync schedulerService = SchedulingServiceAsync.INSTANCE;
	private MainCss css = Resources.INSTANCE.mainCss();
	private PushButton newTask;
	
	
	public Scheduler(ListGrid grid, String userKey) {
		
		mainGrid = grid;
		
		tasks = new SectionStack();
		tasks.setVisibilityMode(VisibilityMode.MULTIPLE);
		tasks.setWidth(270);
		tasks.setHeight(MIN_HEIGHT);
		tasks.setOverflow(Overflow.AUTO);
		
		newTask = new PushButton(new Image("images/appointment-new.png"));
		newTask.setTitle(BmajWatcherConstants.INSTANCE.newTask());
		newTask.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
			
			@Override
			public void onClick(com.google.gwt.event.dom.client.ClickEvent event) {
				showTaskEditor(NEW_TASK, "", "");
			}
		});
		
		final PushButton showCal = new PushButton(new Image("images/view-calendar.png"));
		showCal.setTitle("Calendar view");
		
		buttonPanel = new HorizontalPanel();
		buttonPanel.setHeight("35px");
		buttonPanel.add(newTask);
		buttonPanel.add(showCal);
		buttonPanel.setCellHorizontalAlignment(newTask, HasHorizontalAlignment.ALIGN_RIGHT);
		buttonPanel.setCellHorizontalAlignment(showCal, HasHorizontalAlignment.ALIGN_RIGHT);
		
		final HorizontalPanel schedButtons = new HorizontalPanel();
		schedButtons.addStyleName(css.schedulerButtons());
		schedButtons.setSpacing(2);

		
		// Refresh
		final Image imgRefreshSched = new Image("images/arrow-refresh.png");
		imgRefreshSched.setTitle("Refresh jobs");
		imgRefreshSched.addStyleName(css.imgPointer());
		imgRefreshSched.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
			
			@Override
			public void onClick(com.google.gwt.event.dom.client.ClickEvent event) {
				int size = tasks.getSections().length;
				for (int i = 0; i < size; i++) {
					tasks.removeSection(0);
				}
				loadJobs();
			}
		});

		schedButtons.add(imgRefreshSched);
		
		
		buttonPanel.add(schedButtons);
		buttonPanel.setCellWidth(schedButtons, "210px");
		buttonPanel.setCellHorizontalAlignment(schedButtons, HasHorizontalAlignment.ALIGN_RIGHT);
		buttonPanel.setCellVerticalAlignment(schedButtons, HasVerticalAlignment.ALIGN_MIDDLE);
		

		container = new ScrollPanel(tasks);
		container.setSize("270px", "446px");
		
		
		UserManagerServiceAsync.INSTANCE.getUserLoginFromKey(userKey, new AsyncCallback<String>() {
			
			@Override
			public void onSuccess(String result) {
				if (result != null) {
					login = result;
					
					
					UserManagerServiceAsync.INSTANCE.getAdminLogin(new AsyncCallback<String>() {
						
						@Override
						public void onSuccess(final String adminLogin) {
							final Image imgStartSched = new Image("images/normal-update.png");
							imgStartSched.setTitle("Start scheduler");
							imgStartSched.addStyleName(css.imgPointer());
							final Image imgStopSched = new Image("images/stop.png");
							imgStopSched.setTitle("Put scheduler on stand-by");
							imgStopSched.addStyleName(css.imgPointer());
							
							/*
							 *  Admin can start/stop scheduler
							 */
							if (adminLogin.equals(login)) {
								
								// Start
								imgStartSched.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
									
									@Override
									public void onClick(com.google.gwt.event.dom.client.ClickEvent event) {
										schedulerService.start(new AsyncCallback<Boolean>() {
											
											@Override
											public void onSuccess(Boolean result) {
												if (result) {
													imgStartSched.setVisible(false);
													imgStopSched.setVisible(true);
													tasks.setDisabled(false);
													newTask.setEnabled(true);
												} else {
													SC.warn("Could not start the scheduler");
												}
											}
											
											@Override
											public void onFailure(Throwable caught) {
												SC.warn("RPC error");
											}
										});
									}
								});
								
								// Stop
								imgStopSched.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
									
									@Override
									public void onClick(com.google.gwt.event.dom.client.ClickEvent event) {
										schedulerService.stop(new AsyncCallback<Boolean>() {
											
											@Override
											public void onSuccess(Boolean result) {
												if (result) {
													imgStartSched.setVisible(true);
													imgStopSched.setVisible(false);
													tasks.setDisabled(true);
													newTask.setEnabled(false);
												} else {
													SC.warn("Could not stop the scheduler");
												}
											}
											
											@Override
											public void onFailure(Throwable caught) {
												SC.warn("RPC failure");
											}
										});
									}
								});
								
								schedButtons.add(imgStartSched);
								schedButtons.add(imgStopSched);
								
							}
							
							// Check scheduler status
							schedulerService.isStarted(new AsyncCallback<Boolean>() {
										
								@Override
								public void onSuccess(Boolean result) {
									if (result) {
										if (login.equals(adminLogin)) { // if admin
											imgStartSched.setVisible(false);
											imgStopSched.setVisible(true);
										}
										newTask.setEnabled(true); 
										tasks.setDisabled(false);
									} else {
										if (login.equals(adminLogin)) { // if admin
											imgStartSched.setVisible(true);
											imgStopSched.setVisible(false);
										}
										newTask.setEnabled(false);
										tasks.setDisabled(true);
									}
								}
								
								@Override
								public void onFailure(Throwable caught) {
									SC.warn("RPC failure. Could not retrieve scheduler status");
								}
							});
						}
						
						@Override
						public void onFailure(Throwable caught) {
							SC.warn("RPC failure. Could not get admin login");
						}
					});
					
					
					
					loadJobs();
					
					showCal.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
						
						@Override
						public void onClick(com.google.gwt.event.dom.client.ClickEvent event) {
							TaskViewer viewer = new TaskViewer(login);
							viewer.show();
						}
					});
				}
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("RPC failure");
			}
		});
	}
	
	private void loadJobs() {
		SchedData.getInstance().clear();
		schedulerService.getJobs(login, new AsyncCallback<Map<String,List<String>>>() {
			
			@Override
			public void onSuccess(Map<String, List<String>> result) {
				Set<String> set = result.keySet();
				for (String str : set) {
					String[] tab = str.split(":");
					createTaskTab(SchedData.getInstance().addTask(login, tab[0], tab[1]), result.get(str));
				}
				resizeTasks();
				if (tasks.getSections().length == 0) {
					tasks.setVisible(false);
				}
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.say("Scheduler init failure");
			}
		});
	}
	
	/**
	 * Drag&drop grid that stores the banks for a given scheduled task.
	 *  
	 * @return
	 */
	private ListGrid getGrid(final String id, final List<String> banks) {

		final ListGrid bankList = new ListGrid();
		// testGrid.setWidth(250);
		bankList.setWidth100();
		// testGrid.setHeight(224);
		bankList.setEmptyMessage(BmajWatcherConstants.INSTANCE.emptyGridMessage());
		bankList.setCanAcceptDroppedRecords(true);
		bankList.setShowHeader(false);
		bankList.setBorder("none");

		
		if (banks != null) {
			UserManagerServiceAsync.INSTANCE.getAdminLogin(new AsyncCallback<String>() {
				
				@Override
				public void onSuccess(String result) {
					
					boolean admin = result.equals(login);
					// As users groups can be changed or bank can be deleted,
					// need to get the banks list logged user has access to.
					List<String> validBanks = new ArrayList<String>();
					for (ListGridRecord rec : mainGrid.getRecords()) {
						if (rec.getAttribute(BankGridDataSource.GROUP).equalsIgnoreCase("true") || admin)
							validBanks.add(rec.getAttribute(BankGridDataSource.NAME));
					}

					List<String> banksToRemoveFromTask = new ArrayList<String>();
					for (String bank : banks) {
						if (!validBanks.contains(bank)) {
							banksToRemoveFromTask.add(bank);
						} else {
							ListGridRecord rec = new ListGridRecord();
							rec.setAttribute(BankGridDataSource.NAME, bank);
							bankList.addData(rec);
						}
					}
					
					schedulerService.removeBanksFromTrigger(banksToRemoveFromTask.toArray(new String[banksToRemoveFromTask.size()]),
							SchedData.getInstance().getName(id), new AsyncCallback<Void>() {
								
								@Override
								public void onSuccess(Void result) {
								}
								
								@Override
								public void onFailure(Throwable caught) {
									SC.warn("RPC failure");
								}
							});
				}
				
				@Override
				public void onFailure(Throwable caught) {
					SC.warn("RPC failure");
				}
			});
		}
		
		/*
		 * Right click interception
		 */
		bankList.addCellContextClickHandler(new CellContextClickHandler() {
			
			@Override
			public void onCellContextClick(CellContextClickEvent event) {
				event.cancel();
				showPopupMenu(bankList, SchedData.getInstance().getName(id));
			}
		});

		/*
		 * Actions when a record is brought over the grid.
		 */
		bankList.addDropOverHandler(new DropOverHandler() {

			@Override
			public void onDropOver(DropOverEvent event) {
				bankList.setBorder("1px solid GREEN");
			}
		});
		/*
		 * Actions when a record is dropped in the grid.
		 */
		bankList.addDropHandler(new DropHandler() {

			@Override
			public void onDrop(DropEvent event) {
				bankList.setBorder("none");

				ListGridRecord[] recs = mainGrid.getSelection();
				String[] banks = new String[recs.length];
				boolean exists = false;
				for (int i = 0; i < recs.length && !exists; i++) {
					banks[i] = recs[i].getAttribute(BankGridDataSource.NAME);
					if (gridContainsRecord(bankList, banks[i]))
						exists = true;
				}
				
				if (exists)
					event.cancel();
				else {
					schedulerService.addBanksToTrigger(banks,
							SchedData.getInstance().getName(id), new AsyncCallback<Void>() {
						
						@Override
						public void onSuccess(Void result) {
						}
						
						@Override
						public void onFailure(Throwable caught) {
							SC.say("Failure");
						}
					});
				}
			}
		});
		/*
		 * Actions when the record is no longer over the grid.
		 */
		bankList.addDropOutHandler(new DropOutHandler() {

			@Override
			public void onDropOut(DropOutEvent event) {
				bankList.setBorder("none");
			}
		});

		// Grid that will display the name of the dropped records
		ListGridField bankName = new ListGridField(BankGridDataSource.NAME, "Name");
		bankList.setFields(bankName);
		
		return bankList;
		
	}
	
	private boolean gridContainsRecord(final ListGrid grid, String name) {
		for (ListGridRecord rec : grid.getRecords()) {
			if (rec.getAttribute(BankGridDataSource.NAME).equals(name))
				return true;
		}
		return false;
	}
	
	
	/**
	 * Context menu that displays options for the banks in a scheduled task.
	 * 
	 * @param bankList
	 */
	private void showPopupMenu(final ListGrid bankList, final String taskLabel) {
		
		Menu menu = new Menu();
		MenuItem itemRemove = new MenuItem(BmajWatcherConstants.INSTANCE.remove());
		itemRemove.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler() {
			
			@Override
			public void onClick(MenuItemClickEvent event) {
				
				ListGridRecord[] recs = bankList.getSelection();
				String[] banks = new String[recs.length];
				for (int i = 0; i < recs.length; i++) {
					banks[i] = recs[i].getAttribute(BankGridDataSource.NAME);
				}
				
				/*
				 * Remove bank
				 */
				schedulerService.removeBanksFromTrigger(banks, taskLabel, new AsyncCallback<Void>() {
					
					@Override
					public void onSuccess(Void result) {
					}
					
					@Override
					public void onFailure(Throwable caught) {
						SC.say("Failure");
					}
				});
				bankList.removeSelectedData();
				
			}
		});
		
		menu.addItem(itemRemove);
		menu.showContextMenu();
	}
	
	/**
	 * Creates the tab for a scheduled task.
	 * That tab contains the grid that stores the banks to be updated
	 * at a given time.
	 * 
	 */
	private void createTaskTab(final String id, final List<String> banks) {
		
		final SectionStackSection task = new SectionStackSection(SchedData.getInstance().getName(id));
		task.setID(task.toString());
		final ListGrid content = getGrid(id, banks);
		task.setItems(content);
		
		
		/*
		 * Start all banks
		 */
		ImgButton allUpdatesBtn = new ImgButton();
		allUpdatesBtn.setSrc("update_all.png");
		allUpdatesBtn.setSize(16);
		allUpdatesBtn.setShowRollOver(false);
		allUpdatesBtn.setShowDown(false);
		allUpdatesBtn.setTooltip("Update all banks of this schedule");
		allUpdatesBtn.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				
				if (content.getRecords().length > 0) {
					
					final StringBuilder toUpdate = new StringBuilder();
					for (ListGridRecord bank : content.getRecords()) {
						toUpdate.append(bank.getAttribute(BankGridDataSource.NAME) + " ");
					}
					
					System.out.println("TO update : " + toUpdate.toString());
					
					SC.confirm("Confirm update start ?", new BooleanCallback() {
						
						@Override
						public void execute(Boolean value) {
							if (value) {
								
								BiomajLauncherServiceAsync.INSTANCE.startUpdate(toUpdate.toString().trim(), new AsyncCallback<Boolean>() {
									
									@Override
									public void onSuccess(Boolean result) {
										if (result) {
											MessagePanel.showMessage("Updates started");
										} else {
											SC.warn("Updates could no be started");
										}
									}
									
									@Override
									public void onFailure(Throwable caught) {
										SC.warn("RPC failure");
									}
								});
							}
						}
					});
				}
			}
		});
		
		/*
		 * Edit task
		 */
		ImgButton editBtn = new ImgButton();
		editBtn.setSrc("document-properties.png");
		editBtn.setSize(16);
		editBtn.setShowRollOver(false);
		editBtn.setShowDown(false);
		editBtn.setTooltip(BmajWatcherConstants.INSTANCE.editTask());
		editBtn.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				
				showTaskEditor(EDIT_TASK, id, task.getID());
			}
		});
		
		/*
		 * Delete task
		 */
		ImgButton removeBtn = new ImgButton();
		removeBtn.setSrc("edit-delete.png");
		removeBtn.setSize(16);
		removeBtn.setShowRollOver(false);
		removeBtn.setShowDown(false);
		removeBtn.setTooltip(BmajWatcherConstants.INSTANCE.deleteTask());
		removeBtn.addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				
				SC.confirm("Confirm task deletion ?", new BooleanCallback() {
					
					@Override
					public void execute(Boolean value) {
						if (value) {
							
							schedulerService.deleteTrigger(SchedData.getInstance().getName(id), new AsyncCallback<Void>() {
								
								@Override
								public void onSuccess(Void result) {
									SchedData.getInstance().deleteTask(id);
									tasks.removeSection(task.toString());
									resizeTasks();
									if (tasks.getSections().length == 0)
										tasks.setVisible(false);
								}
								
								@Override
								public void onFailure(Throwable caught) {
									SC.say("Failure");
								}
							});
						}
					}
				});
			}
		});
		
		task.setControls(allUpdatesBtn, editBtn, removeBtn);
		task.setExpanded(true);

		tasks.addSection(task);
		tasks.setVisible(true);
		
	}
	
	private void resizeTasks() {
		int height = tasks.getSections().length * 80;
		if (height > MIN_HEIGHT) {
			tasks.setWidth(254);
			tasks.setHeight(height);
		} else {
			tasks.setWidth(270);
			tasks.setHeight(MIN_HEIGHT);
		}
	}
	
	private void editTaskTab(String id, String label, String expr) {
		tasks.setSectionTitle(id, label);
	}
	
	private void updateCronField(DynamicForm assistedForm, DynamicForm manualForm, SelectItem selectDaysInWeek,
			SelectItem selectDaysInMonth, TimeItem updateTime, RadioGroupItem recurrenceRadio) {
		String date = "";
		int hours = 0;
		int minutes = 0;
		if ((date = assistedForm.getValueAsString(updateTime.getName())) != null) {
			// Expected format : Fri Oct 01 2010 00:00:00...
			date = date.substring(16, 21);
			hours = Integer.valueOf(date.substring(0,2));
			minutes = Integer.valueOf(date.substring(3,5));
		}
			
		String days;
		if (assistedForm.getValueAsString(recurrenceRadio.getName()).equals("Weekly")) {
			days = assistedForm.getValueAsString(selectDaysInWeek.getName());
			if (days == null)
				days = "*";
			manualForm.setValue("cronExpr", "0 " + minutes + " " + hours + " ? * " + days);
		} else {
			days = assistedForm.getValueAsString(selectDaysInMonth.getName());
			if (days == null)
				days = "*";
			manualForm.setValue("cronExpr", "0 " + minutes + " " + hours + " " + days + " * ?");
		}
	}
	
	/**
	 * Modal window for scheduled task creation and edition.
	 * 
	 */
	private void showTaskEditor(final int mode, final String dataId, final String taskId) {
		final Window winModal = new Window();
//		winModal.setStyleName(CSSResources.INSTANCE.mainCss().taskEditor());
		winModal.setWidth(500);
		winModal.setHeight(350);
		winModal.setTitle(BmajWatcherConstants.INSTANCE.editTask());
		winModal.setShowMinimizeButton(false);
		winModal.setIsModal(true);
		winModal.setMembersMargin(10);
		winModal.setShowModalMask(true);
		winModal.centerInPage();
		
		final DynamicForm mainForm = new DynamicForm();
		final Canvas assistedCanvas = new Canvas();
		final DynamicForm assistedForm = new DynamicForm();
		assistedForm.addStyleName(Resources.INSTANCE.mainCss().cronCreationPanel());
		final DynamicForm manualForm = new DynamicForm();
		
		TextItem label = new TextItem("cronLabel", "Label");
		label.setWidth(350);
		TextItem expr = new TextItem("cronExpr", "Cron expression");
		expr.setWidth(350);
		
		final CheckboxItem assistedCheck = new CheckboxItem("assistedCheck", "Assisted cron creation");
		assistedCheck.setValue(true);
		assistedCheck.addChangedHandler(new ChangedHandler() {
			
			@Override
			public void onChanged(ChangedEvent event) {
				if ((Boolean) mainForm.getValue("assistedCheck")) {
					assistedCanvas.show();
					winModal.resizeTo(500, 350);
				} else {
					assistedCanvas.hide();
					winModal.resizeTo(500, 230);
				}
			}
		});
		
		final SelectItem selectDaysInWeek = new SelectItem();
		selectDaysInWeek.setTitle("Select days in week");
		selectDaysInWeek.setMultiple(true);
		selectDaysInWeek.setMultipleAppearance(MultipleAppearance.PICKLIST);
		selectDaysInWeek.setValueMap("MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN");
		
		final SelectItem selectDaysInMonth = new SelectItem();
		selectDaysInMonth.setTitle("Select days in month");
		selectDaysInMonth.setMultiple(true);
		selectDaysInMonth.setMultipleAppearance(MultipleAppearance.PICKLIST);
		selectDaysInMonth.setValueMap("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31");
		selectDaysInMonth.setVisible(false);

		final RadioGroupItem recurrenceRadio = new RadioGroupItem("recurrenceRadio", "Recurrence");
		recurrenceRadio.setValueMap("Weekly", "Monthly");		
		recurrenceRadio.setValue("Weekly");
		
		final TimeItem updateTime = new TimeItem("updateTime", "Update time");
		updateTime.setDisplayFormat(TimeFormatter.TOSHORT24HOURTIME);
		
		recurrenceRadio.addChangedHandler(new ChangedHandler() {
			
			@Override
			public void onChanged(ChangedEvent event) {
				if (assistedForm.getValueAsString("recurrenceRadio").equals("Weekly")) {
					selectDaysInWeek.show();
					selectDaysInMonth.hide();
				} else {
					selectDaysInMonth.show();
					selectDaysInWeek.hide();
				}
				updateCronField(assistedForm, manualForm, selectDaysInWeek, selectDaysInMonth, updateTime, recurrenceRadio);
			}
		});
		updateTime.addChangedHandler(new ChangedHandler() {
			
			@Override
			public void onChanged(ChangedEvent event) {
				updateCronField(assistedForm, manualForm, selectDaysInWeek, selectDaysInMonth, updateTime, recurrenceRadio);
			}
		});
		selectDaysInWeek.addChangedHandler(new ChangedHandler() {
			
			@Override
			public void onChanged(ChangedEvent event) {
				updateCronField(assistedForm, manualForm, selectDaysInWeek, selectDaysInMonth, updateTime, recurrenceRadio);
			}
		});
		selectDaysInMonth.addChangedHandler(new ChangedHandler() {
			
			@Override
			public void onChanged(ChangedEvent event) {
				updateCronField(assistedForm, manualForm, selectDaysInWeek, selectDaysInMonth, updateTime, recurrenceRadio);
			}
		});
		
		
		StaticTextItem example = new StaticTextItem("example", "");
		example.setOutputAsHTML(false);
		example.setWidth(350);
		example.setWrap(true);
		
		
		assistedForm.setWidth(250);
		assistedForm.setPadding(5);
		assistedForm.setItems(recurrenceRadio, selectDaysInMonth, selectDaysInWeek, updateTime);
		
		manualForm.setItems(expr, example);
		manualForm.setValue("example", "<b>Examples :</b><br/>0 0/5 * * * ? : <i>Fire every 5 minutes</i><br/>" +
				"0 15 10 15 * ? : <i>Fire at 10:15am on the 15th day of every month</i>");
		
		mainForm.setItems(label, assistedCheck);
		
		if (mode == EDIT_TASK) {
			mainForm.setValue("cronLabel", SchedData.getInstance().getName(dataId));
			manualForm.setValue("cronExpr", SchedData.getInstance().getCron(dataId));
		}
		
		Button createTask = new Button(BmajWatcherConstants.INSTANCE.saveTask());
		createTask.setWidth("60px");
		Button cancelTask = new Button("Cancel");
		cancelTask.setWidth("60px");
		HLayout btnLayout = new HLayout();
		btnLayout.setPadding(10);
		btnLayout.addMember(createTask);
		btnLayout.addMember(cancelTask);
		btnLayout.setAlign(Alignment.CENTER);

		cancelTask.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
			
			@Override
			public void onClick(com.google.gwt.event.dom.client.ClickEvent event) {
				winModal.hide();
			}
		});
		
		createTask.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
			
			@Override
			public void onClick(com.google.gwt.event.dom.client.ClickEvent event) {
				final String newLabel = mainForm.getValueAsString("cronLabel");
				final String newCron = manualForm.getValueAsString("cronExpr");
				
				if (newLabel != null && newCron != null &&
						!newLabel.trim().isEmpty() && !newCron.trim().isEmpty()) {
				
					if (mode == EDIT_TASK) {

						final String exp = SchedData.getInstance().getCron(dataId);
						final String lbl = SchedData.getInstance().getName(dataId);
						/*
						 * Modify cron
						 */
						if (!newCron.equals(exp)) {
							schedulerService.setCron(lbl, newCron, new AsyncCallback<Boolean>() {
								
								@Override
								public void onSuccess(Boolean result) {
									if (result) {
										winModal.hide();
										SchedData.getInstance().changeCron(dataId, newCron);
									}
									else
										SC.warn("Cron syntax error");
								}
								
								@Override
								public void onFailure(Throwable caught) {
									SC.warn("Failure");
								}
							});
						}
						/*
						 * Modify name
						 */
						if (!newLabel.equals(lbl)) {
							if (!SchedData.getInstance().jobExists(login, newLabel)) {
								SchedData.getInstance().changeName(dataId, newLabel);
								schedulerService.renameTrigger(lbl, newLabel, new AsyncCallback<Boolean>() {
									
									@Override
									public void onSuccess(Boolean result) {
										if (!result)
											SC.warn("Task name already exists");
										else
											winModal.hide();
									}
									
									@Override
									public void onFailure(Throwable caught) {
										SC.say("Failure");
									}
								});
								editTaskTab(taskId, newLabel, newCron);
							} else {
								SC.warn("Task name already exists");
							}
						}
					/*
					 * Create task
					 */
					} else {
						if (!SchedData.getInstance().jobExists(login, newLabel)) {
							schedulerService.createTrigger(login, newLabel, newCron, new AsyncCallback<Integer>() {
								
								@Override
								public void onSuccess(Integer result) {
									if (result > 0) {
										winModal.hide();
										createTaskTab(SchedData.getInstance().addTask(login, newLabel, newCron), null);
										resizeTasks();
									} else if (result < 0)
										SC.warn("Cron syntax error");
									else
										SC.warn("Task name already exists");
								}
								
								@Override
								public void onFailure(Throwable caught) {
									SC.warn("Failure");
								}
							});
						} else {
							SC.warn("Task name already exists");
						}
					}
				} else {
					SC.warn("Empty fields are not allowed !");
				}
			}
		});
			
		winModal.addItem(mainForm);
		assistedCanvas.setWidth100();
		assistedCanvas.addChild(assistedForm);
		winModal.addItem(assistedCanvas);
		winModal.addItem(manualForm);
		winModal.addItem(btnLayout);
		
		winModal.show();
	}
	
	public void showBankSection(String bankName) {
		SectionStackSection[] sections = tasks.getSections();
		for (int i = 0; i < sections.length; i++) {
			for (Canvas canvas : sections[i].getItems()) {
				if (canvas instanceof ListGrid) {
					ListGrid grid = (ListGrid) canvas;
					for (ListGridRecord record : grid.getRecords()) {
						if (record.getAttribute(BankGridDataSource.NAME).equals(bankName)) {
							collapseAll();
							tasks.expandSection(i);
							return;
						}
					}
				}
			}
		}
		collapseAll();
	}
	
	private void collapseAll() {
		int length = tasks.getSections().length;
		for (int i = 0; i < length; i++) {
			tasks.collapseSection(i);
		}
	}
	
	/**
	 * Returns the panel that contains the scheduler elements.
	 *  
	 * @return
	 */
	public Panel getContainer() {
		return container;
	}
	
	public Panel getButtonPanel() {
		return buttonPanel;
	}

}
