/* DataValidationHandler.java

{{IS_NOTE
	Purpose:
		
	Description:
		
	History:
		2015/3/27 , Created by JerryChen
}}IS_NOTE

Copyright (C) 2015 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
}}IS_RIGHT
*/
package org.zkoss.zssex.ui.impl.ua;

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

import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.SerializableEventListener;
import org.zkoss.zss.api.Range;
import org.zkoss.zss.api.Ranges;
import org.zkoss.zss.api.AreaRef;
import org.zkoss.zss.api.model.Validation.AlertStyle;
import org.zkoss.zss.api.model.Validation.OperatorType;
import org.zkoss.zss.api.model.Validation.ValidationType;
import org.zkoss.zss.api.model.Sheet;
import org.zkoss.zss.api.model.Validation;
import org.zkoss.zss.model.CellRegion;
import org.zkoss.zss.model.InvalidModelOpException;
import org.zkoss.zss.model.SDataValidation;
import org.zkoss.zss.model.SSheet;
import org.zkoss.zss.model.STable;
import org.zkoss.zss.ui.UserActionContext;
import org.zkoss.zss.ui.impl.ua.AbstractCellHandler;
import org.zkoss.zss.ui.sys.UndoableActionManager;
import org.zkoss.zssex.ui.dialog.DataValidationCtrl;
import org.zkoss.zssex.ui.dialog.FormatCellCtrl;
import org.zkoss.zssex.ui.dialog.impl.DialogCallbackEvent;
import org.zkoss.zssex.ui.impl.undo.DataValidationAction;
import org.zkoss.zul.Messagebox;

/**
 * @author JerryChen
 *
 */
public class DataValidationHandler extends AbstractCellHandler {
	private static final long serialVersionUID = 1889483495942352074L;

	/* (non-Javadoc)
	 * @see org.zkoss.zss.ui.sys.ua.impl.AbstractHandler#processAction(org.zkoss.zss.ui.UserActionContext)
	 */
	@Override
	protected boolean processAction(final UserActionContext ctx) {
		final Sheet sheet = ctx.getSheet();
		final AreaRef selection = ctx.getSelection();
		Range range = Ranges.range(sheet, selection);
		final List<Validation> validations = range.getValidations(); 
		//ZSS-990
		validTableTotalRows(range);
		if(isOverlapped(range)) {
			String label = Labels.getLabel("zssex.dlg.format.dataValidation.overlapMsg");
			Messagebox.show(label, "ZK Spreadsheet", 
					Messagebox.OK + Messagebox.CANCEL, Messagebox.INFORMATION, new SerializableEventListener<Event>() {
				private static final long serialVersionUID = 2936000638773070248L;

				@Override
				public void onEvent(Event event) throws Exception {
					if(event.getData().equals(Messagebox.OK)) {
						showValidationDialog(ctx, sheet, selection, validations);
					}
				}
			});
		} else {
			showValidationDialog(ctx, sheet, selection, validations);			
		}
		return true;
	}

	//ZSS-990
	private void validTableTotalRows(Range range) {
		final int row1 = range.getRow();
		final int row2 = range.getLastRow();
		final int col1 = range.getColumn();
		final int col2 = range.getLastColumn();
		
		final SSheet sheet = range.getSheet().getInternalSheet();
		for (STable tb : sheet.getTables()) {
			if (tb.getTotalsRowCount() == 0) continue;
			
			final CellRegion rgn = tb.getAllRegion().getRegion();
			final int tc1 = rgn.getColumn();
			final int tr2 = rgn.getLastRow();
			final int tc2 = rgn.getLastColumn();
			
			// if overlap the table totals row
			if (tr2 >= row1 && tr2 <= row2 && tc2 >= col1 && tc1 <= col2) {
				throw new InvalidModelOpException("The operation cannot be applied on Table's totals row"); //ZSS-990
			}
		}
	}

	/**
	 * Detect if current selection has two validation or 1 validation with any empty cells 
	 * @return true means current selection includes two or more validations, or 1 validation with empty cells.
	 */
	//ZSS-698
	private boolean isOverlapped(Range range) {
		List<SDataValidation> validations = range.getInternalRange().getValidations();
		if(validations.size() >= 2)
			return true;
		if(validations.size() == 1) {
			Iterator<CellRegion> validationIter = validations.get(0).getRegions().iterator();
			CellRegion cellRegion = new CellRegion(range.getRow(), range.getColumn(), range.getLastRow(), range.getLastColumn());
			List<CellRegion> remaining = new ArrayList<CellRegion>(2);
			remaining.add(cellRegion);
			while(validationIter.hasNext()) {
				CellRegion validationRegion = validationIter.next();
				List<CellRegion> tempRegion = new ArrayList<CellRegion>(2);
				for (CellRegion remainingRegion : remaining) {
					tempRegion.addAll(remainingRegion.diff(validationRegion.getOverlap(remainingRegion)));
				}
				remaining = tempRegion;
			}
			return remaining.size() > 0;
		}
		return false;
	}

	private void showValidationDialog(final UserActionContext ctx,
			final Sheet sheet, final AreaRef selection,
			final List<Validation> validations) {
		
		Validation validation = validations.size() > 0 ? validations.get(0) : null;
		DataValidationCtrl.show(new SerializableEventListener<DialogCallbackEvent>(){
			private static final long serialVersionUID = -1058080304759009998L;

			@Override
			public void onEvent(DialogCallbackEvent event) throws Exception {
				if(FormatCellCtrl.ON_OK.equals(event.getName())){
					
					ValidationType validationType = (ValidationType)event.getData(DataValidationCtrl.ARG_VALIDATION_TYPE_CODE);
					OperatorType operatorType = (OperatorType)event.getData(DataValidationCtrl.ARG_OPERATOR_TYPE_CODE);
					boolean ignoreBlank = (Boolean)event.getData(DataValidationCtrl.ARG_IGNORE_BLANK_CODE);
					boolean inCellDropDown = (Boolean)event.getData(DataValidationCtrl.ARG_IN_CELL_DROPDOWN_CODE);
					String param1 = (String)event.getData(DataValidationCtrl.ARG_PARAM1_CODE);
					String param2 = (String)event.getData(DataValidationCtrl.ARG_PARAM2_CODE);
					
					boolean isShowInput = (Boolean)event.getData(DataValidationCtrl.ARG_SHOW_INPUT_CODE);
					String inputTitle = (String)event.getData(DataValidationCtrl.ARG_INPUT_TITLE_CODE);
					String inputMessage = (String)event.getData(DataValidationCtrl.ARG_INPUT_MESSAGE_CODE);
					
					boolean isShowError = (Boolean)event.getData(DataValidationCtrl.ARG_SHOW_ERROR_CODE);
					AlertStyle alertStyle = (AlertStyle)event.getData(DataValidationCtrl.ARG_ALERT_STYLE_CODE);
					String errorTitle = (String)event.getData(DataValidationCtrl.ARG_ERROR_TITLE_CODE);
					String errorMessage = (String)event.getData(DataValidationCtrl.ARG_ERROR_MESSAGE_CODE);
					
					UndoableActionManager uam = ctx.getSpreadsheet().getUndoableActionManager();
					uam.doAction(new DataValidationAction(Labels.getLabel("zss.undo.insertComment"), sheet,
						selection.getRow(), selection.getColumn(), 
						selection.getLastRow(), selection.getLastColumn(),
						validationType, ignoreBlank, operatorType, inCellDropDown, param1, param2,
						isShowInput, inputTitle, inputMessage, isShowError, alertStyle, errorTitle, errorMessage));
				}
				
			}}, validation, ctx.getSpreadsheet());
	}

}
