package com.smartgwt.sample.client;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gson.Gson;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Timer;
import com.smartgwt.client.data.AdvancedCriteria;
import com.smartgwt.client.data.Criteria;
import com.smartgwt.client.data.Criterion;
import com.smartgwt.client.data.DSCallback;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.data.DataSource;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.RecordList;
import com.smartgwt.client.rpc.RPCManager;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.AutoFitWidthApproach;
import com.smartgwt.client.types.Autofit;
import com.smartgwt.client.types.Axis;
import com.smartgwt.client.types.FieldType;
import com.smartgwt.client.types.ListGridEditEvent;
import com.smartgwt.client.types.ListGridFieldType;
import com.smartgwt.client.types.OperatorId;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.types.SortArrow;
import com.smartgwt.client.types.SortDirection;
import com.smartgwt.client.types.SummaryFunctionType;
import com.smartgwt.client.util.JSOHelper;
import com.smartgwt.client.util.JSON;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.util.ValueCallback;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.Img;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.TransferImgButton;
import com.smartgwt.client.widgets.cube.CubeGrid;
import com.smartgwt.client.widgets.cube.FacetValue;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.events.DrawEvent;
import com.smartgwt.client.widgets.events.DrawHandler;
import com.smartgwt.client.widgets.events.ResizedEvent;
import com.smartgwt.client.widgets.events.ResizedHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
import com.smartgwt.client.widgets.grid.CellFormatter;
import com.smartgwt.client.widgets.grid.CellValueHoverFormatter;
import com.smartgwt.client.widgets.grid.HoverCustomizer;
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.DataChangedEvent;
import com.smartgwt.client.widgets.grid.events.DataChangedHandler;
import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
import com.smartgwt.client.widgets.grid.events.RemoveRecordClickEvent;
import com.smartgwt.client.widgets.grid.events.RemoveRecordClickHandler;
import com.smartgwt.client.widgets.grid.events.ViewStateChangedEvent;
import com.smartgwt.client.widgets.grid.events.ViewStateChangedHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.menu.Menu;
import com.smartgwt.client.widgets.menu.MenuItem;
import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;

/**
 * Class that provides more customization for the standard cubegrid, for use as a BEER Dashboard
 * @author Alexander Trefonas
 *
 */
public class TKRCubeGrid extends CubeGrid {

	CubeGridConfig config;
	DataSource dataSource;
	static TKRCubeGrid cubeGrid;
	private boolean didDraw = false;
	private boolean authorized = false;
	Map<String, RecordList> metricColumnTypeToUserEditsList;
	
	
	
	public TKRCubeGrid() {
		metricColumnTypeToUserEditsList = new HashMap<String, RecordList>();
/* 
 * README!
 * Below style lines were disabled 1/31/2018. Re-enable for custom styling. 
 */
//		setBaseStyle("brcmGridCell");
//		setInnerHeaderBaseStyle("brcmCubeGridHeader");
//		setColHeaderBaseStyle("brcmCubeGridHeader");
//		setRowHeaderBaseStyle("brcmCubeGridHeader");
		
		final TKRCubeGrid self = this;
		this.setWrapFacetTitles(true);
		this.setWrapFacetValueTitles(true);
		this.setWrapCells(true);
		this.setRowHeaderGridMode(true);
		this.setCanHover(true);
		this.setScrollbarSize(15);
		this.setShowCustomScrollbars(true);
		this.setHoverAutoFitMaxWidth(400);	
		this.setCanMinimizeFacets(true);

		
		new Timer() {

			@Override
			public void run() {
				final ListGridField[] fields = self.getAllFields();
				int i = 0;
				for (ListGridField field : fields) {
					field.setAttribute("BrcmColumnOrder", i);
					i++;
				}
				
				final Timer resizedVSTimer = new Timer(){

					@Override
					public void run() {
						RecordList reclist = self.getRecordList();
						
						Map<Integer, String> colSeqToColId = new HashMap<Integer, String>();
						for (int i = 0; i < reclist.getLength(); i++) {
							Record rec = reclist.get(i);
							if (rec.getAttribute("_rowNum").equals("0")) {
								Integer colSeq = rec.getAttributeAsInt("_colNum");
								if (colSeq >= 0) {
									colSeqToColId.put(colSeq, rec.getAttribute("PK_TKR_Columns"));
								}
							}
						}
						
						final ListGridField[] fields = self.getAllFields();
						
						int i = 0;
						DataSource columnsDS = DataSource.get("TKR_Columns");
						
						RPCManager.startQueue();
						for (ListGridField field : fields) {
							String width = field.getWidth();
							String columnId = colSeqToColId.get(i);
							Record updateRec = new Record();
							updateRec.setAttribute("PK_TKR_Columns", columnId);
							updateRec.setAttribute("CustomWidth", width);
							columnsDS.updateData(updateRec);
							i++;
						}
						
						RPCManager.sendQueue();
					}};
				
				
				self.addResizedHandler(new ResizedHandler() {

					@Override
					public void onResized(ResizedEvent event) {
						if (authorized) {
							resizedVSTimer.schedule(1000);
						}
					}});
				
				self.addCellContextClickHandler(new CellContextClickHandler() {

					@Override
					public void onCellContextClick(CellContextClickEvent event) {
						event.cancel();
						String viewState = self.getViewState();
						
						Menu menu = new Menu();
						MenuItem descItem = new MenuItem("Set Description");
						MenuItem commentItem = new MenuItem("Add Comment");
						MenuItem manageItem = new MenuItem("Manage Comments");
						
						final String metricId = event.getRecord().getAttribute("PK_TKR_Metrics");
						final String columnId = event.getRecord().getAttribute("PK_TKR_Columns");

						if (authorized) {
							menu.setItems(descItem, commentItem, manageItem);
						} else {
							menu.setItems(commentItem);
						}
						descItem.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler(){
							@Override
							public void onClick(MenuItemClickEvent event) {
								SC.askforValue("Set Description", "Enter the description:", new ValueCallback(){

									@Override
									public void execute(String value) {
										if (value == null) {
											return;
										}
										
									}});
								
							}});
						commentItem.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler(){
							@Override
							public void onClick(MenuItemClickEvent event) {
								SC.askforValue("Add Comment", "Enter the comment:", new ValueCallback(){

									@Override
									public void execute(String value) {
										if (value == null || value.length() == 0) {
											return;
										}
										
									}});
								
							}});
						
						
						menu.showContextMenu();
					}});
				
			}}.schedule(1);

		setCellFormatter(new CellFormatter() {

			@Override
			public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
				if (value == null) {
					return "-";
				}
				
				if (record.getAttribute("metric").contains("Comment")) {
					String val = record.getAttribute("Value");
					if (val.length() < 30) {
						return val;
					} else {
						return val.substring(0,  30) + "...";
					}
				}
				
				String columnId = record.getAttribute("PK_TKR_Columns"); 
				String metricId = record.getAttribute("PK_TKR_Metrics"); 
				String key1 = metricId + "-" + columnId + "-description";
				String key2 = metricId + "-" + columnId + "-comment";
				
				boolean hasUserEdit = false;

				if (metricColumnTypeToUserEditsList.get(key1) != null &&
					metricColumnTypeToUserEditsList.get(key1).getLength() > 0) {
					hasUserEdit = true;
				}
				if (metricColumnTypeToUserEditsList.get(key2) != null &&
					metricColumnTypeToUserEditsList.get(key2).getLength() > 0) {
					hasUserEdit = true;
				}				
				
				String retval =  value == null ? "-" : "<span style='font-size:15px;'>"+value.toString()+"</span>";
				
				retval += "";
				return retval;
				
			}
		});

	}
	
	public void setAuthorized(boolean authorized) {
		this.authorized = authorized;
	}
	
	public void clearEdits(String metricId, String columnId) {
		if (metricColumnTypeToUserEditsList == null) {
			return;
		}
		
		String key = metricId+"-"+columnId+"-"+"description";
		metricColumnTypeToUserEditsList.remove(key);
		key = metricId+"-"+columnId+"-"+"comment";
		metricColumnTypeToUserEditsList.remove(key);

	}
	
	public void setUserEditsMapFromRecords(Record[] records) {
		if (records == null) {
			return;
		}
		if (metricColumnTypeToUserEditsList == null) {
			this.metricColumnTypeToUserEditsList = new HashMap<String, RecordList>();
		}
		
		/* 
		 * In the case when we are adding a single comment, we want to clear out the pre-existing
		 * comments for a metric because after adding the comment, the full list of comments is downloaded
		 * again. So the below set hasEditedKey is used.
		 */
		Set<String> hasEditedKey = new HashSet<String>();
		
		for (Record rec : records) {
			String type = rec.getAttribute("Type");
			String columnId = rec.getAttribute("FK_TKR_Columns");
			String metricId = rec.getAttribute("FK_TKR_Metrics");
			
			String key = metricId+"-"+columnId+"-"+type;
			
			RecordList userEditsList = metricColumnTypeToUserEditsList.get(key);
			if (userEditsList == null || !hasEditedKey.contains(key)) {
				userEditsList = new RecordList();
				metricColumnTypeToUserEditsList.put(key, userEditsList);
			}
			
			hasEditedKey.add(key);

			userEditsList.add(rec);
		}
	}
	
	public void fetchData(AdvancedCriteria criteria, final DSCallback callback) {

		DSRequest cubeDataReq = new DSRequest();
		if ( getValueProperty() != null) {
		Map<String, SummaryFunctionType> summaryFunctions = new HashMap<String, SummaryFunctionType>();
		summaryFunctions.put(getValueProperty(),  SummaryFunctionType.SUM);
		
		cubeDataReq.setSummaryFunctions(summaryFunctions);
		}
		if ( this.getFetchOperation() != null) {
			cubeDataReq.setOperationId(getFetchOperation());
		}
		String[] groupBy = new String[getRowFacets().length + getColumnFacets().length];
		int i = 0;
		for (String facet : getRowFacets()) {
			groupBy[i] = facet;
			i++;
		}
		for (String facet : getColumnFacets()) {
			groupBy[i] = facet;
			i++;
		}
		cubeDataReq.setGroupBy(groupBy);
		dataSource.fetchData(criteria, new DSCallback() {

			@Override
			public void execute(DSResponse dsResponse, Object data, DSRequest dsRequest) {
				setData(dsResponse.getDataAsRecordList());
				if ( callback != null) {
					callback.execute(dsResponse, data, dsRequest);
				}
			}

		}, cubeDataReq);
	}

	public void setConfig(CubeGridConfig config) {
		this.config = config;
		setRowFacets(config.getRowFacets());
		setColumnFacets(config.getColumnFacets());
		setValueProperty(config.getValue());
	}
	public void setDataSource(DataSource datasource) {
		this.dataSource = datasource;
	}



}



