/*	DefaultComponentActionHandler.java

	Purpose:
		
	Description:
		
	History:
		2013/6/25 by Dennis

	Copyright (C) 2010 Potix Corporation. All Rights Reserved.
*/
package org.zkoss.zssex.ui.impl;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.zkoss.lang.Strings;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zss.api.AreaRef;
import org.zkoss.zss.api.Range.PasteOperation;
import org.zkoss.zss.api.Range.PasteType;
import org.zkoss.zss.api.model.Book;
import org.zkoss.zss.api.model.Chart;
import org.zkoss.zss.api.model.Picture;
import org.zkoss.zss.api.model.Sheet;
import org.zkoss.zss.model.SBook;
import org.zkoss.zss.ui.AuxAction;
import org.zkoss.zss.ui.CellSelectionType;
import org.zkoss.zss.ui.Spreadsheet;
import org.zkoss.zss.ui.UserActionContext;
import org.zkoss.zss.ui.UserActionHandler;
import org.zkoss.zss.ui.event.CellSelectionAction;
import org.zkoss.zss.ui.event.CellSelectionUpdateEvent;
import org.zkoss.zss.ui.event.Events;
import org.zkoss.zss.ui.event.WidgetKeyEvent;
import org.zkoss.zss.ui.event.WidgetUpdateEvent;
import org.zkoss.zssex.ui.impl.ua.AbstractObjectHandler;
import org.zkoss.zssex.ui.dialog.HeaderSizeCtrl.HeaderType;
import org.zkoss.zssex.ui.impl.ua.ApplyFilterHandler;
import org.zkoss.zssex.ui.impl.ua.AutoFillHandler;
import org.zkoss.zssex.ui.impl.ua.CleanFilterHandler;
import org.zkoss.zssex.ui.impl.ua.CustomFiltersHandler;
import org.zkoss.zssex.ui.impl.ua.CustomSortHandler;
import org.zkoss.zssex.ui.impl.ua.DataValidationHandler;
import org.zkoss.zssex.ui.impl.ua.DeleteChartHandler;
import org.zkoss.zssex.ui.impl.ua.DeleteCommentHandler;
import org.zkoss.zssex.ui.impl.ua.DeletePictureHandler;
import org.zkoss.zssex.ui.impl.ua.EditCommentHandler;
import org.zkoss.zssex.ui.impl.ua.FormatCellHandler;
import org.zkoss.zssex.ui.impl.ua.HeaderSizeHandler;
import org.zkoss.zssex.ui.impl.ua.HideSheetHandler;
import org.zkoss.zssex.ui.impl.ua.HyperlinkHandler;
import org.zkoss.zssex.ui.impl.ua.InsertChartHandler;
import org.zkoss.zssex.ui.impl.ua.InsertCommentHandler;
import org.zkoss.zssex.ui.impl.ua.InsertFunctionHandler;
import org.zkoss.zssex.ui.impl.ua.InsertPictureHandler;
import org.zkoss.zssex.ui.impl.ua.MergeCenterHandler;
import org.zkoss.zssex.ui.impl.ua.MergeHandler;
import org.zkoss.zssex.ui.impl.ua.MoveChartHandler;
import org.zkoss.zssex.ui.impl.ua.MovePictureHandler;
import org.zkoss.zssex.ui.impl.ua.PasteSpecialDialogHandler;
import org.zkoss.zssex.ui.impl.ua.PasteSpecialHandler;
import org.zkoss.zssex.ui.impl.ua.ProtectSheetAction;
import org.zkoss.zssex.ui.impl.ua.ReapplyFilterHandler;
import org.zkoss.zssex.ui.impl.ua.ShiftCellHandler;
import org.zkoss.zssex.ui.impl.ua.Top10FilterHandler;
import org.zkoss.zssex.ui.impl.ua.UnhideSheetHandler;
import org.zkoss.zssex.ui.impl.ua.UnmergeHandler;
import org.zkoss.zssex.ui.impl.ua.RichTextEditHandler;
/**
 * Action Handler for user's action in zssex, it handles widget (chart and image) actions
 * 
 * @author dennis
 * 
 */
public class UserActionManagerCtrlImpl extends org.zkoss.zss.ui.impl.DefaultUserActionManagerCtrl {
	private static final long serialVersionUID = 1L;

	private final Set<String> _interestedEvents = new LinkedHashSet<String>();
	
	public UserActionManagerCtrlImpl(){
		_interestedEvents.add(Events.ON_WIDGET_CTRL_KEY);
		_interestedEvents.add(Events.ON_WIDGET_UPDATE);
		_interestedEvents.add(Events.ON_CELL_SELECTION_UPDATE);
		
		initDefaultAuxHandlers();
	}
	
	private void initDefaultAuxHandlers() {
		String category =  Category.AUXACTION.getName();
		UserActionHandler uah;
		
		registerHandler(category, AuxAction.PASTE_FORMULA.getAction(), new PasteSpecialHandler(PasteType.FORMULAS,PasteOperation.NONE,false,false));
		registerHandler(category, AuxAction.PASTE_VALUE.getAction(), new PasteSpecialHandler(PasteType.VALUES,PasteOperation.NONE,false,false));
		registerHandler(category, AuxAction.PASTE_ALL_EXPECT_BORDERS.getAction(), new PasteSpecialHandler(PasteType.ALL_EXCEPT_BORDERS,PasteOperation.NONE,false,false));
		registerHandler(category, AuxAction.PASTE_TRANSPOSE.getAction(), new PasteSpecialHandler(PasteType.ALL, PasteOperation.NONE, false, true));
		
		
		registerHandler(category, AuxAction.MERGE_AND_CENTER.getAction(), new MergeCenterHandler());
		registerHandler(category, AuxAction.MERGE_ACROSS.getAction(), new MergeHandler(true));
		registerHandler(category, AuxAction.MERGE_CELL.getAction(), new MergeHandler(false));
		registerHandler(category, AuxAction.UNMERGE_CELL.getAction(), new UnmergeHandler());
		
		registerHandler(category, AuxAction.FILTER.getAction(), new ApplyFilterHandler());
		registerHandler(category, AuxAction.CLEAR_FILTER.getAction(), new CleanFilterHandler());
		registerHandler(category, AuxAction.REAPPLY_FILTER.getAction(), new ReapplyFilterHandler());
		
		registerHandler(category, AuxAction.PROTECT_SHEET.getAction(), new ProtectSheetAction());
		
		registerHandler(category, AuxAction.INSERT_CHART.getAction(), new AbstractObjectHandler() {
			private static final long serialVersionUID = -5783144640583968481L;

			@Override
			protected boolean processAction(UserActionContext ctx) {
				return false;
			}
		});
		
		registerHandler(category, AuxAction.COLUMN_CHART.getAction(), 
				new InsertChartHandler(Chart.Type.COLUMN,Chart.Grouping.STANDARD, Chart.LegendPosition.RIGHT));
		
		registerHandler(category, AuxAction.COLUMN_CHART_3D.getAction(), 
				new InsertChartHandler(Chart.Type.COLUMN_3D,Chart.Grouping.STANDARD, Chart.LegendPosition.RIGHT));
		
		registerHandler(category, AuxAction.LINE_CHART.getAction(), 
				new InsertChartHandler(Chart.Type.LINE,Chart.Grouping.STANDARD, Chart.LegendPosition.RIGHT));
		
		registerHandler(category, AuxAction.LINE_CHART_3D.getAction(), 
				new InsertChartHandler(Chart.Type.LINE_3D,Chart.Grouping.STANDARD, Chart.LegendPosition.RIGHT));
		
		registerHandler(category, AuxAction.PIE_CHART.getAction(), 
				new InsertChartHandler(Chart.Type.PIE,Chart.Grouping.STANDARD, Chart.LegendPosition.RIGHT));
		
		registerHandler(category, AuxAction.PIE_CHART_3D.getAction(), 
				new InsertChartHandler(Chart.Type.PIE_3D,Chart.Grouping.STANDARD, Chart.LegendPosition.RIGHT));
		
		registerHandler(category, AuxAction.BAR_CHART.getAction(), 
				new InsertChartHandler(Chart.Type.BAR,Chart.Grouping.STANDARD, Chart.LegendPosition.RIGHT));
		
		registerHandler(category, AuxAction.BAR_CHART_3D.getAction(),
				new InsertChartHandler(Chart.Type.BAR_3D,Chart.Grouping.STANDARD, Chart.LegendPosition.RIGHT));
		
		registerHandler(category, AuxAction.AREA_CHART.getAction(),
				new InsertChartHandler(Chart.Type.AREA,Chart.Grouping.STANDARD, Chart.LegendPosition.RIGHT));
		
		registerHandler(category, AuxAction.SCATTER_CHART.getAction(),
				new InsertChartHandler(Chart.Type.SCATTER,Chart.Grouping.STANDARD, Chart.LegendPosition.RIGHT));
		
		registerHandler(category, AuxAction.DOUGHNUT_CHART.getAction(),
				new InsertChartHandler(Chart.Type.DOUGHNUT,Chart.Grouping.STANDARD, Chart.LegendPosition.RIGHT));
		
		registerHandler(category, AuxAction.INSERT_PICTURE.getAction(), new InsertPictureHandler());
		
		registerHandler(category, AuxAction.ROW_HEIGHT.getAction(), new HeaderSizeHandler(HeaderType.ROW));
		registerHandler(category, AuxAction.COLUMN_WIDTH.getAction(), new HeaderSizeHandler(HeaderType.COLUMN));
		
		registerHandler(category, AuxAction.PASTE_SPECIAL.getAction(), new PasteSpecialDialogHandler());
		
		registerHandler(category, AuxAction.CUSTOM_SORT.getAction(), new CustomSortHandler());
		
		registerHandler(category, AuxAction.HYPERLINK.getAction(), new HyperlinkHandler());
		
		registerHandler(category, AuxAction.FORMAT_CELL.getAction(), new FormatCellHandler());
		
		registerHandler(category, AuxAction.DATA_VALIDATION.getAction(), new DataValidationHandler());
		
		registerHandler(category, AuxAction.INSERT_FUNCTION.getAction(), new InsertFunctionHandler());
		
		registerHandler(category, AuxAction.RICH_TEXT_EDIT.getAction(), new RichTextEditHandler());
		
		registerHandler(category, AuxAction.HIDE_SHEET.getAction(), new HideSheetHandler());
		
		registerHandler(category, AuxAction.UNHIDE_SHEET.getAction(), new UnhideSheetHandler());
		
		registerHandler(category, AuxAction.INSERT_COMMENT.getAction(), new InsertCommentHandler());
		
		registerHandler(category, AuxAction.EDIT_COMMENT.getAction(), new EditCommentHandler());
		
		registerHandler(category, AuxAction.DELETE_COMMENT.getAction(), new DeleteCommentHandler());

		//ZSS-1192: call CustomFitlersHandler#processAction()
		registerHandler(category, AuxAction.CUSTOM_FILTERS.getAction(), new CustomFiltersHandler());
		
		//ZSS-1193: call Top10FitlersHandler#processAction()
		registerHandler(category, AuxAction.TOP10_FILTER.getAction(), new Top10FilterHandler());
		
		//for enable some menu folder, do nothing
		UserActionHandler folderhandler = new AbstractObjectHandler() {
			private static final long serialVersionUID = 2987372171521192422L;

			@Override
			protected boolean processAction(final UserActionContext ctx) {
				return false;
			}
		};
		registerHandler(category, AuxAction.OTHER_CHART.getAction(), folderhandler);
		
		
		category =  Category.KEYSTROKE.getName();
		registerHandler(category, "#del/picture", new DeletePictureHandler());
		registerHandler(category, "#del/chart", new DeleteChartHandler());
		
		
		//event
		category =  Category.EVENT.getName();
		registerHandler(category, Events.ON_CELL_SELECTION_UPDATE+SPLIT_CHAR+"move", new ShiftCellHandler());
		registerHandler(category, Events.ON_CELL_SELECTION_UPDATE+SPLIT_CHAR+"resize", new AutoFillHandler());
		
		registerHandler(category, Events.ON_WIDGET_UPDATE+SPLIT_CHAR+"move"+SPLIT_CHAR+"picture", new MovePictureHandler());
		registerHandler(category, Events.ON_WIDGET_UPDATE+SPLIT_CHAR+"resize"+SPLIT_CHAR+"picture", new MovePictureHandler());
		registerHandler(category, Events.ON_WIDGET_UPDATE+SPLIT_CHAR+"move"+SPLIT_CHAR+"chart", new MoveChartHandler());
		registerHandler(category, Events.ON_WIDGET_UPDATE+SPLIT_CHAR+"resize"+SPLIT_CHAR+"chart", new MoveChartHandler());
	}
	
	@Override
	public Set<String> getInterestedEvents() {
		Set<String> evts = new LinkedHashSet<String>();
		evts.addAll(super.getInterestedEvents());
		evts.addAll(_interestedEvents);
		return evts;
	}
	
	
	
	protected boolean dispatchCellSelectionUpdateAction(UserActionContext ctx) {
		CellSelectionUpdateEvent evt = (CellSelectionUpdateEvent)ctx.getEvent();
		//last selection either get form selection or from event
		String action;
		if(evt.getAction()==CellSelectionAction.MOVE){
			action = Events.ON_CELL_SELECTION_UPDATE+SPLIT_CHAR+"move";
		}else if(evt.getAction()==CellSelectionAction.RESIZE){
			action = Events.ON_CELL_SELECTION_UPDATE+SPLIT_CHAR+"resize";
		}else{
			return false;
		}
		((UserActionContextImpl)ctx).setAction(action);
		
		((UserActionContextImpl)ctx).setData("source", new AreaRef(evt.getOrigRow(),evt.getOrigColumn(),evt.getOrigLastRow(),evt.getOrigLastColumn()));
		
		boolean r = false;
		for(UserActionHandler uac :getHandlerList(ctx.getCategory(), ctx.getAction())){
			if(uac!=null && uac.isEnabled(ctx.getBook(), ctx.getSheet())){
				r |= uac.process(ctx);
			}
		}
		return r;
		
	}
	
	protected boolean dispatchWidgetKeyAction(UserActionContext ctx) {
		WidgetKeyEvent event = (WidgetKeyEvent)ctx.getEvent();

		String action = ctx.getAction();
		if(event!=null){
			action = getAction(event);
			if(Strings.isBlank(action))
				return false;
			
			Object widgetData = event.getData();
			if(widgetData instanceof Picture){
				action = action+SPLIT_CHAR+"picture";
				((UserActionContextImpl)ctx).setData("picture",widgetData);
			}else if(widgetData instanceof Chart){
				action = action+SPLIT_CHAR+"chart";
				((UserActionContextImpl)ctx).setData("chart",widgetData);
			}
		}
		((UserActionContextImpl)ctx).setAction(action);
		
		boolean r = false;
		for(UserActionHandler uac :getHandlerList(ctx.getCategory(), ctx.getAction())){
			if(uac!=null && uac.isEnabled(ctx.getBook(), ctx.getSheet())){
				r |= uac.process(ctx);
			}
		}
		return r;
	}
	
	protected boolean dispatchWidgetUpdateAction(UserActionContext ctx) {
		WidgetUpdateEvent event = (WidgetUpdateEvent)ctx.getEvent();
		Object widgetData = event.getData();
		String action = "";
		((UserActionContextImpl)ctx).setData("anchor",event.getSheetAnchor());
		if(widgetData instanceof Picture){
			switch(event.getAction()){
			case RESIZE:
				action = Events.ON_WIDGET_UPDATE+SPLIT_CHAR+"resize"+SPLIT_CHAR+"picture";
				break;
			case MOVE:
				action = Events.ON_WIDGET_UPDATE+SPLIT_CHAR+"move"+SPLIT_CHAR+"picture";
				break;
			}
			((UserActionContextImpl)ctx).setData("picture",widgetData);
		}else if(widgetData instanceof Chart){
			switch(event.getAction()){
			case RESIZE:
				action = Events.ON_WIDGET_UPDATE+SPLIT_CHAR+"resize"+SPLIT_CHAR+"chart";
				break;
			case MOVE:
				action = Events.ON_WIDGET_UPDATE+SPLIT_CHAR+"move"+SPLIT_CHAR+"chart";
				break;
			}
			((UserActionContextImpl)ctx).setData("chart",widgetData);
		}
		((UserActionContextImpl)ctx).setAction(action);
		
		boolean r = false;
		for(UserActionHandler uac :getHandlerList(ctx.getCategory(), ctx.getAction())){
			if(uac!=null && uac.isEnabled(ctx.getBook(), ctx.getSheet())){
				r |= uac.process(ctx);
			}
		}
		return r;
		
	}
	
	@Override
	public void onEvent(Event event) throws Exception {
		super.onEvent(event);
		String nm = event.getName();
		if(!_interestedEvents.contains(nm))
			return;

		Spreadsheet spreadsheet = (Spreadsheet)event.getTarget();
		Book book = spreadsheet.getBook();
		Sheet sheet = spreadsheet.getSelectedSheet();
		String action = "";
		AreaRef selection = spreadsheet.getSelection();
		Map<String,Object> extraData = new HashMap<String,Object>();
		
		AreaRef visibleSelection = new AreaRef(selection.getRow(), selection.getColumn(), 
			Math.min(spreadsheet.getCurrentMaxVisibleRows(), selection.getLastRow()), //ZSS-1084 
			Math.min(spreadsheet.getCurrentMaxVisibleColumns(), selection.getLastColumn())); //ZSS-1084

		CellSelectionType _selectionType = CellSelectionType.CELL;

		//book could be null after close -> new book
		SBook sbook = book==null?null:book.getInternalBook();
		if(sbook!=null){
			boolean wholeRow = selection.getColumn()==0 && selection.getLastColumn()>=sbook.getMaxColumnIndex();
			boolean wholeColumn = selection.getRow()==0 && selection.getLastRow()>=sbook.getMaxRowIndex();
			boolean wholeSheet = wholeRow&&wholeColumn;
			
			_selectionType = wholeSheet?CellSelectionType.ALL:wholeRow?CellSelectionType.ROW:wholeColumn?CellSelectionType.COLUMN:CellSelectionType.CELL;
		}
		
		if(Events.ON_WIDGET_CTRL_KEY.equals(nm)){
			UserActionContextImpl ctx = new UserActionContextImpl(spreadsheet,event,book,sheet,visibleSelection,_selectionType,extraData,Category.KEYSTROKE.getName(),action);
			dispatchWidgetKeyAction(ctx);
		}else if(Events.ON_WIDGET_UPDATE.equals(nm)){
			UserActionContextImpl ctx = new UserActionContextImpl(spreadsheet,event,book,sheet,visibleSelection,_selectionType,extraData,Category.EVENT.getName(),action);
			dispatchWidgetUpdateAction(ctx);
		}else if(Events.ON_CELL_SELECTION_UPDATE.equals(nm)){
			UserActionContextImpl ctx = new UserActionContextImpl(spreadsheet,event,book,sheet,visibleSelection,_selectionType,extraData,Category.EVENT.getName(),action);
			dispatchCellSelectionUpdateAction(ctx);
		}
		
	}
}
