/* DefaultWidgetHandler.java

	Purpose:
		
	Description:
		
	History:
		Apr 21, 2008 2:40:58 PM     2008, Created by Dennis.Chen

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

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;





//import org.zkoss.poi.ss.util.AreaReference;
//import org.zkoss.poi.ss.util.CellReference;
import org.zkoss.zss.api.AreaRef;
import org.zkoss.zss.model.SSheet;
import org.zkoss.zss.ui.Spreadsheet;
import org.zkoss.zss.ui.Widget;
import org.zkoss.zss.ui.sys.SpreadsheetCtrl;
import org.zkoss.zss.ui.sys.WidgetHandler;
import org.zkoss.zssex.ui.au.out.AuRedrawWidget;

/**
 * @author Dennis.Chen
 *
 */
public class DefaultWidgetHandler implements WidgetHandler, Serializable {
	
	private static final long serialVersionUID = 1L;
	private Spreadsheet _spreadsheet;
	private List<WidgetCtrl> _clientWidgets = new ArrayList<WidgetCtrl>(); 
	private List<WidgetCtrl> _nonClientWidgets = new ArrayList<WidgetCtrl>();
	private Ghost _ghost;
	
	private static String WIDGET_RES_PREFIX = "zsw_";

	public boolean addWidget(Widget widget) {
		if(!(widget instanceof BaseWidget)){
			//throw or just return false?;
			//throw new UiException("Current Implementation cannot handle "+widget.getClass());
			return false;
		}
		
		if (_ghost == null) {
			_ghost = newGhost();
			_spreadsheet.appendChild(_ghost);
		}
		WidgetCtrl ctrl = ((BaseWidget)widget).getCtrl();

		boolean r = _ghost.appendChild(ctrl);
		
		if (r) {
			//TODO: Peter, is this the line cause the problem?
			//why? Does widget support container component like window?
			//20131030, hawkchen@potix.com, ZSS-496: call invalidate() to avoid appending redundant ImageWidget s
			//Dennis : Doesn't need to invalidate after fix of ZSS-491
//			_ghost.invalidate();// invalidate ghost, so ZK addChd will not fire, then i can control the behavior
			
			((BaseWidget) widget).setHandler0(this);

			_nonClientWidgets.add(ctrl);

			//ZSS-112: spreadsheet may invalidated when add widget 
			if (!_spreadsheet.isInvalidated()) {
				SSheet sheet = _spreadsheet.getSelectedSSheet();
				AreaRef rect = ((SpreadsheetCtrl) _spreadsheet.getExtraCtrl()).getVisibleArea();
				onLoadWidgetOnDemand((BaseWidget)widget, sheet, rect.getColumn(), rect.getRow(), rect.getLastColumn(), rect.getLastRow());	
			}
		}

		return r;
	}

	/**
	 * use {@link #updateWidget(SSheet, String)}
	 */
	@Deprecated
	public void updateWidgets(SSheet sheet, int left, int top, int right, int bottom) {
//		for(WidgetCtrl ctrl : _clientWidgets) {
//			Widget widget = ctrl.getWidget();
//			if (widget instanceof ChartWidget) {
//				updateChartWidget((ChartWidget)widget, sheet, left, top, right, bottom);
//			}
//		}
	}
	
	public void updateWidget(SSheet sheet, String widgetId) {
		for(WidgetCtrl ctrl : _clientWidgets) {
			Widget widget = ctrl.getWidget();
			if (widget.getId().equals(widgetId)) {
				if(widget instanceof BaseWidget){
					((BaseWidget)widget).invalidate();
				}
			}
		}
	}

	public Spreadsheet getSpreadsheet() {
		return _spreadsheet;
	}

	public boolean removeWidget(Widget widget) {
		if (!(widget instanceof BaseWidget)) {
			return false;
		}
		if (((BaseWidget) widget).getHandler() != this) {
			return false;
		}
		WidgetCtrl ctrl = ((BaseWidget) widget).getCtrl();
		if (_ghost == null) {
			_ghost = newGhost();
			_spreadsheet.appendChild(_ghost);
		}
		boolean r = _ghost.removeChild(ctrl);
		if (r) {
			//_ghost.invalidate();// invalidate ghost, so ZK addChd will not fire, then i can control the behavior
			((BaseWidget) widget).setHandler0(null);
			((BaseWidget) widget).setInClient(false);
			_clientWidgets.remove(ctrl);
			_nonClientWidgets.remove(ctrl);
			//Sheet sheet = _spreadsheet.getSelectedSheet();
		}
		return r;
	}

	public void init(Spreadsheet spreadsheet) {
		this._spreadsheet = spreadsheet;
	}

	public void onLoadOnDemand(SSheet sheet,int left,int top,int right,int bottom) {
		if (_ghost == null)
			return;

		int size = _nonClientWidgets.size();
		for (int i = size - 1; i >= 0; i--) {
			WidgetCtrl ctrl = (WidgetCtrl) _nonClientWidgets.get(i);
			BaseWidget widget = ctrl.getWidget();
			onLoadWidgetOnDemand(widget, sheet, left, top, right, bottom);
		}
	}
	
	private boolean onLoadWidgetOnDemand(BaseWidget widget, SSheet sheet, int left, int top, int right, int bottom) {
		final int r = widget.getRow();
		final int c = widget.getColumn();
		final int r2 = widget.getRow2();
		final int c2 = widget.getColumn2();
		final WidgetCtrl ctrl = widget.getCtrl(); 
		//final String uuid = ctrl.getUuid();
		if (r2 >= top && r <= bottom && c2 >= left && c <= right) {
			redrawWidget(sheet.getId(), widget);
			if (!widget.isInClient()) {
				widget.setInClient(true);
				_clientWidgets.add(ctrl);
				_nonClientWidgets.remove(ctrl);
			}
			return true;
		}
		return false;
	}

	private void redrawWidget(String sheetid, BaseWidget widget) {
		WidgetCtrl ctrl = widget.getCtrl();
		String uuid = ctrl.getUuid();
		_spreadsheet.response(WIDGET_RES_PREFIX + uuid, new AuRedrawWidget(_spreadsheet, sheetid, uuid));
	}
	
//	class DefferedRender implements DeferredValue{
//
//		WidgetCtrl _ctrl;
//		DefferedRender(WidgetCtrl ctrl){
//			_ctrl = ctrl;
//		}
//		
//		public String getValue() {
//			StringWriter sw = new StringWriter();
//			try {
//				 _ctrl.redraw(sw);
//			} catch (IOException e) {
//				throw new UiException(e);
//			}
//			return sw.toString();
//		}
//	}

	public void invaliate() {
		
		Iterator iter = _clientWidgets.iterator();
		WidgetCtrl ctrl;
		while(iter.hasNext()){
			ctrl = (WidgetCtrl)iter.next();
			ctrl.getWidget().setInClient(false);
			_nonClientWidgets.add(ctrl);
		}
		_clientWidgets.clear();
	}
	private Ghost newGhost() {
		Ghost ghost = new Ghost();
		ghost.setAttribute(SpreadsheetCtrl.CHILD_PASSING_KEY, "");
		return ghost;
	}
}