/******************************************************************************
 * Product: iDempiere ERP & CRM Smart Business Solution                       *
 * Copyright (C) 2014 T.G.I.                                                  *
 * This program is free software; you can redistribute it and/or modify it    *
 * under the terms version 2 of the GNU General Public License as published   *
 * by the Free Software Foundation. This program is distributed in the hope   *
 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.           *
 * See the GNU General Public License for more details.                       *
 * You should have received a copy of the GNU General Public License along    *
 * with this program; if not, write to the Free Software Foundation, Inc.,    *
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.                     *
 *****************************************************************************/

package org.adempiere.webui.session;

import java.util.logging.Level;

import org.compiere.util.CLogger;
import org.compiere.util.Env;
import org.zkoss.zk.au.AuRequest;
import org.zkoss.zk.au.AuService;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.ext.Disable;
import org.zkoss.zk.ui.ext.Readonly;
import org.zkoss.zul.Button;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.impl.InputElement;


/**
 * Zk desktop listener to deny request to modify a readonly field or perform action using a readonly button.  
 * @author hieplq
 *
 */
public class ValidateReadonlyComponent implements AuService {
	private static final CLogger	log = CLogger.getCLogger (ValidateReadonlyComponent.class);
	/**
	 * throw WrongValueException when denied request, other false 
	 */
	@Override
	public boolean service(AuRequest request, boolean everError) {
		String cmd = request.getCommand();
		
		// event is reason change value of component
		boolean considerEvent = Events.ON_CHANGE.equals(cmd) || Events.ON_CHECK.equals(cmd) || 
								Events.ON_SELECT.equals(cmd) ||
								Events.ON_CLICK.equals(cmd) || Events.ON_DOUBLE_CLICK.equals(cmd) || Events.ON_OK.equals(cmd) || Events.ON_UPLOAD.equals(cmd); 
		
		if (!considerEvent){
			return false; // don't denied
		}
		
		Component comp = request.getComponent();
		
		// get necessary interface
		Disable iDisable = null;
		Readonly iReadonly = null;
		
		if (comp instanceof Disable){
			iDisable = (Disable)comp;
		}
		
		if (comp instanceof Readonly){
			iReadonly = (Readonly)comp;
		}
		
		boolean isCannotEdit = (iDisable != null && iDisable.isDisabled()) || (iReadonly != null && iReadonly.isReadonly());
		
		// don't care editable component
		if (!isCannotEdit){
			return false;
		}
		
		// detect kind of component raise event
		InputElement inputComp = null;
		Checkbox checkbox = null;
		Combobox comb = null;
		Button button = null;
		
		if (comp instanceof Combobox) {// have to check before InputElement
			comb = (Combobox)comp;
		} else if (comp instanceof InputElement) {
			inputComp = (InputElement)comp;// textbox, datebox, numberbox,...
		} else if (comp instanceof Checkbox) {
			checkbox = (Checkbox)comp;
		} else if (comp instanceof Button) {// have to check latest
			button = (Button)comp;
		} else {//HtmlBasedComponent
			log.log(Level.SEVERE, String.format("Consider to denied event of control %1$s when it's readonly on event %2$s", comp.getClass(), cmd));
			return false;// just log to investigate don't lock process
		}
			
		
		if (isCannotEdit){
			boolean editing = (inputComp != null && Events.ON_CHANGE.equals(cmd)) || 
								(checkbox != null && Events.ON_CHECK.equals(cmd)) ||
								(comb != null && (Events.ON_CHANGE.equals(cmd) || Events.ON_SELECT.equals(cmd))) ||
								(button != null && (Events.ON_CLICK.equals(cmd) || Events.ON_OK.equals(cmd) || Events.ON_UPLOAD.equals(cmd)));;
			
			// for combobox each change have both event onchange and onselect
			if (editing){
				comp.invalidate();
				String user = Env.getContext(Env.getCtx(), Env.AD_USER_NAME) + "[" + Env.getContext(Env.getCtx(), Env.AD_USER_ID) + "]";
				log.log(Level.WARNING, String.format("Detected UI interaction with a read-only element: %1$s on event %2$s from user %3$s",
						comp.getClass(), cmd, user));
				return true;
			}
		}
        
		return false;
	}

}