/******************************************************************************
 * Product: Posterita Ajax UI 												  *
 * Copyright (C) 2007 Posterita Ltd.  All Rights Reserved.                    *
 * 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.                     *
 * For the text or an alternative of this public license, you may reach us    *
 * Posterita Ltd., 3, Draper Avenue, Quatre Bornes, Mauritius                 *
 * or via info@posterita.org or http://www.posterita.org/                     *
 *****************************************************************************/

package org.adempiere.webui.editor;

import java.beans.PropertyChangeEvent;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;

import org.adempiere.webui.ValuePreference;
import org.adempiere.webui.apps.AEnv;
import org.adempiere.webui.component.Searchbox;
import org.adempiere.webui.event.ContextMenuEvent;
import org.adempiere.webui.event.ContextMenuListener;
import org.adempiere.webui.event.ValueChangeEvent;
import org.adempiere.webui.event.ValueChangeListener;
import org.adempiere.webui.grid.WBPartner;
import org.adempiere.webui.panel.InfoBPartnerPanel;
import org.adempiere.webui.panel.InfoPanel;
import org.adempiere.webui.panel.InfoProductPanel;
import org.compiere.model.GridField;
import org.compiere.model.Lookup;
import org.compiere.model.MLookup;
import org.compiere.model.MLookupFactory;
import org.compiere.model.MRole;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.DisplayType;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;

/**
 * Search Editor for web UI.
 * Web UI port of search type VLookup
 *
 * @author Ashley G Ramdass
 *
 */
public class WSearchEditor extends WEditor implements ContextMenuListener, ValueChangeListener, IZoomableEditor
{
	private static final String[] LISTENER_EVENTS = {Events.ON_CLICK, Events.ON_CHANGE, Events.ON_OK};
	private Lookup 				lookup;
	private String				m_tableName = null;
	private String				m_keyColumnName = null;
	private String 				columnName;
	private WEditorPopupMenu	popupMenu;
    private Object              value;
    private InfoPanel			infoPanel = null;

	private static CLogger log = CLogger.getCLogger(WSearchEditor.class);

	public WSearchEditor (GridField gridField)
	{
		super(new Searchbox(), gridField);

		lookup = gridField.getLookup();
		
		if (lookup != null)
			columnName = lookup.getColumnName();
		
		init();
	}

	
    @Override
	public Searchbox getComponent() {
		return (Searchbox) super.getComponent();
	}
    
	@Override
	public boolean isReadWrite() {
		return getComponent().isEnabled();
	}


	@Override
	public void setReadWrite(boolean readWrite) {
		getComponent().setEnabled(readWrite);
	}


	/**
	 * Constructor for use if a grid field is unavailable
	 *
	 * @param lookup		Store of selectable data
	 * @param label			column name (not displayed)
	 * @param description	description of component
	 * @param mandatory		whether a selection must be made
	 * @param readonly		whether or not the editor is read only
	 * @param updateable	whether the editor contents can be changed
	 */
	public WSearchEditor (Lookup lookup, String label, String description, boolean mandatory, boolean readonly, boolean updateable)
	{
		super(new Searchbox(), label, description, mandatory, readonly, updateable);

		if (lookup == null)
		{
			throw new IllegalArgumentException("Lookup cannot be null");
		}

		this.lookup = lookup;
        columnName = lookup.getColumnName();
		super.setColumnName(columnName);
		init();
	}

	public WSearchEditor(String columnName, boolean mandatory, boolean readonly, boolean updateable,
    		Lookup lookup) 
	{
		super(new Searchbox(), null, null, mandatory, readonly, updateable);

		if (lookup == null)
		{
			throw new IllegalArgumentException("Lookup cannot be null");
		}

		this.lookup = lookup;
        this.columnName = columnName;
		super.setColumnName(columnName);
		init();
	}


	/**
     * initialise editor
     * @param columnName columnName
	 */
	private void init()
	{

		columnName = this.getColumnName();
                
		if (columnName.equals("C_BPartner_ID"))
		{
			popupMenu = new WEditorPopupMenu(true, true, true, true, true);
			getComponent().setButtonImage("/images/BPartner10.png");
		}
		else if (columnName.equals("M_Product_ID"))
		{
			popupMenu = new WEditorPopupMenu(true, true, true, false, false);
			getComponent().setButtonImage("/images/Product10.png");
		}
		else
		{
			popupMenu = new WEditorPopupMenu(true, true, true, false, false);
			getComponent().setButtonImage("/images/PickOpen10.png");
		}
		
		(getComponent().getTextbox()).setContext(popupMenu.getId());

		return;
	}

	public WEditorPopupMenu getPopupMenu()
	{
	   	return popupMenu;
	}

	@Override
	public void setValue(Object value)
	{
        this.value = value;
		if (value != null && !"".equals(String.valueOf(value)))
		{
		    String text = lookup.getDisplay(value);

            if (text.startsWith("_"))
            {
                text = text.substring(1);
            }

            getComponent().setText(text);
		}
		else
		{
			getComponent().setText("");
		}
	}

	@Override
	public Object getValue()
	{
		return value;
	}

	@Override
	public String getDisplay()
	{
		return getComponent().getText();
	}

	public void onEvent(Event e)
	{
		if (Events.ON_CHANGE.equals(e.getName()) || Events.ON_OK.equals(e.getName()))
		{
			if (infoPanel != null)
		 	{
				infoPanel.detach();
		 	 	infoPanel = null;
		 	}
			actionText(getComponent().getText());

		}
		else if (Events.ON_CLICK.equals(e.getName()))
		{
			if (infoPanel != null)
			{
				infoPanel.detach();
				infoPanel = null;
			}
			actionButton("");
		}
	}
	
	@Override
	public void propertyChange(PropertyChangeEvent evt)
	{
		if ("FieldValue".equals(evt.getPropertyName()))
		{
			if ( evt.getNewValue()== null)
			{
				actionRefresh("");
			}
			else
			{
				actionRefresh(evt.getNewValue());
			}
		}
	}

	private void actionRefresh(Object value)
	{
//		boolean mandatory = isMandatory();
//		AEnv.actionRefresh(lookup, value, mandatory);
    	setValue(value);
	}

	public void actionZoom()
	{
	   	AEnv.actionZoom(lookup, getValue());
	}
    private void actionZoom(Object value)
    {
        AEnv.actionZoom(lookup, value);
    }

	public void onMenu(ContextMenuEvent evt)
	{
		if (WEditorPopupMenu.REQUERY_EVENT.equals(evt.getContextEvent()))
		{
			actionRefresh(getValue());
		}
		else if (WEditorPopupMenu.ZOOM_EVENT.equals(evt.getContextEvent()))
		{
			actionZoom();
		}
		else if (WEditorPopupMenu.PREFERENCE_EVENT.equals(evt.getContextEvent()))
		{
			if (MRole.getDefault().isShowPreference())
				ValuePreference.start (this.getGridField(), getValue());
			return;
		}
		else if (WEditorPopupMenu.NEW_EVENT.equals(evt.getContextEvent()))
		{
			if (infoPanel != null)
			{
				infoPanel.detach();
				infoPanel = null;
			}
			actionBPartner(true);
		}
		// Elaine 2009/02/16 - update record
		else if (WEditorPopupMenu.UPDATE_EVENT.equals(evt.getContextEvent()))
		{
			if (infoPanel != null)
			{
				infoPanel.detach();
				infoPanel = null;
			}
			actionBPartner(false);
		}
		//
	}

	private void actionText(String text)
	{
		//	Nothing entered
		if (text == null || text.length() == 0 || text.equals("%"))
		{
			actionButton(text);
			return;
		}
		text = text.toUpperCase();
		log.config(getColumnName() + " - " + text);

		//	Exact first
		PreparedStatement pstmt = null;
		String finalSQL = Msg.parseTranslation(Env.getCtx(), getDirectAccessSQL(text));
		int id = -3;

		try
		{
			pstmt = DB.prepareStatement(finalSQL, null);
			ResultSet rs = pstmt.executeQuery();
			if (rs.next())
			{
				id = rs.getInt(1);		//	first
				if (rs.next())
					id = -1;			//	only if unique
			}
			rs.close();
			pstmt.close();
		}
		catch (Exception e)
		{
			log.log(Level.SEVERE, finalSQL, e);
			id = -2;
		}

		//	Try like
		if (id == -3 && !text.endsWith("%"))
		{
			text += "%";
			finalSQL = Msg.parseTranslation(Env.getCtx(), getDirectAccessSQL(text));

			try
			{
				pstmt = DB.prepareStatement(finalSQL, null);
				ResultSet rs = pstmt.executeQuery();
				if (rs.next())
				{
					id = rs.getInt(1);		//	first
					if (rs.next())
						id = -1;			//	only if unique
				}
				rs.close();
				pstmt.close();
			}
			catch (Exception e)
			{
				log.log(Level.SEVERE, finalSQL, e);
				id = -2;
			}
		}

		try
		{
			if (pstmt != null)
				pstmt.close();
		}
		catch (Exception e)
		{
		}

		//	No (unique) result
		if (id <= 0)
		{
			if (id == -3)
				log.fine(getColumnName() + " - Not Found - " + finalSQL);
			else
				log.fine(getColumnName() + " - Not Unique - " + finalSQL);

			//m_value = null;	// force re-display
			actionButton(getComponent().getText());
			return;
		}
		log.fine(getColumnName() + " - Unique ID=" + id);

		actionCombo(new Integer(id));          //  data binding
		//m_text.requestFocus();
	}	//	actionText


	private void actionCombo (Object value)
	{
		log.fine("Value=" + value);

		ValueChangeEvent evt = new ValueChangeEvent(this, this.getColumnName(), value, value);
		// -> ADTabpanel - valuechange
		fireValueChange(evt);
		
		//  is the value updated ?
		boolean updated = false;
		if (value == null && getValue() == null)
			updated = true;
		else if (value != null && value.equals(getValue()))
			updated = true;
		if (!updated)
		{
			setValue(value);
		}
	}	//	actionCombo

	/**
	 *	Action - Special BPartner Screen
	 *  @param newRecord true if new record should be created
	 */
	
	private void actionBPartner (boolean newRecord)
	{
		WBPartner vbp = new WBPartner (lookup.getWindowNo());
		int BPartner_ID = 0;
		
		//  if update, get current value
		if (!newRecord)
		{
			if (value instanceof Integer)
				BPartner_ID = ((Integer)value).intValue();
			else if (value != null)
				BPartner_ID = Integer.parseInt(value.toString());
		}

		vbp.loadBPartner (BPartner_ID);
		
		
		vbp.setVisible(true);
		AEnv.showWindow(vbp);
		
		//  get result
		int result = vbp.getC_BPartner_ID();
		
		if (result == 0					//	0 = not saved
			&& result == BPartner_ID)	//	the same
			return;
		
		//  Maybe new BPartner - put in cache
		lookup.getDirect(new Integer(result), false, true);
		setValue(new Integer(result));
		actionCombo (new Integer(result));      //  data binding
		
		//setValue(getValue());
	}	//	actionBPartner
	
	private void actionButton(String queryValue)
	{
		if (lookup == null)
			return;		//	leave button disabled
		
		/**
		 *  Three return options:
		 *  - Value Selected & OK pressed   => store result => result has value
		 *  - Cancel pressed                => store null   => result == null && cancelled
		 *  - Window closed                 -> ignore       => result == null && !cancalled
		 */

		Object result = null;			
		boolean cancelled = false;	

		String col = lookup.getColumnName();		//	fully qualified name

		if (col.indexOf('.') != -1)
			col = col.substring(col.indexOf('.')+1);

		//  Zoom / Validation
		String whereClause = getWhereClause();

		log.fine(col + ", Zoom=" + lookup.getZoom() + " (" + whereClause + ")");

		// boolean resetValue = false;	// Reset value so that is always treated as new entry

		if (col.equals("M_Product_ID"))
		{
			//	Reset
			Env.setContext(Env.getCtx(), lookup.getWindowNo(), Env.TAB_INFO, "M_Product_ID", "0");
			Env.setContext(Env.getCtx(), lookup.getWindowNo(), Env.TAB_INFO, "M_AttributeSetInstance_ID", "0");
			Env.setContext(Env.getCtx(), lookup.getWindowNo(), Env.TAB_INFO, "M_Lookup_ID", "0");

			//  Replace Value with name if no value exists
			if (queryValue.length() == 0 && getComponent().getText().length() > 0)
				queryValue = "@" + getComponent().getText() + "@";   //  Name indicator - otherwise Value

			int M_Warehouse_ID = Env.getContextAsInt(Env.getCtx(), lookup.getWindowNo(), "M_Warehouse_ID");
			int M_PriceList_ID = Env.getContextAsInt(Env.getCtx(), lookup.getWindowNo(), "M_PriceList_ID");

			//	Show Info
			InfoProductPanel ip = new InfoProductPanel (lookup.getWindowNo(),
					M_Warehouse_ID, M_PriceList_ID, false,queryValue, whereClause);

			ip.setVisible(true);
			ip.setTitle("Product Info");
			ip.setStyle("border: 2px");
			ip.setClosable(true);
			ip.setAttribute("mode", "modal");
			ip.addValueChangeListener(this);
			infoPanel = ip;
			AEnv.showWindow(ip);
			
			cancelled = ip.isCancelled();
			result = ip.getSelectedKey();
		}
		else if (col.equals("C_BPartner_ID"))
		{
			//  Replace Value with name if no value exists
			if (queryValue.length() == 0 && getComponent().getText().length() > 0)
				queryValue = getComponent().getText();

			boolean isSOTrx = true;     //  default

			if (Env.getContext(Env.getCtx(), lookup.getWindowNo(), "IsSOTrx").equals("N"))
				isSOTrx = false;

			InfoBPartnerPanel ip = new InfoBPartnerPanel(queryValue, lookup.getWindowNo(), isSOTrx,false, whereClause);

			ip.setVisible(true);
			ip.setTitle("Business Partner Info");
			ip.setStyle("border: 2px");
			ip.setClosable(true);
			ip.setAttribute("mode", "modal");
			ip.addValueChangeListener(this);
			infoPanel = ip;
			AEnv.showWindow(ip);

			cancelled = ip.isCancelled();
			result = ip.getSelectedKey();
		}
		else	//	General Info
		{
			if (m_tableName == null)	//	sets table name & key column
				getDirectAccessSQL("*");

            if (queryValue.length() == 0 && getComponent().getText().length() > 0)
                queryValue = getComponent().getText();

			InfoPanel ig = InfoPanel.create(lookup.getWindowNo(), m_tableName,m_keyColumnName,queryValue, false, whereClause);
			ig.setVisible(true);
			ig.setStyle("border: 2px");
			ig.setClosable(true);
			ig.setAttribute("mode", "modal");
			ig.addValueChangeListener(this);
			infoPanel = ig;
			AEnv.showWindow(ig);

			cancelled = ig.isCancelled();
			result = ig.getSelectedKey();

		}

		infoPanel = null;
		//  Result
		if (result != null)
		{
			//ensure data binding happen
			actionCombo (result);	//	data binding
		}
		else if (cancelled)
		{
			log.config(getColumnName() + " - Result = null (cancelled)");
			actionCombo(null);
		}
		else
		{
			log.config(getColumnName() + " - Result = null (not cancelled)");
		}
		
	}

	/**
	 * 	Generate Access SQL for Search.
	 * 	The SQL returns the ID of the value entered
	 * 	Also sets m_tableName and m_keyColumnName
	 *	@param text uppercase text for LIKE comparison
	 *	@return sql or ""
	 *  Example
	 *	SELECT C_Payment_ID FROM C_Payment WHERE UPPER(DocumentNo) LIKE x OR ...
	 */
	private String getDirectAccessSQL (String text)
	{
		String m_columnName = getColumnName();
		
		StringBuffer sql = new StringBuffer();
		m_tableName = m_columnName.substring(0, m_columnName.length()-3);
		m_keyColumnName = m_columnName;

		if (m_columnName.equals("M_Product_ID"))
		{
			//	Reset
			Env.setContext(Env.getCtx(), lookup.getWindowNo(), Env.TAB_INFO, "M_Product_ID", "0");
			Env.setContext(Env.getCtx(), lookup.getWindowNo(), Env.TAB_INFO, "M_AttributeSetInstance_ID", "0");
			Env.setContext(Env.getCtx(), lookup.getWindowNo(), Env.TAB_INFO, "M_Locator_ID", "0");

			sql.append("SELECT M_Product_ID FROM M_Product WHERE (UPPER(Value) LIKE ")
				.append(DB.TO_STRING(text))
				.append(" OR UPPER(Name) LIKE ").append(DB.TO_STRING(text))
				.append(" OR UPC LIKE ").append(DB.TO_STRING(text)).append(")");
		}
		else if (m_columnName.equals("C_BPartner_ID"))
		{
			sql.append("SELECT C_BPartner_ID FROM C_BPartner WHERE (UPPER(Value) LIKE ")
				.append(DB.TO_STRING(text))
				.append(" OR UPPER(Name) LIKE ").append(DB.TO_STRING(text)).append(")");
		}
		else if (m_columnName.equals("C_Order_ID"))
		{
			sql.append("SELECT C_Order_ID FROM C_Order WHERE UPPER(DocumentNo) LIKE ")
				.append(DB.TO_STRING(text));
		}
		else if (m_columnName.equals("C_Invoice_ID"))
		{
			sql.append("SELECT C_Invoice_ID FROM C_Invoice WHERE UPPER(DocumentNo) LIKE ")
				.append(DB.TO_STRING(text));
		}
		else if (m_columnName.equals("M_InOut_ID"))
		{
			sql.append("SELECT M_InOut_ID FROM M_InOut WHERE UPPER(DocumentNo) LIKE ")
				.append(DB.TO_STRING(text));
		}
		else if (m_columnName.equals("C_Payment_ID"))
		{
			sql.append("SELECT C_Payment_ID FROM C_Payment WHERE UPPER(DocumentNo) LIKE ")
				.append(DB.TO_STRING(text));
		}
		else if (m_columnName.equals("GL_JournalBatch_ID"))
		{
			sql.append("SELECT GL_JournalBatch_ID FROM GL_JournalBatch WHERE UPPER(DocumentNo) LIKE ")
				.append(DB.TO_STRING(text));
		}
		else if (m_columnName.equals("SalesRep_ID"))
		{
			sql.append("SELECT AD_User_ID FROM AD_User WHERE UPPER(Name) LIKE ")
				.append(DB.TO_STRING(text));
			
			m_tableName = "AD_User";
			m_keyColumnName = "AD_User_ID";
		}
		
		//	Predefined
		
		if (sql.length() > 0)
		{
			String wc = getWhereClause();
			
			if (wc != null && wc.length() > 0)
				sql.append(" AND ").append(wc);
			
			sql.append(" AND IsActive='Y'");
			//	***
			
			log.finest(m_columnName + " (predefined) " + sql.toString());
			
			return MRole.getDefault().addAccessSQL(sql.toString(),
				m_tableName, MRole.SQL_NOTQUALIFIED, MRole.SQL_RO);
		}
		
		//	Check if it is a Table Reference
		
		if (lookup != null && lookup instanceof MLookup)
		{
			int AD_Reference_ID = ((MLookup)lookup).getAD_Reference_Value_ID();
		
			if (AD_Reference_ID != 0)
			{
				String query = "SELECT kc.ColumnName, dc.ColumnName, t.TableName "
					+ "FROM AD_Ref_Table rt"
					+ " INNER JOIN AD_Column kc ON (rt.AD_Key=kc.AD_Column_ID)"
					+ " INNER JOIN AD_Column dc ON (rt.AD_Display=dc.AD_Column_ID)"
					+ " INNER JOIN AD_Table t ON (rt.AD_Table_ID=t.AD_Table_ID) "
					+ "WHERE rt.AD_Reference_ID=?";
				
				String displayColumnName = null;
				PreparedStatement pstmt = null;
				
				try
				{
					pstmt = DB.prepareStatement(query, null);
					pstmt.setInt(1, AD_Reference_ID);
					ResultSet rs = pstmt.executeQuery();
				
					if (rs.next())
					{
						m_keyColumnName = rs.getString(1);
						displayColumnName = rs.getString(2);
						m_tableName = rs.getString(3);
					}
					rs.close();
					pstmt.close();
					pstmt = null;
				}
				catch (Exception e)
				{
					log.log(Level.SEVERE, query, e);
				}
				
				try
				{
					if (pstmt != null)
						pstmt.close();
				
					pstmt = null;
				}
				catch (Exception e)
				{
					pstmt = null;
				}
				
				if (displayColumnName != null)
				{
					sql = new StringBuffer();
					sql.append("SELECT ").append(m_keyColumnName)
						.append(" FROM ").append(m_tableName)
						.append(" WHERE UPPER(").append(displayColumnName)
						.append(") LIKE ").append(DB.TO_STRING(text))
						.append(" AND IsActive='Y'");
				
					String wc = getWhereClause();
					
					if (wc != null && wc.length() > 0)
						sql.append(" AND ").append(wc);
					
					//	***
					
					log.finest(m_columnName + " (Table) " + sql.toString());
					
					return MRole.getDefault().addAccessSQL(sql.toString(),
								m_tableName, MRole.SQL_NOTQUALIFIED, MRole.SQL_RO);
				}
			} // Table Reference
		} // MLookup
		
		/** Check Well Known Columns of Table - assumes TableDir	**/
		
		String query = "SELECT t.TableName, c.ColumnName "
			+ "FROM AD_Column c "
			+ " INNER JOIN AD_Table t ON (c.AD_Table_ID=t.AD_Table_ID AND t.IsView='N') "
			+ "WHERE (c.ColumnName IN ('DocumentNo', 'Value', 'Name') OR c.IsIdentifier='Y')"
			+ " AND c.AD_Reference_ID IN (10,14)"
			+ " AND EXISTS (SELECT * FROM AD_Column cc WHERE cc.AD_Table_ID=t.AD_Table_ID"
				+ " AND cc.IsKey='Y' AND cc.ColumnName=?)";
		
		m_keyColumnName = m_columnName;
		sql = new StringBuffer();
		PreparedStatement pstmt = null;
		
		try
		{
			pstmt = DB.prepareStatement(query, null);
			pstmt.setString(1, m_keyColumnName);
			ResultSet rs = pstmt.executeQuery();
		
			while (rs.next())
			{
				if (sql.length() != 0)
					sql.append(" OR ");
			
				m_tableName = rs.getString(1);
				sql.append("UPPER(").append(rs.getString(2)).append(") LIKE ").append(DB.TO_STRING(text));
			}
			
			rs.close();
			pstmt.close();
			pstmt = null;
		}
		catch (SQLException ex)
		{
			log.log(Level.SEVERE, query, ex);
		}
		
		try
		{
			if (pstmt != null)
				pstmt.close();
		}
		catch (SQLException ex1)
		{
		}
		pstmt = null;
		//
		if (sql.length() == 0)
		{
			log.log(Level.SEVERE, m_columnName + " (TableDir) - no standard/identifier columns");
			return "";
		}
		//
		StringBuffer retValue = new StringBuffer ("SELECT ")
			.append(m_columnName).append(" FROM ").append(m_tableName)
			.append(" WHERE ").append(sql)
			.append(" AND IsActive='Y'");
		
		String wc = getWhereClause();
		
		if (wc != null && wc.length() > 0)
			retValue.append(" AND ").append(wc);
		//	***
		log.finest(m_columnName + " (TableDir) " + sql.toString());
		return MRole.getDefault().addAccessSQL(retValue.toString(),
					m_tableName, MRole.SQL_NOTQUALIFIED, MRole.SQL_RO);
	}
	
	private String getWhereClause()
	{
		String whereClause = "";

		if (lookup == null)
			return "";

		if (lookup.getZoomQuery() != null)
			whereClause = lookup.getZoomQuery().getWhereClause();

		String validation = lookup.getValidation();

		if (validation == null)
			validation = "";

		if (whereClause.length() == 0)
			whereClause = validation;
		else if (validation.length() > 0)
			whereClause += " AND " + validation;

		//	log.finest("ZoomQuery=" + (lookup.getZoomQuery()==null ? "" : lookup.getZoomQuery().getWhereClause())
	//		+ ", Validation=" + lookup.getValidation());

		if (whereClause.indexOf('@') != -1)
		{
			String validated = Env.parseContext(Env.getCtx(), lookup.getWindowNo(), whereClause, false);

			if (validated.length() == 0)
				log.severe(getColumnName() + " - Cannot Parse=" + whereClause);
			else
			{
				log.fine(getColumnName() + " - Parsed: " + validated);
				return validated;
			}
		}
		return whereClause;
	}	//	getWhereClause


	public String[] getEvents()
    {
        return LISTENER_EVENTS;
    }

	public void valueChange(ValueChangeEvent evt)
	{
        if ("zoom".equals(evt.getPropertyName()))
        {
            actionZoom(evt.getNewValue());
        }
        else
        {
        	if (evt.getNewValue() != null)
			{
				actionCombo(evt.getNewValue());
			}
        }

	}

	/**
	 * @param windowNo
	 * @return WSearchEditor
	 */
	public static WSearchEditor createBPartner(int windowNo) {
		int AD_Column_ID = 3499;    //  C_Invoice.C_BPartner_ID
		try
		{
			Lookup lookup = MLookupFactory.get (Env.getCtx(), windowNo, 
				0, AD_Column_ID, DisplayType.Search);
			return new WSearchEditor ("C_BPartner_ID", false, false, true, lookup);
		}
		catch (Exception e)
		{
			log.log(Level.SEVERE, "", e);
		}
		return null;
	}

	/**
	 * @param windowNo
	 * @return WSearchEditor 
	 */
	public static WSearchEditor createProduct(int windowNo) {
		int AD_Column_ID = 3840;    //  C_InvoiceLine.M_Product_ID
		try
		{
			Lookup lookup = MLookupFactory.get (Env.getCtx(), windowNo, 0, 
				AD_Column_ID, DisplayType.Search);
			return new WSearchEditor("M_Product_ID", false, false, true, lookup);
		}
		catch (Exception e)
		{
			log.log(Level.SEVERE, "", e);
		}
		return null;
	}
}
