/******************************************************************************
 * Product: Compiere ERP & CRM Smart Business Solution                        *
 * Copyright (C) 1999-2007 ComPiere, Inc. 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    *
 * ComPiere, Inc., 3600 Bridge Parkway #102, Redwood City, CA 94065, USA      *
 * or via info@compiere.org or http://www.compiere.org/license.html           *
 *****************************************************************************/
package org.compiere.grid.ed;

import java.awt.*;
import java.awt.event.*;
import java.util.logging.*;
import javax.swing.*;
import javax.swing.border.*;
import org.compiere.apps.*;
import org.compiere.model.*;
import org.compiere.swing.*;
import org.compiere.util.*;

/**
 *  Maintain Value Preferences.
 *  To delete a preference, select a null value and save.
 *
 *  @author Jorg Janke
 *  @version  $Id: ValuePreference.java,v 1.1 2008/01/16 07:43:00 jrmt Exp $
 */
public class ValuePreference extends CDialog
	implements ActionListener
{
	/**
	 *  Factory
	 *  @param mField	field
	 *  @param aValue	value
	 *  @return ValuePreference or null
	 */
	public static ValuePreference start (GridField mField, Object aValue)
	{
		return start (mField, aValue, null);
	}   //  start

	/**
	 *  Factory
	 *  @param mField	field
	 *  @param aValue	value
	 *  @param aDisplayValue	display value
	 *  @return ValuePreference or null
	 */
	public static ValuePreference start (GridField mField, Object aValue, String aDisplayValue)
	{
		if (!mField.isEditable(false))
		{
			log.info("Field not editable (R/O)");
			return null;
		}
		
		//  Set Value/DisplayValue
		String Value = null;
		String DisplayValue = null;
		if (aValue != null)
		{
			Value = aValue.toString();
			if (aValue instanceof Boolean)
				Value = ((Boolean)aValue) ? "Y" : "N";
			DisplayValue = (aDisplayValue == null) ? Value : aDisplayValue;
		}

		//  Get from mField
		//  AD_Window_ID, DisplayAttribute, Attribute, DisplayType, AD_Referenece_ID
		int AD_Window_ID = mField.getAD_Window_ID();
		String Attribute = mField.getColumnName();
		String DisplayAttribute = mField.getHeader();
		int displayType = mField.getDisplayType();
		int AD_Reference_ID = 0;
		int WindowNo = mField.getWindowNo();
		
		if ("Value".equals(Attribute) || "DocumentNo".equals(Attribute))
		{
			log.info("No Preference for: " + Attribute);
			return null;
		}

		//  Get from Environment (WindowNo)
		//  AD_Client_ID, AD_Org_ID, AD_User_ID, Frame
		int AD_Client_ID = Env.getCtx().getAD_Client_ID();
		int AD_Org_ID = Env.getCtx().getContextAsInt( WindowNo, "AD_Org_ID");
		int AD_User_ID = Env.getCtx().getAD_User_ID();
		Frame frame = Env.getWindow(WindowNo);

		//  Create Editor
		ValuePreference vp = new ValuePreference (frame, WindowNo,
			AD_Client_ID, AD_Org_ID, AD_User_ID, AD_Window_ID,
			Attribute, DisplayAttribute, Value, DisplayValue,
			displayType, AD_Reference_ID);
		return vp;
	}   //  create

	/**
	 *  Create the popup menu item to start the ValuePreference editor.
	 *  <code>
	 *  .. add method
	 *  public void setField (MField mField)
	 *  {
	 *      m_mField = mField;
	 *      if (m_mField != null)
	 *          ValuePreference.addMenu (this, m_popupMenu);
	 *	}   //  setField
	 *
	 *  .. in actionPerformed add ..
	 *  if (e.getActionCommand().equals(ValuePreference.NAME))
	 *  {
	 *      ValuePreference.start (m_mField, getValue(), DisplayValue);
	 *      return;
	 *  }
	 *  </code>
	 *  @param l listener
	 *  @param popupMenu menu
	 *  @return JMenuItem
	 */
	public static CMenuItem addMenu (ActionListener l, JPopupMenu popupMenu)
	{
		CMenuItem mi = new CMenuItem (Msg.getMsg(Env.getCtx(), NAME), s_icon);
		mi.setActionCommand(NAME);
		mi.addActionListener(l);
		popupMenu.add(mi);
		return mi;
	}   //  addMenu

	/** The Name of the Editor      */
	public static final String      NAME = "ValuePreference";
	/** The Menu Icon               */
	private static Icon             s_icon = new ImageIcon(org.compiere.Compiere.class.getResource("images/VPreference16.gif"));
	/**	Logger			*/
	private static CLogger log = CLogger.getCLogger(ValuePreference.class);
	
	/**
	 *  Constructor
	 *
	 *  @param frame parent
	 *  @param WindowNo window no
	 *  @param AD_Client_ID client
	 *  @param AD_Org_ID org
	 *  @param AD_User_ID user
	 *  @param AD_Window_ID window id
	 *  @param Attribute attribute
	 *  @param DisplayAttribute attribute display
	 *  @param Value value
	 *  @param DisplayValue value display
	 *  @param displayType display type
	 *  @param AD_Reference_ID reference
	 */
	public ValuePreference (Frame frame, int WindowNo,
		int AD_Client_ID, int AD_Org_ID, int AD_User_ID, int AD_Window_ID,
		String Attribute, String DisplayAttribute, String Value, String DisplayValue,
		int displayType, int AD_Reference_ID)
	{
		super(frame, Msg.getMsg(Env.getCtx(), NAME) + " " + DisplayAttribute, true);
		log.config("WindowNo=" + WindowNo
			+ ", Client_ID=" + AD_Client_ID + ", Org_ID=" + AD_Org_ID + ", User_ID=" + AD_User_ID + ", Window_ID=" + AD_Window_ID
			+ ",  Attribute=" + Attribute + "/" + DisplayAttribute + ",  Value=" + Value + "/" + DisplayValue
			+ ",  DisplayType=" + displayType + ", Reference_ID=" + AD_Reference_ID);
		m_ctx = Env.getCtx();
		m_WindowNo = WindowNo;
		m_AD_Client_ID = AD_Client_ID;
		m_AD_Org_ID = AD_Org_ID;
		m_AD_User_ID = AD_User_ID;
		m_AD_Window_ID = AD_Window_ID;
		m_Attribute = Attribute;
		m_DisplayAttribute = DisplayAttribute;
		m_Value = Value;
		m_DisplayValue = DisplayValue;
		m_DisplayType = displayType;
		//
		m_role = MRole.getDefault();
		try
		{
			jbInit();
			dynInit();
		}
		catch(Exception ex)
		{
			log.log(Level.SEVERE, "", ex);
		}
		AEnv.showCenterScreen(this);
	}   //  ValuePreference

	private Ctx				m_ctx;
	private int             m_WindowNo;
	private int             m_AD_Client_ID;
	private int             m_AD_Org_ID;
	private int             m_AD_User_ID;
	private int             m_AD_Window_ID;
	private String          m_Attribute;
	private String          m_DisplayAttribute;
	private String          m_Value;
	private String          m_DisplayValue;
	private int             m_DisplayType;
	private MRole			m_role;

	//  Display
	private CPanel setPanel = new CPanel();
	private GridBagLayout setLayout = new GridBagLayout();
	private CLabel lAttribute = new CLabel();
	private CTextField fAttribute = new CTextField();
	private CLabel lAttributeValue = new CLabel();
	private CLabel lValue = new CLabel();
	private CLabel lValueValue = new CLabel();
	private CTextField fValue = new CTextField();
	private CLabel lSetFor = new CLabel();
	private VCheckBox cbClient = new VCheckBox();
	private VCheckBox cbOrg = new VCheckBox();
	private VCheckBox cbUser = new VCheckBox();
	private VCheckBox cbWindow = new VCheckBox();
	private CLabel lExplanation = new CLabel();
	private CPanel currentPanel = new CPanel();
	private TitledBorder titledBorder;
	private JScrollPane scrollPane = new JScrollPane();
	private BorderLayout currentLayout = new BorderLayout();
	private JTable table = new JTable();

	private ConfirmPanel confirmPanel = new ConfirmPanel(true);
	private JButton bDelete;

	/**
	 *  Static Layout
	 *  @throws Exception
	 */
	void jbInit() throws Exception
	{
		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		titledBorder = new TitledBorder(BorderFactory.createEtchedBorder(Color.white,new Color(148, 145, 140)),
			Msg.getMsg(m_ctx, "CurrentSettings"));
		//
		lAttribute.setText(Msg.translate(m_ctx, "Attribute"));
		lValue.setText(Msg.translate(m_ctx, "Value"));
		lSetFor.setText(Msg.getMsg(m_ctx, "ValuePreferenceSetFor"));
		cbClient.setText(Msg.translate(m_ctx, "AD_Client_ID"));
		cbOrg.setText(Msg.translate(m_ctx, "AD_Org_ID"));
		cbUser.setText(Msg.translate(m_ctx, "AD_User_ID"));
		cbUser.setSelected(true);
		cbWindow.setText(Msg.translate(m_ctx, "AD_Window_ID"));
		cbWindow.setSelected(true);
		//
		setPanel.setLayout(setLayout);
		fAttribute.setEditable(false);
		fValue.setEditable(false);
		this.getContentPane().add(setPanel,  BorderLayout.NORTH);
		setPanel.add(lAttribute,     new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
			,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		setPanel.add(fAttribute,       new GridBagConstraints(1, 0, 4, 1, 0.0, 0.0
			,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
		setPanel.add(lValue,     new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
			,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		setPanel.add(fValue,     new GridBagConstraints(1, 1, 4, 1, 0.0, 0.0
			,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
		setPanel.add(lSetFor,    new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
			,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		setPanel.add(cbClient,      new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
			,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		setPanel.add(cbOrg,    new GridBagConstraints(2, 2, 1, 1, 0.0, 0.0
			,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		setPanel.add(cbUser,   new GridBagConstraints(3, 2, 1, 1, 0.0, 0.0
			,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		setPanel.add(cbWindow,   new GridBagConstraints(4, 2, 1, 1, 0.0, 0.0
			,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		setPanel.add(lAttributeValue,  new GridBagConstraints(5, 0, 1, 1, 0.0, 0.0
			,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
		setPanel.add(lValueValue,  new GridBagConstraints(5, 1, 1, 1, 0.0, 0.0
			,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
		setPanel.add(lExplanation,  new GridBagConstraints(1, 3, 4, 1, 0.0, 0.0
			,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		//
		currentPanel.setBorder(titledBorder);
		currentPanel.setLayout(currentLayout);
	//	this.getContentPane().add(currentPanel, BorderLayout.CENTER);
		currentPanel.add(scrollPane,  BorderLayout.CENTER);
		scrollPane.getViewport().add(table, null);
		this.getContentPane().add(confirmPanel, BorderLayout.SOUTH);
	}   //  jbInit

	/**
	 *  Dynamic Init
	 */
	private void dynInit()
	{
		//  Set Attribute/Value
		fAttribute.setText(m_DisplayAttribute);
		lAttributeValue.setText(m_Attribute);
		fValue.setText(m_DisplayValue);
		lValueValue.setText(m_Value);
		if (CLogMgt.isLevelFine())
		{
			lAttributeValue.setVisible(false);
			lValueValue.setVisible(false);
		}

		//  ActionListener
		cbClient.setEnabled(false);
		cbClient.setSelected(true);
	//	cbClient.addActionListener(this);
		
		//	Can Change Org
		if (MRole.PREFERENCETYPE_Client.equals(m_role.getPreferenceType()))
			cbOrg.addActionListener(this);
		else
		{
			cbOrg.setEnabled(false);
			cbOrg.setSelected(true);
		}
		
		//	Can Change User
		if (MRole.PREFERENCETYPE_Client.equals(m_role.getPreferenceType())
			|| MRole.PREFERENCETYPE_Organization.equals(m_role.getPreferenceType()))
			cbUser.addActionListener(this);
		else
		{
			cbUser.setEnabled(false);
			cbUser.setSelected(true);
		}
		//	Can change all/specific
		cbWindow.addActionListener(this);

		//  Other
		confirmPanel.addActionListener(this);
		bDelete = confirmPanel.addButton(ConfirmPanel.createDeleteButton(true));
		bDelete.addActionListener(this);
		setExplanation();
	}   //  dynInit

	/**
	 *  Action Listener
	 *  @param e event
	 */
	public void actionPerformed (ActionEvent e)
	{
		if (e.getActionCommand().equals(ConfirmPanel.A_CANCEL))
		{
			dispose();
		}
		else if (e.getActionCommand().equals(ConfirmPanel.A_OK))
		{
			save();
			dispose();
		}
		else if (e.getSource() == bDelete)
		{
			if (delete())
				ADialog.info(m_WindowNo, this, "ValuePreferenceDeleted");
			else
				ADialog.warn(m_WindowNo, this, "ValuePreferenceNotFound");
			dispose();
		}
		else
			setExplanation();
	}   //  actionPerformed

	/**
	 *  Set Explanation
	 */
	private void setExplanation()
	{
		/** @todo translation */
		StringBuffer expl = new StringBuffer("For ");
		if (cbClient.isSelected() && cbOrg.isSelected())
			expl.append("this Client and Organization");
		else if (cbClient.isSelected() && !cbOrg.isSelected())
			expl.append("all Organizations of this Client");
		else if (!cbClient.isSelected() && cbOrg.isSelected())
		{
			cbOrg.setSelected(false);
			expl.append("entire System");
		}
		else
			expl.append("entire System");
		//
		if (cbUser.isSelected())
			expl.append(", this User");
		else
			expl.append(", all Users");
		//
		if (cbWindow.isSelected())
			expl.append(" and this Window");
		else
			expl.append(" and all Windows");
		//
		if (Env.getLanguage(Env.getCtx()).isBaseLanguage())
		{
			lExplanation.setText (expl.toString ());
			this.pack ();
		}
	}   //  setExplanation

	/**
	 *  Delete Preference
	 *  @return number of rows deleted
	 */
	public boolean delete()
	{
		log.info("");
		boolean success = false;
		int AD_Preference_ID = getAD_Preference_ID();
		if (AD_Preference_ID > 0)
		{
			MPreference pref = new MPreference(m_ctx, AD_Preference_ID, null);
			success = pref.delete(true);
			if (success)
				m_ctx.setContext(getContextKey(), (String)null);
		}
		return success;
	}   //  delete
	
	/**
	 * 	Get AD_Preference_ID based on selection
	 *	@return id or 0
	 */
	private int getAD_Preference_ID()
	{
		StringBuffer sql = new StringBuffer ("SELECT AD_Preference_ID FROM AD_Preference WHERE ");
		//	Client
		sql.append("AD_Client_ID=").append(cbClient.isSelected() ? m_AD_Client_ID : 0);
		//	Org
		sql.append(" AND AD_Org_ID=").append(cbOrg.isSelected() ? m_AD_Org_ID : 0);
		//	Optional User
		if (cbUser.isSelected())
			sql.append(" AND AD_User_ID=").append(m_AD_User_ID);
		else
			sql.append(" AND AD_User_ID IS NULL");
		//	Optional Window
		if (cbWindow.isSelected())
			sql.append(" AND AD_Window_ID=").append(m_AD_Window_ID);
		else
			sql.append(" AND AD_Window_ID IS NULL");
		//	Attribute (Key)
		sql.append(" AND Attribute='").append(m_Attribute).append("'");
		//
		log.finest(sql.toString());
		int id = DB.getSQLValue(null, sql.toString());
		if (id < 0)
			id = 0;
		return id;
	}	//	getAD_Preference_ID

	/**
	 *  Get Context Key
	 *  @return Context Key
	 */
	private String getContextKey()
	{
		if (cbWindow.isSelected())
			return "P" + m_AD_Window_ID + "|" + m_Attribute;
		else
			return "P|" + m_Attribute;
	}   //  getContextKey

	/**
	 *  Save to Disk
	 *  @return true if inserted or updated
	 */
	public boolean save()
	{
		log.info(m_Attribute + " = " + m_Value);

		//	Handle NULL
		if (m_Value == null || m_Value.length() == 0)
		{
			if (DisplayType.isLookup(m_DisplayType))
				m_Value = "-1";	//	 -1 may cause problems (BPartner - M_DiscountSchema
			else if (DisplayType.isDate(m_DisplayType))
				m_Value = " ";
			else
			{
				ADialog.warn(m_WindowNo, this, "ValuePreferenceNotInserted");
				return false;
			}
		}
		//	No Variables (SQL)
		else if (m_Value.indexOf("@") != -1)
		{
			ADialog.warn(m_WindowNo, this, "ValuePreferenceNotInserted");
			return false;
		}

		boolean success = false;
		int AD_Preference_ID = getAD_Preference_ID();
		MPreference pref = new MPreference(m_ctx, AD_Preference_ID, null);
		if (AD_Preference_ID == 0) //	New
		{
			int Client_ID = cbClient.isSelected() ? m_AD_Client_ID : 0;
			int Org_ID = cbOrg.isSelected() ? m_AD_Org_ID : 0;
			pref.setClientOrg(Client_ID, Org_ID);
			//
			if (cbWindow.isSelected())
				pref.setAD_Window_ID(m_AD_Window_ID);
			if (cbUser.isSelected())
				pref.setAD_User_ID(m_AD_User_ID);
			pref.setAttribute(m_Attribute);
		}
		pref.setValue(m_Value);
		
		success = pref.save();
		if (success)
		{
			m_ctx.setContext(getContextKey(), m_Value);
			ADialog.info(m_WindowNo, this, "ValuePreferenceInserted");
		}
		else
			ADialog.warn(m_WindowNo, this, "ValuePreferenceNotInserted");
		return success;
	}   //  insert

}   //  ValuePreference
