/* DataValidationLoaderImpl.java

{{IS_NOTE
	Purpose:
		
	Description:
		
	History:
		2013/8/7 , Created by dennis
}}IS_NOTE

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

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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.zkoss.json.JSONArray;
import org.zkoss.poi.ss.usermodel.ZssContext;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zss.api.model.Sheet;
import org.zkoss.zss.api.model.impl.SheetImpl;
import org.zkoss.zss.model.CellRegion;
import org.zkoss.zss.model.SCell;
import org.zkoss.zss.model.SDataValidation;
import org.zkoss.zss.model.SSheet;
import org.zkoss.zss.model.impl.AbstractDataValidationAdv;
import org.zkoss.zss.model.sys.EngineFactory;
import org.zkoss.zss.model.sys.format.FormatContext;
import org.zkoss.zss.model.sys.format.FormatEngine;
import org.zkoss.zss.model.sys.format.FormatResult;
import org.zkoss.zss.ui.sys.DataValidationHandler;
import org.zkoss.zssex.ui.ValidationHelper;

/**
 * 
 * @author dennis
 *
 */
//migrate from ose to ee
public class DataValidationHandlerImpl implements DataValidationHandler {
	private static final long serialVersionUID = -474331142130548708L;

	/* (non-Javadoc)
	 * @see org.zkoss.zss.ui.sys.DataValidationLoader#loadDataValidtionJason(org.zkoss.zss.model.sys.XSheet)
	 */
	@Override
	public List<Map<String, Object>> loadDataValidtionJASON(Sheet sheet) {
		SSheet xsheet = (SSheet) ((SheetImpl)sheet).getNative();
		return convertDataValidationToJSON(xsheet,xsheet.getDataValidations());
	}
	
	
	private List<Map<String, Object>> convertDataValidationToJSON(SSheet sheet,List<SDataValidation> dvs) {
		if (dvs != null && !dvs.isEmpty()) {
			List<Map<String, Object>> results = new ArrayList<Map<String, Object>>(dvs.size());
			for(SDataValidation dv : dvs) {
				results.add(convertDataValidationToJSON(sheet,dv));
			}
			return results;
		}
		return null;
	}
	
	private Map<String, Object> convertDataValidationToJSON(SSheet sheet,SDataValidation dv) {
		final List<Map<String, Integer>> addrmapary = new ArrayList<Map<String, Integer>>(dv.getRegions().size() * 4 / 3 + 1);
		for (CellRegion addr : dv.getRegions()) {
			final int left = addr.getColumn();
			final int right = addr.getLastColumn();
			final int top = addr.getRow();
			final int bottom = addr.getLastRow();
			final Map<String, Integer> addrmap = new HashMap<String, Integer>();
			addrmap.put("left", left);
			addrmap.put("top", top);
			addrmap.put("right", right);
			addrmap.put("bottom", bottom);
			addrmapary.add(addrmap);
		}
		
		final Map<String, Object> validMap = new HashMap<String, Object>();
		validMap.put("id",dv.getId());
		validMap.put("rangeList", addrmapary); //range list
		if(dv.isShowInput()){
			validMap.put("showPrompt",true); //whether show prompt box
			validMap.put("promptTitle", dv.getInputTitle()); //the prompt box title
			validMap.put("promptText", dv.getInputMessage()); //the prompt box text
		}
		//LIST
		JSONArray listAry = new JSONArray(); // array of List
		if (dv.isInCellDropdown()) {
			if (dv.hasReferToRelativeCol() || dv.hasReferToRelativeRow()) {
				for (CellRegion addr : dv.getRegions()) {
					final int left = addr.getColumn();
					final int right = addr.getLastColumn();
					final int top = addr.getRow();
					final int bottom = addr.getLastRow();
					for (int r = top; r <= bottom; ++r) {
						for (int c = left; c <= right; ++c) {
							final List<Map<String, Integer>> addrmapary0 = new ArrayList<Map<String, Integer>>(2);
							final Map<String, Integer> addrmap = new HashMap<String, Integer>();
							addrmap.put("left", c);
							addrmap.put("top", r);
							addrmap.put("right", c);
							addrmap.put("bottom", r);
							addrmapary0.add(addrmap);
							
							String[] validationList = getValidationList(r, c, dv);
							Map<String, Object> list = prepareList(validationList, addrmapary0, dv);
							if (list != null) {
								listAry.add(list);
							}
							((AbstractDataValidationAdv)dv).addDependency(r, c);
						}
					}
				}
			} else {
				CellRegion addr = dv.getRegions().iterator().next();
				final int left = addr.getColumn();
				final int right = addr.getLastColumn();
				String[] validationList = getValidationList(left, right, dv);
				Map<String, Object> list = prepareList(validationList, addrmapary, dv);
				if (list != null) {
					listAry.add(list);
				}
			}
			if (!listAry.isEmpty()) {
				//ZSS-197: the method is useful only list validation objects
				validMap.put("showButton", true); //whether show dropdown button
				validMap.put("lists", listAry);
			}
		}
		return validMap;
	}

	private Map<String, Object> prepareList(String[] validationList, List<Map<String, Integer>> addrmapary, SDataValidation dv) {
		if (validationList != null) {
			Map<String, Object> list = new HashMap<String, Object>(); // per List
			list.put("rangeList", addrmapary);
			JSONArray jsonAry = new JSONArray(); // drop down validationList
			for (String v : validationList) {
				jsonAry.add(v);
			}
			list.put("validationList", jsonAry);
			return list;
		}
		return null;
	}

	private String[] getValidationList(int row, int col, SDataValidation dv) {
		List<String> list = new LinkedList<String>();
		if(dv.hasReferToCellList()){
			FormatEngine fe = EngineFactory.getInstance().createFormatEngine(); 
			for(SCell cell:dv.getReferToCellList(row, col)){
				FormatResult r = fe.format(cell, new FormatContext(ZssContext.getCurrent().getLocale()));
				list.add(r.getText());
			}
		}else{
			int s = dv.getNumOfValue1();
			//ZSS-810: after dv.getNumOfValue1() the formula has been 
			//    evaluated and might evaluated to a LazyAreaEval or LazyRefEval
			if (dv.hasReferToCellList()) {
				return getValidationList(row, col, dv);
			}
			for(int i=0;i<s;i++){
				Object val = dv.getValue1(i);
				list.add(val==null?"":val.toString());
			}
		}
		return list.toArray(new String[list.size()]);
	}


	@Override
	public boolean validate(Sheet sheet, int row, int col, String editText,
			EventListener callback) {
		return new ValidationHelper().validate(sheet, row, col, editText, callback);
	}
}
