package org.inria.bmajwatcher.client.ui;

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

import org.inria.bmajwatcher.client.i18n.BmajWatcherConstants;
import org.inria.bmajwatcher.client.services.AuthenticationServiceAsync;
import org.inria.bmajwatcher.client.services.BankDetailServiceAsync;
import org.inria.bmajwatcher.client.services.BankRemovalServiceAsync;
import org.inria.bmajwatcher.client.services.BankStatServiceAsync;
import org.inria.bmajwatcher.client.services.BiomajLauncherServiceAsync;
import org.inria.bmajwatcher.client.services.MaintenanceServiceAsync;
import org.inria.bmajwatcher.client.services.UserManagerServiceAsync;
import org.inria.bmajwatcher.client.ui.bank_editor.BankEditorDialog;
import org.inria.bmajwatcher.client.ui.confirmation.MessagePanel;
import org.inria.bmajwatcher.client.ui.scheduler.Scheduler;
import org.inria.bmajwatcher.client.ui.styles.MainCss;
import org.inria.bmajwatcher.client.ui.styles.Resources;
import org.inria.bmajwatcher.client.ui.users.UserManagerDialog;


import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DecoratedTabPanel;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.smartgwt.client.data.Criteria;
import com.smartgwt.client.data.DSCallback;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.DateDisplayFormat;
import com.smartgwt.client.types.DragDataAction;
import com.smartgwt.client.types.ExpansionMode;
import com.smartgwt.client.types.ListGridFieldType;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.Window;
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.grid.events.RecordDoubleClickEvent;
import com.smartgwt.client.widgets.grid.events.RecordDoubleClickHandler;
import com.smartgwt.client.widgets.grid.events.SelectionChangedHandler;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.menu.Menu;
import com.smartgwt.client.widgets.menu.MenuItem;
import com.smartgwt.client.widgets.menu.MenuItemSeparator;
import com.smartgwt.client.widgets.menu.events.ClickHandler;
import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
import com.smartgwt.client.widgets.toolbar.ToolStripButton;
import com.smartgwt.client.widgets.toolbar.ToolStripMenuButton;


/**
 * Class that binds the components declared in the corresponding .ui.xml file
 * and handles their behavior.
 * This is the main page of the application.
 * 
 * @author rsabas
 *
 */
public class HomePage extends Composite implements com.google.gwt.event.dom.client.ClickHandler {
	
	interface HomePageUiBinder extends UiBinder<Widget, HomePage> {
	}
	
	private static HomePageUiBinder uiBinder = GWT.create(HomePageUiBinder.class);

	@UiField
	FlowPanel contentPanel;
	@UiField
	FlowPanel rightPanel;
	@UiField
	SpanElement title;
	
	private Scheduler sched; 
	private Record selectedRecord = null;
	private VerticalPanel globalGraphPanel;
	private VerticalPanel globalStatsMenu; 
	private Anchor allBanksAnchor = new Anchor("All banks");
	private Anchor freeSpaceAnchor = new Anchor("Free space");
	private Anchor distributionAnchor = new Anchor("Banks by server");
	private Anchor allTypesAnchor = new Anchor("Banks by type");
	private Anchor bankSizeByUser = new Anchor("Bank size by user");
	private Anchor bankCountByUser = new Anchor("Bank count by user");
	
	private PieChartGenerator cGen;
	private HTML total = new HTML();
	private HTML updating = new HTML();
	private HTML error = new HTML();
	
	private ToolStripButton detailIcon;
//	private ToolStripButton normalUpdate;
//	private ToolStripButton updateFromScratch;
	private ToolStripButton removeBank;
	private ToolStripButton editBank;
	private ToolStripButton showSched;
	
	private String loggedUser = null;
	private boolean isAdmin = false;
	
	private ToolStripButton maintenance;
	private boolean isMaintenance = false;
	
	private ListGrid grid;
	private MainCss css = Resources.INSTANCE.mainCss();
	
	private ToolStripMenuButton updateMenu = null;
	
	private UserManagerDialog diag;

	public HomePage() {
		initWidget(uiBinder.createAndBindUi(this));
		
		title.setInnerText("BioMAJ Watcher");
		
		contentPanel.setStylePrimaryName(css.center());
		rightPanel.setStylePrimaryName(css.right());
		
		init();
		
		/*
		tabPane.setCanDragResize(true);
		tabPane.setEdgeMarginSize(10);
		// Resizable only from bottom
		tabPane.setResizeFrom("B");*/
	}
	
	/**
	 * Inits the components.
	 * This method is called when the interface has to be redrawn after user login/logout.
	 */
	private void init() {

		AuthenticationServiceAsync.INSTANCE.getUserAccess(new AsyncCallback<String>() {			
			
			@Override
			public void onSuccess(String result) {
				if (result != null) { // Some user is logged
					String[] split = result.split(":");
					loggedUser = split[0];
					isAdmin = split[1].equals("admin");
					UserManagerServiceAsync.INSTANCE.getUserKey(loggedUser, new AsyncCallback<String>() {
						
						@Override
						public void onSuccess(String userKey) {
							drawContext(true, userKey);
						}
						
						@Override
						public void onFailure(Throwable caught) {
							SC.warn("RPC failure");
						}
					});
					
					
				} else {
					isAdmin = false;
					loggedUser = "";
					drawContext(false, null);
					
				}
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("User access : RPC failure");
			}
		});
	}
	
	/**
	 * Draws the components according to the user group (logged or guest).
	 * 
	 * @param logged
	 */
	private void drawContext(final boolean logged, final String userKey) {
		
		DecoratedTabPanel tabPanel = new DecoratedTabPanel();
		final VLayout bankLayout = new VLayout();
		bankLayout.setMembersMargin(5);
		final VLayout errorLayout = new VLayout();
		final ListGrid errorGrid = getErrorGrid(userKey);
		
		tabPanel.addSelectionHandler(new SelectionHandler<Integer>() {
			
			@Override
			public void onSelection(SelectionEvent<Integer> event) {
				if (event.getSelectedItem() == 1) {
					BankStatServiceAsync.INSTANCE.getBanksInfo(userKey, new AsyncCallback<List<Map<String,String>>>() {
						
						@Override
						public void onSuccess(List<Map<String, String>> result) {
							generateStatsMenu(result);
						}
						
						@Override
						public void onFailure(Throwable caught) {
							SC.warn("Failure");
						}
					});
				} else if (logged && event.getSelectedItem() == 2) {
					// Hide the layout that contains the bank list otherwise
					// conflicts with the layout that contains the error grid causing
					// bad handling of mouse clicks on the component.
					bankLayout.hide();
					errorLayout.show();
					errorGrid.invalidateCache();
					errorGrid.fetchData();
				} else if (logged && event.getSelectedItem() == 0) {
					errorLayout.hide();
					bankLayout.show();
				}
			}
		});
		
		
		/*
		 * STAT PANEL
		 */
		HorizontalPanel globalStatsPanel = new HorizontalPanel();
		globalStatsMenu = new VerticalPanel();
		globalStatsMenu.setStylePrimaryName(css.graphMenu());
		globalGraphPanel = new VerticalPanel();
		globalGraphPanel.setHeight("543px");
		globalStatsPanel.add(globalStatsMenu);
		globalStatsPanel.add(globalGraphPanel);
		
		/*
		 * BANK LIST
		 */
		grid = getBankGrid(logged, userKey);
		
		/*
		 * REFRESH BUTTON
		 */
//		Button refreshGrid = new Button("Refresh");
		PushButton refreshGrid = new PushButton(new Image("images/view-refresh-4.png"));
		refreshGrid.setTitle("Refresh");
		refreshGrid.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
			
			@Override
			public void onClick(com.google.gwt.event.dom.client.ClickEvent event) {
				grid.invalidateCache();
				grid.fetchData(new Criteria(), new DSCallback() {
					
					@Override
					public void execute(DSResponse response, Object rawData, DSRequest request) {
						updateStatusBar(logged);
					}
				});
			}
		});
		

		bankLayout.addMember(getToolBar(logged, userKey));
		bankLayout.addMember(grid);
		bankLayout.setWidth(684);
		bankLayout.setHeight(513);
		
		rightPanel.clear();
		/*
		 * LOGIN PANEL
		 */
		rightPanel.add(getLoginPanel(logged));

		VerticalPanel pnl = new VerticalPanel();
		pnl.add(bankLayout);
		HorizontalPanel hPnl = new HorizontalPanel();
		hPnl.add(refreshGrid);
		
		if (logged) {
			/*
			 * Show only user banks
			 */
			final CheckBox showGroupOnly = new CheckBox("Show group banks only");
			showGroupOnly.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
				
				@Override
				public void onClick(ClickEvent event) {
					if (showGroupOnly.getValue()) {
						grid.filterData(new Criteria(BankGridDataSource.GROUP, "true"));
					} else {
						grid.clearCriteria();
						grid.filterData();
					}
				}
			});
			hPnl.add(showGroupOnly);
			hPnl.setCellWidth(showGroupOnly, "100%");
			hPnl.setCellHorizontalAlignment(showGroupOnly, HasHorizontalAlignment.ALIGN_RIGHT);
		}
		
		pnl.add(hPnl);
		tabPanel.setStylePrimaryName(css.tabPane());
		tabPanel.add(pnl, BmajWatcherConstants.INSTANCE.banksStatus());
		tabPanel.add(globalStatsPanel, BmajWatcherConstants.INSTANCE.statistics());
		if (logged) {
			/*
			 * ERROR PANEL
			 */
			VerticalPanel errorsPanel = new VerticalPanel();
			errorLayout.addMember(errorGrid);
			errorLayout.setWidth(684);
			errorLayout.setHeight(543);
			errorsPanel.add(errorLayout);
			tabPanel.add(errorsPanel, BmajWatcherConstants.INSTANCE.errors());
		}
		
		tabPanel.selectTab(0);
		
		contentPanel.clear();
		contentPanel.add(tabPanel);
		contentPanel.add(getStatusBar(logged));
	}
	
	private ToolStrip getToolBar(final boolean logged, final String key) {
		ToolStrip ts = new ToolStrip();
		ts.setWidth100();
		
		ToolStripButton typeHierarchy = new ToolStripButton();
		typeHierarchy.setTooltip("Types hierarchy");
		typeHierarchy.setIcon("code-block.png");
		typeHierarchy.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
			
			@Override
			public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
				showTypesDialog();
			}
		});
		
		detailIcon = new ToolStripButton();
		removeBank = new ToolStripButton();
		editBank = new ToolStripButton();
		showSched = new ToolStripButton();
		
		
		
		detailIcon.setIcon("bank-detail.png");
		detailIcon.setTitle("Bank detail");
		detailIcon.setDisabled(selectedRecord == null);
		detailIcon.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
			
			@Override
			public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
				showBankDetail(selectedRecord, logged && Boolean.valueOf(selectedRecord.getAttributeAsString(BankGridDataSource.GROUP)), key);
			}
		});
		
		if (logged) {
			Menu updateItems = new Menu();
			MenuItem itemNormalUpdate = new MenuItem("biomaj.sh --update", "normal-update.png");;
			MenuItem itemUpdateFromScratch = new MenuItem("biomaj.sh --update --fromscratch", "update-from-scratch.png");
			MenuItem itemNewUpdate = new MenuItem("biomaj.sh --update --new", "update-new.png");
			MenuItem itemRebuild = new MenuItem("biomaj.sh --rebuild", "rebuild-bank.png");
			
			
			itemNormalUpdate.addClickHandler(new ClickHandler() {
				
				@Override
				public void onClick(MenuItemClickEvent event) {
					if (selectedRecord != null) {
						updateBank(selectedRecord.getAttribute(BankGridDataSource.NAME));
					}
				}
			});				
			
			itemUpdateFromScratch.addClickHandler(new ClickHandler() {
				
				@Override
				public void onClick(MenuItemClickEvent event) {
					if (selectedRecord != null) {
						updateBankFromScratch(selectedRecord.getAttribute(BankGridDataSource.NAME));
					}
				}
			});
			
			itemNewUpdate.addClickHandler(new ClickHandler() {
				
				@Override
				public void onClick(MenuItemClickEvent event) {
					if (selectedRecord != null) {
						updateBankNew(selectedRecord.getAttribute(BankGridDataSource.NAME));
					}
				}
			});
			
			itemRebuild.addClickHandler(new ClickHandler() {
				
				@Override
				public void onClick(MenuItemClickEvent event) {
					if (selectedRecord != null) {
						rebuildBank(selectedRecord.getAttribute(BankGridDataSource.NAME));
					}
				}
			});
			
			updateItems.setItems(itemNormalUpdate, itemUpdateFromScratch, itemNewUpdate, itemRebuild);
			
//			String imgHtml = Canvas.imgHTML("system-switch-user.png", 16, 16);
			String imgHtml = "";
			updateMenu = new ToolStripMenuButton(imgHtml + " <span class=\"" + css.toolBarMenuSmall() + "\">Update ???</span>", updateItems);
			updateMenu.setIconSize(16);
			updateMenu.addStyleName(css.toolBarMenuSmall());
			updateMenu.setDisabled(true);
			ts.addMenuButton(updateMenu);
			ts.addSeparator();
			
			removeBank.setIcon("edit-delete.png");
			removeBank.setTooltip("Remove bank");
			removeBank.setDisabled(selectedRecord == null);
			removeBank.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
				
				@Override
				public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
					if (selectedRecord != null)
						showRemoveDialog(selectedRecord.getAttribute(BankGridDataSource.NAME));
				}
			});
			ts.addButton(detailIcon);
			ts.addButton(removeBank);
			
			
			editBank.setIcon("document-properties.png");
			editBank.setTooltip("Edit bank properties");
			editBank.setDisabled(selectedRecord == null);
			editBank.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
				
				@Override
				public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
					if (selectedRecord != null)
						BankEditorDialog.getInstance(loggedUser).show(selectedRecord.getAttribute(BankGridDataSource.NAME));
				}
			});
			ts.addButton(editBank);
			
			showSched.setIcon("clock-go.png");
			showSched.setTitle("Show task");
			showSched.setDisabled(selectedRecord == null);
			showSched.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
				
				@Override
				public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
					if (selectedRecord != null)
						sched.showBankSection(selectedRecord.getAttribute(BankGridDataSource.NAME));
					
				}
			});
			ts.addButton(showSched);
			
			ts.addSeparator();
			
			ToolStripButton bankEditor = new ToolStripButton();
			bankEditor.setIcon("page-edit.png");
			bankEditor.setTitle("New bank");
			bankEditor.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
				
				@Override
				public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
					BankEditorDialog.getInstance(loggedUser).show();
				}
			});
			ts.addButton(bankEditor);
			ts.addSeparator();		
			
			ts.addButton(typeHierarchy);
			
			
			maintenance = new ToolStripButton();
			maintenance.setIcon("maintenance-off.png");
			maintenance.setTitle("Maintenance mode");
			if(!isAdmin) {
				maintenance.disable();
			}
			MaintenanceServiceAsync.INSTANCE.getMaintenanceMode(new AsyncCallback<Boolean>() {			
				
				@Override
				public void onSuccess(Boolean mode) {
					isMaintenance = mode;
					if(isMaintenance) {
						maintenance.setIcon("maintenance-on.png");
					}
					else {
						maintenance.setIcon("maintenance-off.png");
					}
				}
				
				@Override
				public void onFailure(Throwable caught) {
					SC.warn("Maintenance access : RPC failure");
				}
			});
			
			maintenance.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
				
				@Override
				public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
					//TODO call server to update status
					if(isMaintenance) {
						setMaintenanceMode(false);
					}
					else {
						setMaintenanceMode(true);
					}
						
				}
			});
			ts.addButton(maintenance);
			
			
		} else {
			ts.addButton(detailIcon);
			ts.addSeparator();
			ts.addButton(typeHierarchy);
		}
		ts.addFill();
		
		return ts;
	}
	
	
	private void setMaintenanceMode(boolean mode) {
		isMaintenance = mode;
		if(isMaintenance) {
			maintenance.setIcon("maintenance-on.png");
		}
		else {
			maintenance.setIcon("maintenance-off.png");
		}
		MaintenanceServiceAsync.INSTANCE.setMaintenanceMode(mode,new AsyncCallback<Void>() {			
			
			@Override
			public void onSuccess(Void result) {
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("Maintenance access : RPC failure");
			}
		});
	}
	
	private void generateStatsMenu(List<Map<String, String>> data) {
		
		VerticalPanel topMenu = new VerticalPanel();
		topMenu.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		globalStatsMenu.clear();
		globalStatsMenu.add(topMenu);
		
		topMenu.add(allBanksAnchor);
		allBanksAnchor.addClickHandler(this);
		topMenu.add(freeSpaceAnchor);
		freeSpaceAnchor.addClickHandler(this);
		topMenu.add(allTypesAnchor);
		allTypesAnchor.addClickHandler(this);
		topMenu.add(distributionAnchor);
		distributionAnchor.addClickHandler(this);
		if (isAdmin) {
			topMenu.add(bankSizeByUser);
			bankSizeByUser.addClickHandler(this);
			topMenu.add(bankCountByUser);
			bankCountByUser.addClickHandler(this);
		}
		
		topMenu.add(new HTML("<b>Types</b>"));
		
		Set<String> types = new TreeSet<String>();
		
		for (Map<String, String> map : data) {
			if (types.add(map.get("type"))) {
				Anchor type = new Anchor(map.get("type"));
				type.addClickHandler(this);
				topMenu.add(type);
			}
		}
		
		cGen = new PieChartGenerator(data);
		globalGraphPanel.clear();
		globalGraphPanel.add(cGen.getAllBanks());
	}
	
	private ListGrid getErrorGrid(String userKey) {
		ListGrid errors = new ListGrid() {
			@Override
			protected Canvas getExpansionComponent(ListGridRecord record) {
				Canvas canvas = super.getExpansionComponent(record);
				canvas.setMargin(5);
				return canvas;
			}
			
			@Override
			protected String getCellCSSText(ListGridRecord record, int rowNum, int colNum) {
				if (getFieldName(colNum).equals(ErrorGridDataSource.TYPE)) {
					if (record.getAttributeAsString(ErrorGridDataSource.TYPE).equalsIgnoreCase("error")) {
						return "font-weight:bold; color:RED;";
					} else
						return super.getCellCSSText(record, rowNum, colNum);
				} else
					return super.getCellCSSText(record, rowNum, colNum);
			}
		};
		errors.setCanExpandRecords(true);
		errors.setExpansionMode(ExpansionMode.DETAIL_FIELD);
		errors.setDetailField(ErrorGridDataSource.MESSAGE);
		
		ListGridField typeField = new ListGridField(ErrorGridDataSource.TYPE, BmajWatcherConstants.INSTANCE.type());
		typeField.setWidth(70);
		ListGridField bankField = new ListGridField(ErrorGridDataSource.BANK, BmajWatcherConstants.INSTANCE.bank());
		bankField.setWidth(140);
		ListGridField sourceField = new ListGridField(ErrorGridDataSource.SOURCE, BmajWatcherConstants.INSTANCE.source());
		sourceField.setWidth(90);
		ListGridField logField = new ListGridField(ErrorGridDataSource.LOG, BmajWatcherConstants.INSTANCE.log());
//		logField.setWidth(150);
		logField.setType(ListGridFieldType.LINK);
		ListGridField dateField = new ListGridField(ErrorGridDataSource.DATE, BmajWatcherConstants.INSTANCE.date());
		dateField.setWidth(140);
		
		errors.setFields(typeField, bankField, logField, sourceField, dateField);
		

		errors.setDataSource(ErrorGridDataSource.getInstance(userKey));
		errors.setAutoFetchData(false);
		
		return errors;
	}
	
	/**
	 * Generates the grid that contains the bank list.
	 * 
	 * @param logged whether some elements should be displayed or not
	 * @return
	 */
	private ListGrid getBankGrid(final boolean logged, final String key) {
		
		final ListGrid banks = new ListGrid() {
			@Override
			protected String getCellCSSText(ListGridRecord record, int rowNum, int colNum) {
				String style = "";
				
				// Change row color for user banks
				if (Boolean.valueOf(record.getAttributeAsString(BankGridDataSource.OWNER)))
//					style = "background-color:#E9E6FE;";
					style = "background-color:#EDEDFE;";
				else if (Boolean.valueOf(record.getAttributeAsString(BankGridDataSource.GROUP)))
//					style = "background-color:#EDEDFE;";
					style = "background-color:#EBDBFE;";
				else if (!isAdmin) // Can't drag records if not owner
					record.setCanDrag(false);
				
				if (getFieldName(colNum).equals(BankGridDataSource.STATUS)) {
					
					if (record.getAttributeAsString(BankGridDataSource.STATUS).equalsIgnoreCase("OK")) {
						style += "font-weight:bold; color:GREEN;";
					} else if (record.getAttributeAsString(BankGridDataSource.STATUS).equalsIgnoreCase("KO")) {
						style += "font-weight:bold; color:RED;";
					} else if (record.getAttributeAsString(BankGridDataSource.STATUS).equalsIgnoreCase("updating")) {
						style += "font-weight:bold; color:BLACK;";
					} else
						style += super.getCellCSSText(record, rowNum, colNum);
				} else
					style += super.getCellCSSText(record, rowNum, colNum);
				
				return style;
			}
		};
		
		banks.setBaseStyle("bankGridCell");
		
		banks.setShowFilterEditor(true);
		banks.setShowAllRecords(false);
		banks.setWidth100();
		banks.setHeight100();
		banks.setDateFormatter(DateDisplayFormat.TOSERIALIZEABLEDATE);
		
//		banks.invalidateCache();
//		banks.fetchData();
		
		banks.addSelectionChangedHandler(new SelectionChangedHandler() {
			
			@Override
			public void onSelectionChanged(
					com.smartgwt.client.widgets.grid.events.SelectionEvent event) {
				
				selectedRecord = event.getRecord();
				detailIcon.setDisabled(false);
				
				if (logged && (isAdmin || Boolean.valueOf(selectedRecord.getAttributeAsString(BankGridDataSource.GROUP)))) {
					showSched.setDisabled(false);
					editBank.setDisabled(false);
					
					boolean isUpdating = selectedRecord.getAttribute(BankGridDataSource.STATUS).equalsIgnoreCase("updating");
					if (updateMenu != null) {
						String imgHtml = "";
						updateMenu.setTitle(imgHtml + " <span class=\"" + css.toolBarMenuSmall() + "\">Update " + selectedRecord.getAttribute(BankGridDataSource.NAME) + "</span>");
						updateMenu.setDisabled(isUpdating);
					}
					removeBank.setDisabled(isUpdating);
				} else {
					showSched.setDisabled(true);
					editBank.setDisabled(true);
					if (updateMenu != null)
						updateMenu.setDisabled(true);
					removeBank.setDisabled(true);
				}
			}
		});
		
		banks.addRecordDoubleClickHandler(new RecordDoubleClickHandler() {
			
			@Override
			public void onRecordDoubleClick(RecordDoubleClickEvent event) {
				Record record = event.getRecord();
				showBankDetail(record, logged && (isAdmin || Boolean.valueOf(record.getAttributeAsString(BankGridDataSource.GROUP))), key);
			}
		});
		
		
		ListGridField schedField = new ListGridField(BankGridDataSource.IS_SCHED, "Sched", 60);
		schedField.setAlign(Alignment.CENTER);
		schedField.setType(ListGridFieldType.IMAGE);
		schedField.setCanSort(false);
		
		ListGridField visibilityField = new ListGridField(BankGridDataSource.VISIBILITY, "Access", 60);
		visibilityField.setAlign(Alignment.CENTER);
		visibilityField.setType(ListGridFieldType.IMAGE);
		visibilityField.setImageURLSuffix(".png");
		visibilityField.setCanSort(false);
		
		ListGridField typeField = new ListGridField(BankGridDataSource.TYPE, BmajWatcherConstants.INSTANCE.type());
		ListGridField formatsField = new ListGridField(BankGridDataSource.FORMATS, BmajWatcherConstants.INSTANCE.formats());
		ListGridField nameField = new ListGridField(BankGridDataSource.NAME, BmajWatcherConstants.INSTANCE.name());
		ListGridField releaseField = new ListGridField(BankGridDataSource.RELEASE, BmajWatcherConstants.INSTANCE.release(), 80);
		ListGridField sessionField = new ListGridField(BankGridDataSource.SESSION, BmajWatcherConstants.INSTANCE.session(), 150);
		
		ListGridField statusField = new ListGridField(BankGridDataSource.STATUS, BmajWatcherConstants.INSTANCE.status(), 60);
		
		if (logged) {
			banks.setCanDragRecordsOut(true);
			banks.setDragDataAction(DragDataAction.COPY);
			
			banks.setFields(schedField, typeField, formatsField, nameField, releaseField, sessionField, statusField, visibilityField);
			
			banks.addCellContextClickHandler(new CellContextClickHandler() {
				
				@Override
				public void onCellContextClick(CellContextClickEvent event) {
					event.cancel();
					Record record = event.getRecord();
					// Popup for group only
					if (logged && (isAdmin || Boolean.valueOf(record.getAttributeAsString(BankGridDataSource.GROUP))))
						showPopupMenu(record, banks);
				}
			});
		}
		else
			banks.setFields(typeField, formatsField, nameField, releaseField, sessionField);
		
		banks.setAutoFetchData(false);
		banks.setDataSource(BankGridDataSource.getInstance(key));
		
		banks.fetchData(new Criteria(), new DSCallback() {
			
			@Override
			public void execute(DSResponse response, Object rawData, DSRequest request) {
				updateStatusBar(logged);
				if (logged)
					rightPanel.add(getScheduler(grid, key));
			}
		});

		return banks;
	}
	
	/**
	 * Generates login form.
	 * 
	 * @param logged if true displays logout form, if false display login form
	 * @return
	 */
	private Composite getLoginPanel(final boolean logged) {
		HorizontalPanel okPanel = new HorizontalPanel();
				
		Label login = new Label(BmajWatcherConstants.INSTANCE.userName());
		login.setStylePrimaryName(css.formLabel());
		Label passwd = new Label(BmajWatcherConstants.INSTANCE.passwd());
		passwd.setStylePrimaryName(css.formLabel());
		final TextBox loginTxt = new TextBox();
		loginTxt.setStylePrimaryName(css.formText());
		final PasswordTextBox passwdTxt = new PasswordTextBox();
		passwdTxt.setStylePrimaryName(css.formText());
		
		Button submitButton;
		
		VerticalPanel container = new VerticalPanel();
		HorizontalPanel namePanel = new HorizontalPanel();
		container.add(namePanel);
		
		if (!logged) {
			HorizontalPanel passwdPanel = new HorizontalPanel();
			
			namePanel.add(login);
			namePanel.add(loginTxt);
			
			passwdPanel.add(passwd);
			passwdPanel.add(passwdTxt);
			
			container.add(passwdPanel);
			
			submitButton = new Button(BmajWatcherConstants.INSTANCE.submit());
		} else {
			namePanel.add(new HTML("<b>Welcome</b>&nbsp;"));
			Anchor ancLogin = new Anchor(loggedUser);
			ancLogin.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
				
				@Override
				public void onClick(ClickEvent event) {
					diag = new UserManagerDialog(loggedUser);
					diag.addStyleName(css.bankEditor());
					diag.setPopupPosition(100, 100);
					diag.show();
				}
			});
			namePanel.add(ancLogin);
			
			submitButton = new Button(BmajWatcherConstants.INSTANCE.logout());
		}
		
		
		/*
		 * CATCH ENTER
		 */
		loginTxt.addKeyPressHandler(new KeyPressHandler() {
			@Override
			public void onKeyPress(KeyPressEvent event) {
				if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER)
					requestAuthentication(loginTxt.getValue(), passwdTxt.getValue());
			}
		});
		passwdTxt.addKeyPressHandler(new KeyPressHandler() {
			
			@Override
			public void onKeyPress(KeyPressEvent event) {
				if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER)
					requestAuthentication(loginTxt.getValue(), passwdTxt.getValue());
			}
		});
		
		
		submitButton.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
			
			@Override
			public void onClick(com.google.gwt.event.dom.client.ClickEvent event) {
				if (!logged)
					requestAuthentication(loginTxt.getValue(), passwdTxt.getValue());
				else
					requestLogout();
			}
		});

		submitButton.addStyleName(css.formBtn());
		container.add(okPanel);
		okPanel.add(submitButton);
		
		DecoratedTabPanel pnl = new DecoratedTabPanel();
		pnl.add(container, BmajWatcherConstants.INSTANCE.login());
		pnl.setStylePrimaryName(css.loginPane());
		pnl.selectTab(0);
		
		return pnl;
	}
	
	/**
	 * Generates status bar that contains global stats about online banks. 
	 * 
	 * @param logged
	 * @param listGridRecords 
	 * @return
	 */
	private Panel getStatusBar(final boolean logged) {
		
		VerticalPanel statusBar = new VerticalPanel();
		statusBar.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		statusBar.setStylePrimaryName(css.toolStrip());
		final HorizontalPanel hp = new HorizontalPanel();
		hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		if (logged)
			hp.setWidth("300px");
		else
			hp.setWidth("200px");
		statusBar.add(hp);
		
		total.setHTML("Total : ?");
		hp.add(total);
		if (logged) {
			updating.setHTML("Updating : ?");
			hp.add(updating);
			error.setHTML("Error : ?");
			hp.add(error);
		}
		
		return statusBar;
		
	}
	
	
	private void updateStatusBar(final boolean logged) {
		
		BankStatServiceAsync.INSTANCE.banksStatus(new AsyncCallback<Map<String,Integer>>() {
			
			@Override
			public void onSuccess(Map<String, Integer> result) {
				total.setHTML("Total : " + result.get("total"));
				updating.setHTML("Updating : " + result.get("updating"));
				error.setHTML("Error : " + result.get("error"));
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("Status bar update failure");
			}
		});
		
	}
	
	/**
	 * Window that displays detailed info about a bank.
	 * 
	 * @param bank
	 * @param logged
	 */
	private void showBankDetail(final Record bank, final boolean logged, String userKey) {
		BankDetailDialog dialog = new BankDetailDialog(bank, logged, userKey);
		dialog.show();
	}
	
	/**
	 * Context menu that displays available actions for a bank.
	 * 
	 * @param bank
	 */
	private void showPopupMenu(final Record bank, final ListGrid grid) {
		
		Menu menu = new Menu();
		final String bankName = bank.getAttribute(BankGridDataSource.NAME);
		
		/*
		 * Change bank owner
		 */
		MenuItem itemChangeOwner = new MenuItem("Change bank owner", "group-go.png");
		itemChangeOwner.setSubmenu(getUserSubMenu(bankName));
		
		/*
		 * Edit bank properties
		 */
		MenuItem itemEdit = new MenuItem("Edit bank properties", "document-properties.png");
		itemEdit.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(MenuItemClickEvent event) {
				BankEditorDialog.getInstance(loggedUser).show(bank.getAttribute(BankGridDataSource.NAME));
			}
		});
		
		/*
		 * Show scheduled bank in tasks
		 */
		MenuItem itemShowTask = new MenuItem("Show task", "clock-go.png");
		itemShowTask.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(MenuItemClickEvent event) {
				sched.showBankSection(bankName);
			}
		});
		
		/*
		 * Start update
		 */
		MenuItem itemLaunch = new MenuItem(BmajWatcherConstants.INSTANCE.updateStart(), "normal-update.png");
		itemLaunch.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(MenuItemClickEvent event) {
				updateBank(bankName);
			}
		});
		
		/*
		 * Stop update // Not used, does not work !
		 */
		MenuItem itemStop = new MenuItem(BmajWatcherConstants.INSTANCE.updateStop());
		itemStop.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(MenuItemClickEvent event) {
				BiomajLauncherServiceAsync.INSTANCE.stopUpdate(bankName, new AsyncCallback<Boolean>() {
					
					@Override
					public void onSuccess(Boolean result) {
						if (!result)
							SC.say("Failure");
					}
					
					@Override
					public void onFailure(Throwable caught) {
						SC.warn(BmajWatcherConstants.INSTANCE.rpcFailure());
					}
				});
			}
		});
		
		/*
		 * Start update from scratch
		 */
		MenuItem itemFromScratch = new MenuItem(BmajWatcherConstants.INSTANCE.updateFromScratch(), "update-from-scratch.png");
		itemFromScratch.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(MenuItemClickEvent event) {
				updateBankFromScratch(bankName);
			}
		});
		
		/*
		 * Start update --new
		 */
		MenuItem itemNew = new MenuItem("New update (--new)", "update-new.png");
		itemNew.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(MenuItemClickEvent event) {
				updateBankNew(bankName);
			}
		});
		
		/*
		 * Rebuild bank
		 */
		MenuItem itemRebuild = new MenuItem("Rebuild bank (--rebuild)", "rebuild-bank.png");
		itemRebuild.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(MenuItemClickEvent event) {
				rebuildBank(bankName);
			}
		});
		
		/*
		 * Remove bank
		 */
		MenuItem itemRemove = new MenuItem(BmajWatcherConstants.INSTANCE.remove(), "edit-delete.png");
		itemRemove.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(MenuItemClickEvent event) {	
				showRemoveDialog(bank.getAttributeAsString(BankGridDataSource.NAME));
			}
		});
		
		/*
		 * Change bank visibility
		 */
		MenuItem itemVisibility = new MenuItem("Change visibility", "lock-edit.png");
		itemVisibility.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(MenuItemClickEvent event) {
				final boolean vis = bank.getAttribute(BankGridDataSource.VISIBILITY).equals("public");
				UserManagerServiceAsync.INSTANCE.changeBankVisibility(bank.getAttribute(BankGridDataSource.NAME),
						!vis, new AsyncCallback<Boolean>() {
							
							@Override
							public void onSuccess(Boolean result) {
								if (!result) {
									SC.warn("Bank visibility could not be changed");
								} else {
									MessagePanel.showMessage("Access to bank set to " + (vis ? "private" : "public"));
								}
							}
							
							@Override
							public void onFailure(Throwable caught) {
								SC.warn("RPC failure");
							}
						});
			}
		});
		
		if (!bank.getAttribute(BankGridDataSource.STATUS).equalsIgnoreCase("updating")) {
			itemFromScratch.setEnabled(true);
			itemLaunch.setEnabled(true);
			itemRemove.setEnabled(true);
			itemNew.setEnabled(true);
			itemRebuild.setEnabled(true);
			itemStop.setEnabled(false);
		}
		else {
			itemFromScratch.setEnabled(false);
			itemLaunch.setEnabled(false);
			itemRemove.setEnabled(false);
			itemNew.setEnabled(false);
			itemRebuild.setEnabled(false);
			itemStop.setEnabled(false);
		}
		
		if (isAdmin)
			menu.setItems(itemVisibility, itemChangeOwner, new MenuItemSeparator(), itemEdit, new MenuItemSeparator(), itemShowTask, new MenuItemSeparator(), itemLaunch, itemFromScratch, itemNew, itemRebuild, new MenuItemSeparator(), itemRemove);
		else
			menu.setItems(itemVisibility, new MenuItemSeparator(), itemEdit, new MenuItemSeparator(), itemShowTask, new MenuItemSeparator(), itemLaunch, itemFromScratch, itemNew, itemRebuild, new MenuItemSeparator(), itemRemove);
		
		menu.showContextMenu();
	}
	
	private Menu getUserSubMenu(final String bankName) {
		final Menu userList = new Menu();
		UserManagerServiceAsync.INSTANCE.getLogins(new AsyncCallback<List<String>>() {
			
			@Override
			public void onSuccess(List<String> result) {
				for (final String login : result) {
					MenuItem user = new MenuItem(login);
					user.addClickHandler(new ClickHandler() {
						
						@Override
						public void onClick(MenuItemClickEvent event) {
							UserManagerServiceAsync.INSTANCE.changeBankOwner(bankName, login, new AsyncCallback<Boolean>() {
								
								@Override
								public void onSuccess(Boolean result) {
									if (!result) {
										SC.warn("Could not change bank owner");
									} else {
										MessagePanel.showMessage("Owner changed");
									}
								}
								
								@Override
								public void onFailure(Throwable caught) {
									SC.warn("RPC failure");
								}
							});
						}
					});
					userList.addItem(user);
				}
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("Could not retrieve user logins");
			}
		});
		
		return userList;
	}
	
	/**
	 * Displays dialog that allows user to remove a bank.
	 * 
	 * @param bankName
	 */
	private void showRemoveDialog(final String bankName) {
		final Window winModal = new Window();
		winModal.setWidth(450);
		winModal.setHeight(300);
		winModal.setTitle("Delete from " + bankName);
		winModal.setShowMinimizeButton(false);
		winModal.setIsModal(true);
//		winModal.setMembersMargin(10);
		winModal.setShowModalMask(true);
		winModal.centerInPage();
		
		Canvas canvas = new Canvas();
		final CheckBox keepProd = new CheckBox("Keep production directories");
		final List<CheckBox> cbs = new ArrayList<CheckBox>();
		final VerticalPanel pnl = new VerticalPanel();
		pnl.setStylePrimaryName(css.deletePanel());
		pnl.setSize("100%", "100%");
		final RadioButton rbSelect = new RadioButton("directories", "Directories");
		rbSelect.setValue(true);
		rbSelect.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				for (CheckBox cb : cbs)
					cb.setVisible(true);
			}
		});
		
		final RadioButton rbAll = new RadioButton("directories", "All");
		rbAll.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				for (CheckBox cb: cbs)
					cb.setVisible(false);
			}
		});
		
		final RadioButton rbAllNoHistory = new RadioButton("directories", "All with no history");
		rbAllNoHistory.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				for (CheckBox cb: cbs)
					cb.setVisible(false);
			}
		});
		
		pnl.add(rbSelect);
		canvas.addChild(pnl);
		final Button btnDelete = new Button("Delete", new com.google.gwt.event.dom.client.ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				if (rbSelect.getValue()) { // Remove directories
					List<String> paths = new ArrayList<String>();
					for (CheckBox cb : cbs) {
						if (cb.getValue())
							paths.add(cb.getText());
					}
					if (paths.size() > 0) {
						BankRemovalServiceAsync.INSTANCE.deleteDirectories(paths, bankName, keepProd.getValue(), new AsyncCallback<Void>() {
							
							@Override
							public void onSuccess(Void result) {
								MessagePanel.showMessage("Remove started");
							}
							
							@Override
							public void onFailure(Throwable caught) {
								SC.warn("Failure");
							}
						});
					}
				} else if (rbAll.getValue()) { // Remove all
					BankRemovalServiceAsync.INSTANCE.deleteBank(bankName, false, keepProd.getValue(), new AsyncCallback<Void>() {
						
						@Override
						public void onSuccess(Void result) {
							MessagePanel.showMessage("Remove started");
						}
						
						@Override
						public void onFailure(Throwable caught) {
							SC.warn("Failure");
						}
					});
				} else { // Remove all no history
					BankRemovalServiceAsync.INSTANCE.deleteBank(bankName, true, keepProd.getValue(), new AsyncCallback<Void>() {
						
						@Override
						public void onSuccess(Void result) {
							MessagePanel.showMessage("Remove started");
						}
						
						@Override
						public void onFailure(Throwable caught) {
							SC.warn("Failure");
						}
					});
				}
				winModal.hide();
			}
		});
		
		final Button btnCancel = new Button("Cancel", new com.google.gwt.event.dom.client.ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				winModal.hide();
			}
		});
		
		
		BankRemovalServiceAsync.INSTANCE.getDirectories(bankName, new AsyncCallback<List<String>>() {
			
			@Override
			public void onSuccess(List<String> result) {
				for (String path : result) {
					CheckBox cb = new CheckBox(path);
					cb.setStylePrimaryName(css.checkBox());
					cbs.add(cb);
					pnl.add(cb);
				}
				pnl.add(rbAll);
				pnl.add(rbAllNoHistory);
				pnl.add(keepProd);
				HorizontalPanel btnPanel = new HorizontalPanel();
				btnPanel.setSpacing(3);
				btnPanel.add(btnDelete);
				btnPanel.add(btnCancel);
//				pnl.add(btnDelete);
				pnl.add(btnPanel);
				pnl.setCellHorizontalAlignment(btnPanel, HasHorizontalAlignment.ALIGN_CENTER);
				winModal.setHeight(175 + result.size() * 40);
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("Failure");
			}
		});
		winModal.addItem(canvas);
		
		winModal.show();
	}

	/**
	 * Asynchronous server call for user logging out.
	 */
	private void requestLogout() {
		AuthenticationServiceAsync.INSTANCE.logout(new AsyncCallback<Void>() {
			
			@Override
			public void onSuccess(Void result) {
				init();
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("Logging out failure");
			}
		});
	}
	
	/**
	 * Asynchronous server call for user authentication.
	 * 
	 * @param login username to be checked
	 * @param passwd passwd to be checked
	 */
	private void requestAuthentication(final String login, String passwd) {
		AuthenticationServiceAsync.INSTANCE.authenticate(login, passwd, new AsyncCallback<Boolean>() {
			
			@Override
			public void onSuccess(Boolean result) {
				if (result) {
					init();
				}
				else
					SC.say(BmajWatcherConstants.INSTANCE.accessDenied());
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("Logging in failure");
			}
		});
	}
	
	/**
	 * Returns component for scheduled task handling for the given user.
	 * 
	 * @return
	 */
	private Composite getScheduler(ListGrid grid, String userKey) {
		
		sched = new Scheduler(grid, userKey);
		DecoratedTabPanel tb = new DecoratedTabPanel();
		tb.setStylePrimaryName(css.scheduler());
		VerticalPanel pnl = new VerticalPanel();
		pnl.add(sched.getButtonPanel());
		pnl.add(sched.getContainer());
		tb.add(pnl, "Scheduler");
		tb.selectTab(0);
		
		return tb;
	}
	
	private void showTypesDialog() {
		BankDetailServiceAsync.INSTANCE.getTypes(loggedUser, new AsyncCallback<List<String>>() {
			
			@Override
			public void onSuccess(List<String> result) {
				// Result is sorted
				final DialogBox typeDialog = new DialogBox(false, false);
				typeDialog.addStyleName(css.typeHierarchyDialog());
				VerticalPanel typePanel = new VerticalPanel();
				typePanel.addStyleName(css.typePanel());
				
				Set<String> addedTypes = new HashSet<String>();
				
				List<TreeItem> items = new ArrayList<TreeItem>();
				TreeItem root = new TreeItem("Types");
				root.setTitle("Root node");
				
				for (final String type : result) {
					int start = 0;
					int index = 0;
					
					// Build the arboresence according to the /
					while ((index = type.indexOf("/", start)) > 0) {

						String substr = type.substring(start, index);
						if (addedTypes.add(substr)) { // No duplicates types
							
							TreeItem item = new TreeItem(substr);
							item.setTitle(type.substring(0, index));
							items.add(item);
						}
						start = index + 1;
					}
					
					if (addedTypes.add(type.substring(start))) { // Add t3 where t3 in t1/t2/t3 or t3 alone
						
						TreeItem item = new TreeItem(type.substring(start));
						item.setTitle(type);
						items.add(item);
						
					}
				}
				
				Button btnClose = new Button("Close");
				btnClose.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
					
					@Override
					public void onClick(ClickEvent event) {
						typeDialog.hide();
					}
				});
				
				// Link the nodes
				for (TreeItem item : items) {
					if (!item.getTitle().contains("/"))
						root.addItem(item);
					for (TreeItem item2 : items) {
						if (!item.getTitle().equals(item2.getTitle()) && item2.getTitle().startsWith(item.getTitle()))
							item.addItem(item2);
					}
				}
				
				final Tree tree = new Tree();
				tree.addItem(root);
				root.setState(true);
				tree.addBlurHandler(new BlurHandler() {
					
					@Override
					public void onBlur(BlurEvent event) {
						String fullType = tree.getSelectedItem().getTitle();
						if (!fullType.equals("Root node"))
							grid.filterData(new Criteria(BankGridDataSource.TYPE, fullType));
					}
				});
				
				
				VerticalPanel main = new VerticalPanel();
				main.add(new Label("Click on a type to filter the banks :"));
				typePanel.add(tree);
				main.add(typePanel);
				
				// Clear filtering
				Anchor clear = new Anchor("Clear");
				clear.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
					
					@Override
					public void onClick(ClickEvent event) {
						grid.clearCriteria();
						grid.filterData();
					}
				});
				HorizontalPanel hpBtm = new HorizontalPanel();
				hpBtm.setWidth("100%");
				hpBtm.add(clear);
				hpBtm.add(btnClose);
				hpBtm.setCellHorizontalAlignment(clear, HasHorizontalAlignment.ALIGN_LEFT);
				hpBtm.setCellHorizontalAlignment(btnClose, HasHorizontalAlignment.ALIGN_RIGHT);
				
				main.add(hpBtm);
				typeDialog.add(main);
				typeDialog.setHTML("<b>Types hierachy</b>");
				typeDialog.center();
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("Failed to retrieve bank types");
			}
		});
	}

	@Override
	public void onClick(com.google.gwt.event.dom.client.ClickEvent event) {
		globalGraphPanel.clear();
		
		if (event.getSource() == allBanksAnchor) {
			globalGraphPanel.add(cGen.getAllBanks());
		} else if (event.getSource() == allTypesAnchor) {
			globalGraphPanel.add(cGen.getAllTypes());
		} else if (event.getSource() == distributionAnchor) {
			globalGraphPanel.add(cGen.getDistribution());
		} else if (event.getSource() == freeSpaceAnchor){
			globalGraphPanel.add(cGen.getFreeSpace());
		} else if (event.getSource() == bankCountByUser) {
			globalGraphPanel.add(cGen.getBankCountByUser());
		} else if (event.getSource() == bankSizeByUser) {
			globalGraphPanel.add(cGen.getSizeByUser());
		} else {
			Anchor anc = (Anchor) event.getSource();
			String type = anc.getText();
			globalGraphPanel.add(cGen.getType(type));
		}
	}

	private void updateBank(String bankName) {
		if(isMaintenance && !isAdmin) {
			MessagePanel.showMessage("Server in maintenance, no update allowed");
			return;
		}
		BiomajLauncherServiceAsync.INSTANCE.startUpdate(bankName, new AsyncCallback<Boolean>() {
			
			@Override
			public void onSuccess(Boolean result) {
				if (!result) {
					SC.warn("Update failure");
				} else {
					MessagePanel.showMessage("Update started");
				}
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("Failure");
			}
		});
	}
	
	private void rebuildBank(String bankName) {
		if(isMaintenance && !isAdmin) {
			MessagePanel.showMessage("Server in maintenance, no update allowed");
			return;
		}
		BiomajLauncherServiceAsync.INSTANCE.rebuild(bankName, new AsyncCallback<Boolean>() {
			
			@Override
			public void onSuccess(Boolean result) {
				if (!result) {
					SC.warn("Update failure");
				} else {
					MessagePanel.showMessage("Rebuild started");
				}
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("Failure");
			}
		});
	}
	
	private void updateBankNew(String bankName) {
		if(isMaintenance && !isAdmin) {
			MessagePanel.showMessage("Server in maintenance, no update allowed");
			return;
		}
		BiomajLauncherServiceAsync.INSTANCE.startUpdateNew(bankName, new AsyncCallback<Boolean>() {
					
			@Override
			public void onSuccess(Boolean result) {
				if (!result) {
					SC.warn("Update failure");
				} else {
					MessagePanel.showMessage("Update started");
				}
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("Failure");
			}
		});
	}
	
	private void updateBankFromScratch(String bankName) {
		if(isMaintenance && !isAdmin) {
			MessagePanel.showMessage("Server in maintenance, no update allowed");
			return;
		}
		BiomajLauncherServiceAsync.INSTANCE.startUpdateFromScratch(bankName, new AsyncCallback<Boolean>() {
			
			@Override
			public void onSuccess(Boolean result) {
				if (!result) {
					SC.warn("Update failure");
				} else {
					MessagePanel.showMessage("Update started");
				}
			}
			
			@Override
			public void onFailure(Throwable caught) {
				SC.warn("Failure");
			}
		});
	}
}
