/******************************************************************************
 * The contents of this file are subject to the   Compiere License  Version 1.1
 * ("License"); You may not use this file except in compliance with the License
 * You may obtain a copy of the License at http://www.compiere.org/license.html
 * Software distributed under the License is distributed on an  "AS IS"  basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 * The Original Code is Compiere ERP & CRM Smart Business Solution. The Initial
 * Developer of the Original Code is Jorg Janke. Portions created by Jorg Janke
 * are Copyright (C) 1999-2005 Jorg Janke.
 * All parts are Copyright (C) 1999-2005 ComPiere, Inc.  All Rights Reserved.
 * Contributor(s): ______________________________________.
 *****************************************************************************/
package com.ampiere.web.servlet;

import java.io.IOException;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.Enumeration;
import java.util.logging.Level;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;

import org.apache.commons.lang.StringUtils;
import org.apache.ecs.AlignType;
import org.apache.ecs.xhtml.big;
import org.apache.ecs.xhtml.div;
import org.apache.ecs.xhtml.form;
import org.apache.ecs.xhtml.hr;
import org.apache.ecs.xhtml.i;
import org.apache.ecs.xhtml.img;
import org.apache.ecs.xhtml.input;
import org.apache.ecs.xhtml.li;
import org.apache.ecs.xhtml.link;
import org.apache.ecs.xhtml.option;
import org.apache.ecs.xhtml.script;
import org.apache.ecs.xhtml.small;
import org.apache.ecs.xhtml.span;
import org.apache.ecs.xhtml.table;
import org.apache.ecs.xhtml.td;
import org.apache.ecs.xhtml.th;
import org.apache.ecs.xhtml.thead;
import org.apache.ecs.xhtml.tr;
import org.apache.ecs.xhtml.ul;
import org.compiere.common.constants.DisplayTypeConstants;
import org.compiere.model.DataStatusEvent;
import org.compiere.model.DataStatusListener;
import org.compiere.model.GridField;
import org.compiere.model.GridTab;
import org.compiere.model.GridWindowVO;
import org.compiere.model.MCurrency;
import org.compiere.model.MLocator;
import org.compiere.model.MPInstance;
import org.compiere.model.MSession;
import org.compiere.process.ProcessInfo;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.DisplayType;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
import org.compiere.util.Msg;
import org.compiere.util.NamePair;
import org.compiere.util.ValueNamePair;
import org.compiere.util.WebDoc;
import org.compiere.util.WebEnv;
import org.compiere.util.WebSessionCtx;
import org.compiere.util.WebUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.ampiere.util.AWebUtil;
import com.ampiere.util.AmpiereUtil;
import com.ampiere.util.Constants;
import com.ampiere.util.ProcessCtl;

import com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl;
import com.sun.org.apache.xpath.internal.operations.Div;

import javax.xml.parsers.DocumentBuilderFactory;


/**
 *  Web Window Servlet
 *
 *  @author Jorg Janke
 *  @version  $Id: WWindow.java,v 1.1 2010/01/13 11:51:48 clmg Exp $
 */
public class WWindow extends HttpServlet implements DataStatusListener
{
	private static final long serialVersionUID = 5764325063392615769L;
	/**	Logger			*/
	protected static CLogger	log = CLogger.getCLogger(WWindow.class);

	/**
	 *  Initialize global variables
	 *  @param config
	 *  @throws ServletException
	 */
	public void init(ServletConfig config) throws ServletException
	{
		super.init (config);
		if (!WebEnv.initWeb(config))
			throw new ServletException("WWindow.init");
	}   //  init
	
	/**
	 * Get Servlet information
	 * @return info
	 */
	public String getServletInfo()
	{
		return "Compiere Web Window";
	}	//	getServletInfo

	/**
	 * Clean up resources
	 */
	public void destroy()
	{
		log.fine("destroy");
	}   //  destroy

	/** Window Number Counter                   */
	private static int          s_WindowNo  = 1;
	/** Form Name                               */
	protected static final String FORM_NAME   = "WForm";

	/**  Hidden Parameter   Command - Button    */
	private static final String P_Command   = "PCommand";
	/** Hidden Parameter - Tab No               */
	private static final String P_Tab       = "PTab";
	/** Hidden Parameter - MultiRow Row No      */
	private static final String P_MR_RowNo  = "PMRRowNo";
	/** Hidden Parameter - Changed Field for Callout/etc.	*/
	private static final String P_ChangedColumn = "ChangedColumn";
	/** Hidden Parameter - reserve 1	*/
	private static final String P_Reserve1   = "Reserve1";
	/** Hidden Parameter - reserve 2	*/
	private static final String P_Reserve2   = "Reserve2";
	/** Hidden Parameter - reserve 3	*/
	private static final String P_Reserve3   = "Reserve3";
	
	private static final String Change_Flag   = "ChangeFlag";

	/** Multi Row Lines per Screen          */
	private static final int    MAX_LINES   = 12;
	/** Indicator for last line             */
//	private static final int    LAST_LINE   = 999999;

	/** Error Indicator                     */
	private static final String ERROR       = " ERROR! ";

	private HttpServletRequest m_request = null;	// HTTP servelet request object
	private StringBuffer m_popupAlert = null;		// Callout result popup alerts/warinings
	private String m_popupLookup = null;			// Callout requst popup dialog javascript
	
	private String m_oldFieldGroup = null; //clmg 2009/03/11

	/**
	 *  Process the HTTP Get request - Initial Call.
	 *  <br>
	 *  http://localhost/compiere/WWindow?AD_Window_ID=123
	 *  <br>
	 *  Create Window with request parameters
	 *  AD_Window_ID
	 *  AD_Menu_ID
	 *
	 *  Clean up old/existing window
	 *
	 *  @param request
	 *  @param response
	 *  @throws ServletException
	 *  @throws IOException
	 */
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		m_popupAlert = null;
		m_popupLookup = null;
		m_request = request;
		
		request.getSession().setAttribute(Constants.SAVE_ERROR, Constants.DISABLED); //clmg 2009/03/24

		//  Get Session attributes
		HttpSession sess = request.getSession();
		WebSessionCtx wsc = WebSessionCtx.get(request);
		if (wsc == null)
		{
			WebUtil.createTimeoutPage(request, response, this, null);
			return;
		}

		//  Parameter: AD_Window_ID
		int AD_Window_ID = WebUtil.getParameterAsInt(request, "AD_Window_ID");
		//  Get Parameter: Menu_ID
		int AD_Menu_ID = WebUtil.getParameterAsInt(request, "AD_Menu_ID");
		//
		log.info("AD_Window_ID=" + AD_Window_ID
			+ "; AD_Menu_ID=" + AD_Menu_ID);

		//  Clean up old Window
		WWindowStatus ws = WWindowStatus.get(request);
		if (ws != null)
		{
			int WindowNo = ws.mWindow.getWindowNo();
			log.fine("Disposing - WindowNo=" + WindowNo + ", ID=" + ws.mWindow.getAD_Window_ID());
//			ws.mWindow.dispose();
			try{
				ws.mWindow.dispose();
			}catch(Exception e){
//				WebUtil.createResponse (request, response, this, null, doc, true);
				return;
			}
			
			Env.clearWinContext(wsc.ctx, WindowNo);
		}

		/**
		 *  New Window data
		 */
		GridWindowVO mWindowVO = GridWindowVO.create (wsc.ctx, s_WindowNo++, AD_Window_ID, AD_Menu_ID);
		if (mWindowVO == null)
		{
			String msg = Msg.translate(wsc.ctx, "AD_Window_ID") + " "
				+ Msg.getMsg(wsc.ctx, "NotFound") + ", ID=" + AD_Window_ID + "/" + AD_Menu_ID;
			WebUtil.createErrorPage(request, response, this, msg);
			sess.setAttribute(WWindowStatus.NAME, null);
			return;
		}
		//  Create New Window
		ws = new WWindowStatus(mWindowVO);
		sess.setAttribute(WWindowStatus.NAME, ws);

		//  Query
//		ws.curTab.query(ws.mWindow.isTransaction());
		//TODO
		ws.curTab.query(ws.mWindow.isTransaction()?2:0);
		ws.curTab.navigate(0);

        resetAmountformat(wsc, ws);
        sess.setAttribute(WebSessionCtx.NAME, wsc);
        
		// Clear session field lookup informations
		sess.setAttribute("FieldLookup", null);

		// Add data status listener, catch Callout errors
		ws.curTab.addDataStatusListener(this);

		/**
		 *  Build Page
		 */
		WebDoc doc = null;
		if (ws.curTab.isSingleRow())
			doc = getSR_Form (request.getRequestURI(), wsc, ws);
		else
			doc = getMR_Form (request.getRequestURI(), wsc, ws);

		//	fini
		log.fine("Fini");
	//	log.trace(log.l6_Database, doc.toString());
		WebUtil.createResponse (request, response, this, null, doc, true);
		log.fine("Closed");
	}   //  doGet


	/**************************************************************************
	 *  Process the HTTP Post request
	 *
	 *  @param request request
	 *  @param response response
	 *  @throws ServletException
	 *  @throws IOException
	 */
	public void doPost(HttpServletRequest request, HttpServletResponse response) 
		throws ServletException, IOException
	{
		m_popupAlert = null;
		m_popupLookup = null;
		m_request = request;	
	
		String actionType = request.getParameter(Constants.ACTION_TYPE);
		if(Constants.CHECK_SAVE_ERROR_ACTION.equals(actionType)){
			String saveError;
			if(request.getSession().getAttribute(Constants.SAVE_ERROR)==null){
				saveError = Constants.DISABLED;
			}else{
				saveError = (String)request.getSession().getAttribute(Constants.SAVE_ERROR); //clmg 2009/03/24;
			}
			AWebUtil.createSaveErrorResponse(response, saveError); //clmg 2009/03/24);
			return;
		}

		WebEnv.dump(request);
		//  Get Session Info
	  	WebSessionCtx wsc = WebSessionCtx.get(request);
		WWindowStatus ws = WWindowStatus.get(request);
		if (wsc == null || ws == null)
		{
			if (wsc == null)
				WebUtil.createTimeoutPage(request, response, this, "No Context");
			else
				doGet(request, response);
			return;
		}

        //  Get Parameter: Command
		String p_cmd = WebUtil.getParameter (request, P_Command);
		String column = WebUtil.getParameter (request, P_ChangedColumn);
		log.info("Cmd=" + p_cmd + " - ChangedColumn=" + column);

		// Add data status listener, catch Callout errors
		ws.curTab.addDataStatusListener(this);

		//	Changed Column
		if (column != null && column.length() > 0)
		{
			if (p_cmd != null && "ButtonCommand".equalsIgnoreCase(p_cmd)) {
				// Button process
				int processId = WebUtil.getParameterAsInt(request, P_Reserve1);
				boolean batch = ("true".equalsIgnoreCase(WebUtil.getParameter(request, P_Reserve2)) ? true : false);
				String value = WebUtil.getParameter(request, P_Reserve3);
				request.setAttribute(P_Command, "");
				request.setAttribute(P_ChangedColumn, "");
				request.setAttribute(P_Reserve1, "");
				request.setAttribute(P_Reserve2, "");
				request.setAttribute(P_Reserve3, "");

				int currentRow = ws.curTab.getCurrentRow();
				int keyId = ws.curTab.getKeyID(currentRow);
				actionButton(ws, wsc, column, processId, batch, value);

				// Query again to get newest values from DB
				ws.curTab.query(ws.curTab.getOnlyCurrentDays());

				// Navigate to current row
				for (int ii = 0; ii < ws.curTab.getRowCount(); ii++) {
					if (keyId == ws.curTab.getKeyID(ii)) {
						ws.curTab.navigate(ii);
						break;
					}
				}
			} else {
				//	Changed Column
				updateFields(request, wsc, ws);
			}
		}
		else	//	Exit & Commands
		{
			if (p_cmd.equals("Exit"))
			{
				MSession cSession = MSession.get(wsc.ctx, false);
				if (cSession != null)
					cSession.logout();
				WebUtil.createLoginPage(request, response, this, ws.ctx, "Exit");
				return;
			}
			executeCommand(request, p_cmd, wsc, ws);
		}
		
		// Clear session field lookup informations
		HttpSession sess = request.getSession();
		sess.setAttribute("FieldLookup", null);

        resetAmountformat(wsc, ws);
        sess.setAttribute(WebSessionCtx.NAME, wsc);
        
		/**************************************************
		 *  Build Page
		 */
		WebDoc doc = null;
		//  Create Simgle/Multi Row
		// modi-by-clmg
//		if (ws.curTab.isSingleRow())
//			doc = getSR_Form (request.getRequestURI(), wsc, ws);
//		else
//			doc = getMR_Form (request.getRequestURI(), wsc, ws);
		if (ws.curTab.isSingleRow()){
			// when it is not a callout
//			if(StringUtils.isEmpty(column)){
			if (!Constants.AJAX_ACTION.equals(actionType)){
				doc = getSR_Form (request.getRequestURI(), wsc, ws);
			}
			request.getSession().setAttribute(Constants.SAVE_ERROR, Constants.DISABLED); //clmg 2009/03/24
//			}
		}
			
		else
			doc = getMR_Form (request.getRequestURI(), wsc, ws);

	//	log.trace(log.l6_Database, doc.toString());
		//modi by clmg, callout
		//WebUtil.createResponse (request, response, this, null, doc, true);
		if(!Constants.AJAX_ACTION.equals(actionType)){
			//---
			if (m_popupAlert != null && m_popupAlert.length() > 0) {
				// Popup error/warning message
				doc.getBody().setOnLoad(("alert('" + m_popupAlert.toString() + "');"));
			}
			if (m_popupLookup != null && m_popupLookup.length() > 0) {
				// Open lookup window
				doc.getBody().setOnLoad(m_popupLookup);
			}

			//
			log.fine("Fini");
			WebUtil.createResponse (request, response, this, null, doc, true);
		}else{
			//if that was a callout
			//WebUtil.createResponse (request, response, this, null, doc, true);
			Document xml_doc = get_Ajax_SR_Form (request, wsc, ws);
			AWebUtil.createCalloutAjaxResponse(response, xml_doc);
//			WebUtil.createResponse (request, response, this, null, doc, true);
		}
		//--clmg
		log.fine("Closed");
	}   //  doPost

	
	/**************************************************************************
	 *  Execute Command.
	 *
	 *  @param request request
	 *  @param p_cmd command
	 *  @param wsc session context
	 *  @param ws window status
	 */
	private void executeCommand (HttpServletRequest request, 
		String p_cmd, WebSessionCtx wsc, WWindowStatus ws)
	{
		//  Get Parameter: Command and Tab changes
		String p_tab = WebUtil.getParameter (request, P_Tab);
		String p_row = WebUtil.getParameter (request, P_MR_RowNo);    //  MR Row Command
		log.config(p_cmd + " - Tab=" + p_tab + " - Row=" + p_row);
//		Env.setContext(wsc.ctx, ws.curTab.getWindowNo(), "NeedSave", 0);
		wsc.ctx.setContext(ws.curTab.getWindowNo(), "NeedSave", 0);

		/**
		 *  Multi-Row Selection (i.e. display single row)
		 */
		if (p_row != null && p_row.length() > 0)
		{
			try
			{
				int newRowNo = Integer.parseInt (p_row);
				ws.curTab.navigate(newRowNo);
				ws.curTab.setSingleRow(true);
			}
			catch (Exception e)
			{
				log.log(Level.SEVERE, "Parse RowNo="+ p_row, e);
			}
		}

		/**
		 *  Tab Change
		 */
		else if (p_tab != null && p_tab.length() > 0)
		{
			int newTabNo = 0;
			try
			{
				newTabNo = Integer.parseInt (p_tab);
			}
			catch (Exception e)
			{
				log.log(Level.SEVERE, "Parse TabNo="+ p_tab, e);
			}
			//  move to detail
			if (newTabNo > ws.curTab.getTabNo())
			{
				ws.curTab = ws.mWindow.getTab(newTabNo);
//				ws.curTab.query(false);
				ws.curTab.query(0);
				ws.curTab.navigate(0);
			}
			//  move back
			else if (newTabNo < ws.curTab.getTabNo())
			{
				ws.curTab = ws.mWindow.getTab(newTabNo);
				ws.curTab.dataRefresh();
			}
		}

		/**
		 *  Multi-Row Toggle
		 */
		else if (p_cmd.equals("Multi"))
		{
			boolean single = ws.curTab.isSingleRow();
			ws.curTab.setSingleRow(!single);
//			if (single)
//				ws.curTab.navigate(0);
		}

		/**
		 *  Position Commands
		 */
		else if (p_cmd.equals("First"))
		{
			ws.curTab.navigate(0);
		}
		else if (p_cmd.equals("Next"))
		{
			if( ws.curTab.isSingleRow() ) {
				if( ws.curTab.getCurrentRow() < ws.curTab.getRowCount() ) {
					ws.curTab.navigateRelative(+1);
				}
			} else {
				if( ws.curTab.getRowCount() - ws.curTab.getCurrentRow() >= MAX_LINES ) {
					ws.curTab.navigateRelative(+MAX_LINES);
				}
			}
		}
		else if (p_cmd.equals("Previous"))
		{
			if( ws.curTab.isSingleRow() ) {
				if( ws.curTab.getCurrentRow() > 0 ) {
					ws.curTab.navigateRelative(-1);
				}
			} else {
				if( ws.curTab.getCurrentRow() >= MAX_LINES ) {
					ws.curTab.navigateRelative(-MAX_LINES);
				}
			}
		}
		else if (p_cmd.equals("Last"))
		{
			ws.curTab.navigateRelative(999999);
		}


		/**
		 *  Find
		 */
		else if (p_cmd.equals("Find"))
		{
			/** @todo Find */
		}

		/**
		 *  Refresh
		 */
		else if (p_cmd.equals("Refresh"))
		{
			ws.curTab.dataRefreshAll();
		}

		/**
		 *  Attachment
		 */
		else if (p_cmd.equals("Attachment"))
		{
			/** @todo Attachment */
		}

		/**
		 *  History
		 */
		else if (p_cmd.equals("History"))
		{
			if (ws.mWindow.isTransaction() && ws.curTab.getWindowNo() == 0)
			{
//				ws.curTab.query( !ws.curTab.isOnlyCurrentRows() );
				ws.curTab.query( ws.curTab.getOnlyCurrentDays() );
				ws.curTab.navigate(0);
			}
		}

		/**
		 *  Report
		 */
		else if (p_cmd.equals("Report"))
		{
			/** @todo Report */
//			Env.setContext( wsc.ctx, ws.curTab.getWindowNo(), "IsReportStart", true );
			wsc.ctx.setContext( ws.curTab.getWindowNo(), "IsReportStart", true );
		}

		/**
		 *  Print
		 */
		else if (p_cmd.equals("Print"))
		{
			/** @todo Print */
//			Env.setContext( wsc.ctx, ws.curTab.getWindowNo(), "IsPrintStart", true );
			wsc.ctx.setContext( ws.curTab.getWindowNo(), "IsPrintStart", true );
		}

		/**
		 *  New
		 */
		else if (p_cmd.equals("New"))
		{
			ws.curTab.setSingleRow(true);
			if (!ws.curTab.dataNew(false))
				ws.curTab.dataIgnore();
//			Env.setContext(wsc.ctx, ws.curTab.getWindowNo(), "NeedSave", 1);
			wsc.ctx.setContext(ws.curTab.getWindowNo(), "NeedSave", 1);
		}

		/**
		 *  Ignore
		 */
		else if (p_cmd.equals("Ignore"))
		{
			ws.curTab.dataIgnore();
			ws.curTab.navigate( 0 );
		}

		/**
		 *  Delete
		 */
		else if (p_cmd.equals("Delete"))
		{
			ws.curTab.dataDelete();
		}

		/**
		 *  Save - Check for changed values
		 */
		else if (p_cmd.equals("Save"))
		{
			executeSave (request, wsc, ws);
		}
	}   //  executeCommand

	/**
	 *  Execute Save
	 *  @param request request
	 *  @param ws
	 */
	private void executeSave (HttpServletRequest request, WebSessionCtx wsc, WWindowStatus ws)
	{
		log.info("");
		boolean error = updateFields(request, wsc, ws);
		
		request.getSession().setAttribute(Constants.SAVE_ERROR, Constants.DISABLED); //clmg 2009/03/24
		
		//  Check Mandatory
		log.fine("Mandatory check");
		int size = ws.curTab.getFieldCount();
		for (int i = 0; i < size; i++)
		{
			GridField field = ws.curTab.getField(i);
			if (field.isMandatory(true))        //  context check
			{
				Object value = field.getValue();
				if (value == null || value.toString().length() == 0)
				{
					field.setInserting (true);  //  set editable otherwise deadlock
					field.setError(true);
					field.setErrorValue(value == null ? null : value.toString());
					if (!error)
						error = true;
					log.info("Mandatory Error: " + field.getColumnName());
				}
				else
					field.setError(false);
			}
		}

		if (error){
			request.getSession().setAttribute(Constants.SAVE_ERROR, Constants.ENABLED);//clmg 2009/03/24
			return;
		}
			

		//  save it - of errors ignore changes
		if (!ws.curTab.dataSave(true))
			ws.curTab.dataIgnore();
//		Env.setContext(wsc.ctx, ws.curTab.getWindowNo(), "NeedSave", 0);
		wsc.ctx.setContext(ws.curTab.getWindowNo(), "NeedSave", 0);
		log.fine("done");
	}   //  executeSave

	/**
	 * 	Update Field Values from Parameter
	 *	@param request request
	 *	@param wsc session context
	 *	@param ws window status
	 *	@return true if error
	 */
	private boolean updateFields(HttpServletRequest request, WebSessionCtx wsc, WWindowStatus ws)
	{
		boolean error = false;
		try
		{
			String enc = request.getCharacterEncoding();
			if (enc == null)
				request.setCharacterEncoding(WebEnv.ENCODING);
		}
		catch (Exception e)
		{
			log.log(Level.SEVERE, "Set CharacterEndocung=" + WebEnv.ENCODING, e);
		}
		//  loop through parameters
		Enumeration en = request.getParameterNames();
		while (en.hasMoreElements())
		{
			String key = (String)en.nextElement();
			if (key == null) {
				continue;
			}

			//  ignore hidden commands
			if (key.equals(P_Command)
				|| key.equals(P_ChangedColumn)
				|| key.equals(P_MR_RowNo) 
				|| key.equals(P_Tab)
				|| key.equals(P_Reserve1)
				|| key.equals(P_Reserve2)
				|| key.equals(P_Reserve3))
				continue;
			GridField mField = ws.curTab.getField(key);
		//	log.fine("executeSave - Key=" + key + " - " + mField);
			//  we found a writable field
			if (mField != null && mField.isEditable(true))
			{
				String value = WebUtil.getParameter(request, key);
				Object dbValue = mField.getValue();
				boolean fieldError = false;
				String columnName = mField.getColumnName();
				log.finest(columnName 
					+ ": " + (dbValue==null ? "null" : dbValue.toString()) 
					+ " -> " + (value==null ? "null" : value.toString()));
					//  same = both null
				if (dbValue == null && value == null)
					continue;
				//   new value null
				else if (dbValue != null && value == null)
					setFieldNewValue(wsc, ws, mField, null);
				//  from null to new value
				else if (dbValue == null && value != null)
					fieldError = !setFieldValue (wsc, ws, mField, value);
				//  same
				else if (dbValue.equals(value))
					continue;
				else
					fieldError = !setFieldValue (wsc, ws, mField, value);
				//
				if (!error && fieldError)
				{
					log.info("Error: " + mField.getColumnName());
					error = true;
				}
			}
		}   //  for all parameteres
		
		int fileds = ws.curTab.getFieldCount();
		for( int i=0; i<fileds; i++ )
		{
			GridField mField = ws.curTab.getField(i);
			if (mField != null && mField.isEditable(true) && mField.getDisplayType() == DisplayType.YesNo )
			{
				String key = mField.getColumnName();
				if ( key.equals( "IsActive" ) ) {
					continue;
				}
				String value = WebUtil.getParameter(request, key);
				Object dbValue = mField.getValue();

				if (dbValue != null && value == null) {
					setFieldNewValue(wsc, ws, mField, false);
				}
			}
		}

		//	Re-Do Changed Column to overwrite
		String columnName = WebUtil.getParameter (request, P_ChangedColumn);
		if (columnName != null && columnName.length() > 0)
		{
			GridField mField = ws.curTab.getField(columnName);
			if (mField != null)
			{
				String value = WebUtil.getParameter(request, columnName);
				Object newValue = getFieldValue (wsc, mField, value);
				if (!ERROR.equals(newValue))
				{
					//	De-Selected Check Boxes are null 
					if (newValue == null && mField.getDisplayType() == DisplayType.YesNo)
						newValue = "N";
					log.fine("ChangedColumn: " + columnName + "=" + newValue);
					setFieldNewValue(wsc, ws, mField, newValue);
				}
			}
		}

//		Env.setContext(wsc.ctx, ws.curTab.getWindowNo(), "NeedSave", 1);
		wsc.ctx.setContext(ws.curTab.getWindowNo(), "NeedSave", 1);

		return error;
	}	//	updateFields

	
	/**************************************************************************
	 *  Set Field Value
	 *  @param wsc web session
	 *  @param ws window status
	 *  @param mField field
	 *  @param value as String
	 *  @return true if correct
	 */
	private boolean setFieldValue (WebSessionCtx wsc, WWindowStatus ws, 
		GridField mField, String value)
	{
		Object newValue = getFieldValue (wsc, mField, value);
		if (ERROR.equals(newValue))
		{
			mField.setErrorValue(value);
			return false;
		}
		Object dbValue = mField.getValue();
		if ((newValue == null && dbValue != null)
				|| (newValue != null && !newValue.equals(dbValue))) {
			setFieldNewValue(wsc, ws, mField, newValue);
		}
		return true;
	}   //  setFieldValue

	/**
	 *  Get Field value (convert value to datatype of MField)
	 *  @param wsc session context
	 *  @param mField field
	 *  @param value String Value
	 *  @return converted Field Value
	 */
	private Object getFieldValue (WebSessionCtx wsc, GridField mField, String value)
	{
		if (value == null || value.length() == 0)
			return null;

		int dt = mField.getDisplayType();
		String columnName = mField.getColumnName();

		//  BigDecimal
		if (DisplayType.isNumeric(dt))
		{
			BigDecimal bd = null;
			try
			{
				Number nn = null;
				if (dt == DisplayType.Amount)
					nn = wsc.amountFormat.parse(value);
				else if (dt == DisplayType.Quantity)
					nn = wsc.quantityFormat.parse(value);
				else	//	 DisplayType.CostPrice
					nn = wsc.numberFormat.parse(value);
				if (nn instanceof BigDecimal)
					bd = (BigDecimal)nn;
				else
					bd = new BigDecimal(nn.toString());
			}
			catch (Exception e)
			{
				log.warning("BigDecimal: " + columnName + "=" + value + ERROR);
				return ERROR;
			}
			log.fine("BigDecimal: " + columnName + "=" + value + " -> " + bd);
			return bd;
		}

		//  ID
		else if (DisplayType.isID(dt) && !columnName.equals("AD_Language"))
		{
			Integer ii = null;
			try
			{
				ii = new Integer (value);
			}
			catch (Exception e)
			{
				log.log(Level.WARNING, "ID: " + columnName + "=" + value, e);
				ii = null;
			}
			//  -1 indicates NULL
			if (ii != null && ii.intValue() == -1)
				ii = null;
			log.fine("ID: " + columnName + "=" + value + " -> " + ii);
			return ii;
		}

		//  Date/Time
		else if (DisplayType.isDate(dt))
		{
			Timestamp ts = null;
			try
			{
				java.util.Date d = null;
				if (dt == DisplayType.Date)
					d = wsc.dateFormat.parse(value);
				else
					d = wsc.dateTimeFormat.parse(value);
				ts = new Timestamp(d.getTime());
			}
			catch (Exception e)
			{
				log.warning("Date: " + columnName + "=" + value + ERROR);
				return ERROR;
			}
			log.fine("Date: " + columnName + "=" + value + " -> " + ts);
			return ts;
		}

		//  Checkbox
		else if (dt == DisplayType.YesNo)
		{
			Boolean retValue = Boolean.FALSE;
			if (value.equals("true"))
				retValue = Boolean.TRUE;
			log.fine("YesNo: " + columnName + "=" + value + " -> " + retValue);
			return retValue;
		}

		//  treat as string
		log.fine(columnName + "=" + value);
		return value;
	}   //  getFieldValue


	/**************************************************************************
	 *	Return SingleRow Form details
	 *  @param action action
	 *  @param wsc web session context
	 *  @param ws window status
	 *  @return Form
	 * @throws ParserConfigurationException 
	 */
	private  Document get_Ajax_SR_Form (HttpServletRequest request,WebSessionCtx wsc, WWindowStatus ws)
	{
		Document document = null;

		try{
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			//ビルダーからDOMを取得する
			document = builder.newDocument();
			

			//XMLのルート要素(userタグ)を追加する
			Element elements = document.createElement(Constants.ELEMENTS);
			document.appendChild(elements);       


			//   		if (ws.curTab.isDisplayed())
			//TODO clmg
			if (ws.curTab.isDisplayed(false))
			{
				//   			Env.setContext(wsc.ctx, ws.curTab.getWindowNo(), "Record_ID", ws.curTab.getRecord_ID());
				wsc.ctx.setContext(ws.curTab.getWindowNo(), "Record_ID", ws.curTab.getRecord_ID());
				int currentRow = ws.curTab.getCurrentRow();
				int noFields = ws.curTab.getFieldCount();
				for (int i = 0; i < noFields; i++)
				{
					GridField field = ws.curTab.getField(i);
					String columnName = field.getColumnName();
					
					//for test
					//System.out.println("column name="+columnName+"---noFields="+noFields+": i= "+i);

					/**
					 *  Get Data and convert to String (singleRow)
					 */
					Object oData = ws.curTab.getValue(field);

					String oldValue = ""; // excludes the field which has triggerd callout
					Object newValue = "";
					String objId = "";
					String newValue_str = "";
					//list の場合
					if(DisplayType.isLookup(field.getDisplayType())
							&& field.getDisplayType() != DisplayTypeConstants.Search){
						//set select options
						boolean readOnly = (currentRow == -1 || ! field.isEditable(true));
						Object[] list = field.getLookup().getData(true, true, !readOnly, false).toArray();    //clmg 2009/03/10						
						Element element = document.createElement(Constants.ELEMENT);
						elements.appendChild(element);
						
						Element elm_id=document.createElement(Constants.ID);
						objId = getHtmlObjectName(field);
						elm_id.appendChild(document.createTextNode(objId));
						element.appendChild(elm_id);
						
						Element elm_lookup=document.createElement(Constants.LOOKUP);
						element.appendChild(elm_lookup);
						elm_lookup.appendChild(document.createTextNode(Constants.ENABLED));

						Element elm_visibility=document.createElement(Constants.VISIBILITY);
						element.appendChild(elm_visibility);
						elm_visibility.appendChild(document.createTextNode(Constants.ENABLED));

						Element elm_newValue=document.createElement(Constants.NEW_VALUE);
						element.appendChild(elm_newValue);
						
						for(int p=0; p<list.length; p++){
							
							String key = "";
							String value = "";
							
							boolean isNumber = list[0] instanceof KeyNamePair;
							if (isNumber)
							{
								KeyNamePair onePair = (KeyNamePair)list[p];
								key = String.valueOf(onePair.getKey());
								value = onePair.getName();
							}
							else
							{
								ValueNamePair onePair = (ValueNamePair)list[p];
								key = onePair.getValue();
								value = onePair.getName();
							}
							
							//list 
							//<name>
							Element elm_item=document.createElement(Constants.ITEM);
							elm_newValue.appendChild(elm_item);
							//<key>
							Element elm_key=document.createElement(Constants.KEY);
							elm_item.appendChild(elm_key);
							elm_key.appendChild(document.createTextNode(String.valueOf(key)));
							//<value>
							Element elm_value=document.createElement(Constants.VALUE);
							elm_item.appendChild(elm_value);
							elm_value.appendChild(document.createTextNode(value));							
						}
						
						Element elm_readonly=document.createElement(Constants.READONLY);
						element.appendChild(elm_readonly);
						elm_readonly.appendChild(document.createTextNode(Constants.NO));
						
						Element elm_type=document.createElement(Constants.TYPE);
						element.appendChild(elm_type);
						elm_type.appendChild(document.createTextNode(Constants.ENABLED));
					}
					//
					
					if (field.isDisplayed(true))
					{

						oldValue = request.getParameter(field.getColumnName());
						newValue = field.getValue();

						
//						if(newValue==null && oldValue==null
//								|| newValue==null && oldValue!=null
//								|| newValue!=null && oldValue==null
//								|| !newValue.equals(oldValue)){
						if(true){
							// display and reset value
							//ルート要素に子ノード(lastnameタグ)を追加する
							Element element = document.createElement(Constants.ELEMENT);
							elements.appendChild(element);

							/**
							 *  data elment below
							 */
							//CHECK BOX のルールは。。TODO 
//							if(field.getDisplayType() != DisplayType.YesNo){
								Element elm_id=document.createElement(Constants.ID);
								element.appendChild(elm_id);
								objId = getHtmlObjectName(field);
								elm_id.appendChild(document.createTextNode(objId));
//								elm_id.appendChild(document.createTextNode(field.getColumnName()));
								
								Element elm_lookup=document.createElement(Constants.LOOKUP);
								element.appendChild(elm_lookup);
								elm_lookup.appendChild(document.createTextNode(Constants.DISABLED));

								Element elm_visibility=document.createElement(Constants.VISIBILITY);
								element.appendChild(elm_visibility);
								elm_visibility.appendChild(document.createTextNode(Constants.ENABLED));

								Element elm_newValue=document.createElement(Constants.NEW_VALUE);
								element.appendChild(elm_newValue);
								
								
//								if(field.getDisplayType() == DisplayType.YesNo){
//									newValue_str = "";
//								}else{
								newValue_str = AWebUtil.toString(newValue, wsc, field.getDisplayType(), columnName, field);
//								}
								elm_newValue.appendChild(document.createTextNode(newValue_str));
								
								Element elm_readonly=document.createElement(Constants.READONLY);
								element.appendChild(elm_readonly);
								
								String realOnlyFlag = !field.isEditable(true)?Constants.YES:Constants.NO;
								// not implemented yet
								if (columnName.indexOf("PaymentRule") >= 0) {
									realOnlyFlag = Constants.YES;
								}								
								elm_readonly.appendChild(document.createTextNode(realOnlyFlag));
								
								
								Element elm_type=document.createElement(Constants.TYPE);
								element.appendChild(elm_type);
								if(field.getDisplayType() == DisplayType.YesNo) {
										//|| field.getDisplayType() == DisplayType.Button){									
									//if that is a checkbox, no need to change the value
									elm_type.appendChild(document.createTextNode(Constants.DISABLED));
								}else{
									elm_type.appendChild(document.createTextNode(Constants.ENABLED));
								}
								
								/**
								 * The display field       Name=columnName, ID=FcolumnName 
								 * Show display field
								 * clmg 2009/03/10 
								 */
								if (field.getDisplayType() == DisplayType.Search
										|| field.getDisplayType() == DisplayType.Location
										|| field.getDisplayType() == DisplayType.Account)
									{
									objId = field.getColumnName() + "F";
									AWebUtil.createDisplayElement(document, elements, objId
											, field, realOnlyFlag, true);
									
									objId = field.getColumnName() + "B";
									AWebUtil.createDisplayElement(document, elements, objId
											, field, realOnlyFlag, true);
								}
//							}
							
							
							/**
							 *  label element below
							 */
							if(field.getDisplayType() != DisplayType.Button){
								Element elementLabel = document.createElement(Constants.ELEMENT);
								elements.appendChild(elementLabel);

								//lastnameタグのテキストを追加する
								Element lbl_id=document.createElement(Constants.ID);
								elementLabel.appendChild(lbl_id);
								objId = getHtmlObjectLabelName(field);
								lbl_id.appendChild(document.createTextNode(objId));
//								elm_id.appendChild(document.createTextNode(field.getColumnName()));
								
								Element lbl_lookup=document.createElement(Constants.LOOKUP);
								elementLabel.appendChild(lbl_lookup);
								lbl_lookup.appendChild(document.createTextNode(Constants.DISABLED));

								Element lbl_visibility=document.createElement(Constants.VISIBILITY);
								elementLabel.appendChild(lbl_visibility);
								lbl_visibility.appendChild(document.createTextNode(Constants.ENABLED));

								Element lbl_newValue=document.createElement(Constants.NEW_VALUE);
								elementLabel.appendChild(lbl_newValue);
								lbl_newValue.appendChild(document.createTextNode(""));
								
								Element lbl_type=document.createElement(Constants.TYPE);
								elementLabel.appendChild(lbl_type);
								lbl_type.appendChild(document.createTextNode(Constants.DISABLED));
								
								Element lbl_readonly=document.createElement(Constants.READONLY);
								elementLabel.appendChild(lbl_readonly);
								lbl_readonly.appendChild(document.createTextNode(!field.isEditable(true)?Constants.YES:Constants.NO));
							}
						}
					}
					else{
						oldValue = request.getParameter(field.getColumnName());
						newValue = field.getValue();
						
//						if(newValue==null && oldValue==null
//								|| newValue==null && oldValue!=null
//								|| newValue!=null && oldValue==null
//								|| !newValue.equals(oldValue)){
						if(true){
							// undisplay or reset value
							Element element = document.createElement(Constants.ELEMENT);
							elements.appendChild(element);
							/**
							 *  data elment below
							 */
							Element elm_id=document.createElement(Constants.ID);
							element.appendChild(elm_id);
							objId = getHtmlObjectName(field);
							elm_id.appendChild(document.createTextNode(objId));
//							elm_id.appendChild(document.createTextNode(field.getColumnName()));
							
							Element elm_lookup=document.createElement(Constants.LOOKUP);
							element.appendChild(elm_lookup);
							elm_lookup.appendChild(document.createTextNode(Constants.DISABLED));

							Element elm_visibility=document.createElement(Constants.VISIBILITY);
							element.appendChild(elm_visibility);
							elm_visibility.appendChild(document.createTextNode(Constants.DISABLED));

							Element elm_newValue=document.createElement(Constants.NEW_VALUE);
							element.appendChild(elm_newValue);
							elm_newValue.appendChild(document.createTextNode(AWebUtil.toString(
									newValue, wsc, field.getDisplayType(), columnName, field)));
							
							Element elm_readonly=document.createElement(Constants.READONLY);
							element.appendChild(elm_readonly);
							String realOnlyFlag = !field.isEditable(true)?Constants.YES:Constants.NO;
							// not implemented yet
							if (columnName.indexOf("PaymentRule") >= 0) {
								realOnlyFlag = Constants.YES;
							}								
							elm_readonly.appendChild(document.createTextNode(realOnlyFlag));
							
							
							Element elm_type=document.createElement(Constants.TYPE);
							element.appendChild(elm_type);
//							elm_type.appendChild(document.createTextNode(Constants.ENABLED));							
							if(field.getDisplayType() == DisplayType.YesNo
									|| field.getDisplayType() == DisplayType.Button){
								//if that is a checkbox, no need to change the value
								elm_type.appendChild(document.createTextNode(Constants.DISABLED));
							}else{
								elm_type.appendChild(document.createTextNode(Constants.ENABLED));
							}
							
							/**
							 *  label element below
							 */
							if(field.getDisplayType() != DisplayType.Button){
								Element elementLabel = document.createElement(Constants.ELEMENT);
								elements.appendChild(elementLabel);

								//lastnameタグのテキストを追加する
								Element lbl_id=document.createElement(Constants.ID);
								elementLabel.appendChild(lbl_id);
								objId = getHtmlObjectLabelName(field);
								lbl_id.appendChild(document.createTextNode(objId));
//								elm_id.appendChild(document.createTextNode(field.getColumnName()));
								
								Element lbl_lookup=document.createElement(Constants.LOOKUP);
								elementLabel.appendChild(lbl_lookup);
								lbl_lookup.appendChild(document.createTextNode(Constants.DISABLED));

								Element lbl_visibility=document.createElement(Constants.VISIBILITY);
								elementLabel.appendChild(lbl_visibility);
								lbl_visibility.appendChild(document.createTextNode(Constants.DISABLED));

								Element lbl_newValue=document.createElement(Constants.NEW_VALUE);
								elementLabel.appendChild(lbl_newValue);
								lbl_newValue.appendChild(document.createTextNode(""));
								
								// type: 1:label 0:data
								Element lbl_type=document.createElement(Constants.TYPE);
								elementLabel.appendChild(lbl_type);
								lbl_type.appendChild(document.createTextNode(Constants.DISABLED));
								
								Element lbl_readonly=document.createElement(Constants.READONLY);
								elementLabel.appendChild(lbl_readonly);
								lbl_readonly.appendChild(document.createTextNode(!field.isEditable(true)?Constants.YES:Constants.NO));
							}
							
							/**
							 * The display field       Name=columnName, ID=FcolumnName 
							 * Hide display field
							 * clmg 2009/03/10 
							 */
							if (field.getDisplayType() == DisplayType.Search
									|| field.getDisplayType() == DisplayType.Location
									|| field.getDisplayType() == DisplayType.Account)
								{
								objId = field.getColumnName() + "F";
								AWebUtil.createDisplayElement(document, elements, objId
										, field, realOnlyFlag, false);
								
								objId = field.getColumnName() + "B";
								AWebUtil.createDisplayElement(document, elements, objId
										, field, realOnlyFlag, false);
							}

						}
					}
				}	//	for all fields
			}	//	displayed
			
			/**
			 * JAVASCRIPTの警告があれば表示する。
			 */
			if (m_popupAlert != null && m_popupAlert.length() > 0) {
				String alertScript = "alert('" + m_popupAlert.toString() + "');";
				Element element = document.createElement(Constants.SCRIPT);
				elements.appendChild(element);
				
				Element elm=document.createElement(Constants.ITEM);
				elm.appendChild(document.createTextNode(alertScript));
				element.appendChild(elm);
			}
			if (m_popupLookup != null && m_popupLookup.length() > 0) {
				// Open lookup window
				Element element = document.createElement(Constants.SCRIPT);
				elements.appendChild(element);
				
				Element elm=document.createElement(Constants.ITEM);
				elm.appendChild(document.createTextNode(m_popupLookup));
				element.appendChild(elm);
			}			
			
		}catch(Exception e){
			System.out.println("get_Ajax_SR_Form error");
			;
		}



		return document;
	}	//	getSR_Form


	/**************************************************************************
	 *	Return MultiRow Form details
	 *  @param action action
	 *  @param wsc session context
	 *  @param ws window status
	 *  @return Form
	 */
	private WebDoc getMR_Form (String action, WebSessionCtx wsc, WWindowStatus ws)
	{
		log.fine("Tab=" + ws.curTab.getTabNo());

		int oldRow =  ws.curTab.getCurrentRow();
		int initRowNo = ( oldRow / MAX_LINES ) * MAX_LINES;

		/**
		 *  Table Header
		 */
		table table = new table().setAlign(AlignType.CENTER);
		table.setClass("displaytag");
		table.setBorder(0);
		table.setCellSpacing(0);
		tr line = new tr();
		//  First Column
		line.addElement(new th().addElement(WebEnv.NBSP));
		//	Tab not displayed
//		if (!ws.curTab.isDisplayed())
		//TODO clmg
		if (!ws.curTab.isDisplayed(false))
			return createLayout (action, table, wsc, ws, "", "-");

		int noFields = ws.curTab.getFieldCount();
		//  for all (header) columns
		for (int colNo = 0; colNo < noFields; colNo++)
		{
			GridField field = ws.curTab.getField(colNo);
			if (field.isDisplayed(false))
			{
				th th = new th();
				th.setNoWrap(true);
				th.addElement(field.getHeader());           //  Name
				th.setAbbr(field.getDescription());         //  Description
				line.addElement(th);
			}
		}   //  for all columns
		table.addElement(new thead().addElement(line));

		/**
		 *  Table Lines
		 */
		int lastRow = initRowNo + MAX_LINES;
		lastRow = Math.min(lastRow, ws.curTab.getRowCount());
		String lineClass[] = {"odd", "even", "current"};
		for (int lineNo = initRowNo; lineNo < lastRow; lineNo++)
		{
			//  Row
			ws.curTab.navigate(lineNo);

			line = new tr();
			if( oldRow == ws.curTab.getCurrentRow() ) {
				line.setClass(lineClass[2]);
			} else {
				line.setClass(lineClass[(lineNo >= 0) ? (lineNo % 2) : 1]);
			}

			//  Selector
			String href = "document." + FORM_NAME + "." + P_MR_RowNo + ".value='" + lineNo + "'; " + FORM_NAME + ".submit();";
			img selector = new img(WebEnv.getImageDirectory("Go.gif"));
			selector.setClass("cursorPointer");
			selector.setOnClick(href);
			line.addElement(new td().addElement(selector));

			//  for all columns
			for (int colNo = 0; colNo < noFields; colNo++)
			{
				td td = new td();
				//
				GridField field = ws.curTab.getField(colNo);
				if (!field.isDisplayed(false))
					continue;

				//  Get Data - turn to string
				Object data = ws.curTab.getValue(field.getColumnName());
				String info = null;
				//
				if (data == null)
					info = "";
				else
				{
					int dt = field.getDisplayType();
					switch (dt)
					{
						case DisplayType.Date:
							info = wsc.dateFormat.format(data);
							td.setAlign("right");
							break;
						case DisplayType.DateTime:
							info = wsc.dateTimeFormat.format(data);
							td.setAlign("right");
							break;
						case DisplayType.Amount:
							info = wsc.amountFormat.format(data);
							td.setAlign("right");
							break;
						case DisplayType.Number:
							info = wsc.numberFormat.format(data);
							td.setAlign("right");
//						case DisplayType.CostPrice:
//							info = wsc.costPriceFormat.format(data);
//							td.setAlign("right");
//							break;
						case DisplayType.Quantity:
							info = wsc.quantityFormat.format(data);
							td.setAlign("right");
							break;
						case DisplayType.Integer:
							info = wsc.integerFormat.format(data);
							td.setAlign("right");
							break;
						case DisplayType.YesNo:
							info = Msg.getMsg(ws.ctx, data.toString());
							break;
						/** @todo output formatting 2 */
						default:
							if (DisplayType.isLookup(dt))
								info = field.getLookup().getDisplay(data);
							else
								info = data.toString();
					}
				}

				//  Empty info
				if (info == null || info.length() == 0 || info.trim().length() == 0) {
					info = WebEnv.NBSP;                //  Space
				}

				//
				td.addElement(info);
				line.addElement(td);
			}   //  for all columns
			table.addElement(line);
		}   //  for all table lines

		ws.curTab.navigate( oldRow );
		
		//  Status Line
		String statusDB = String.valueOf(initRowNo+1) + "-" + String.valueOf(lastRow) + " # " + ws.curTab.getRowCount();
		
		return createLayout (action, table, wsc, ws, "", statusDB);
	}	//	getMR_Form

	/**
	 *  Create Window Layout.
	 *  @param action form action
	 *  @param contentTable content table
	 *  @param wsc web session context
	 *  @param ws window status
	 *  @param statusInfo status line info
	 *  @param statusDB status db info
	 *  @return Form
	 */
	private static WebDoc createLayout (String action, table contentTable, 
		WebSessionCtx wsc, WWindowStatus ws, String statusInfo, String statusDB)
	{
		div bodyDiv = (div)new div().setID("body"); //clmg 2009/02/10
		form myForm = null;
		myForm = new form(action);
		myForm.setTarget(WebEnv.TARGET_WINDOW);
		myForm.setID("WWindow" + ws.mWindow.getAD_Window_ID());
		String AD_Language = Env.getAD_Language(ws.ctx);

		//	Window
		myForm.setName(FORM_NAME);
		div hiddenDiv = (div)new div(); //clmg 2009/02/10
		myForm.addElement(hiddenDiv); //clmg 2009/02/10
		
		//clmg 2009/02/10
		hiddenDiv.addElement(new input("hidden", P_Command, ""));    //  button commands 
		hiddenDiv.addElement(new input("hidden", P_MR_RowNo, ""));   //  RowNo
//		myForm.addElement(new input("hidden", P_ChangedColumn, ""));    //
		hiddenDiv.addElement(new input("hidden", P_Reserve1, ""));    // Reserve 1
		hiddenDiv.addElement(new input("hidden", P_Reserve2, ""));    // Reserve 2
		hiddenDiv.addElement(new input("hidden", P_Reserve3, ""));    // Reserve 3
		
		//modi-by-clmg
		hiddenDiv.addElement((new input("hidden", P_ChangedColumn, "")).addAttribute("id", P_ChangedColumn));    //
		hiddenDiv.addElement(new input("hidden", Change_Flag, "").setID(Change_Flag));    //  button commands 
		//--

		//  Set Title of main window
		String title = ws.mWindow.getName() + " - " + wsc.loginInfo;
		hiddenDiv.addElement(new script("top.document.title='" + title + "';"));

		//	Buttons
		//clmg 2009/02/10
		//td toolbar = new td(null, AlignType.LEFT, AlignType.MIDDLE, true);
		td toolbarTd = new td(null, AlignType.LEFT, AlignType.MIDDLE, true);
		div toolbarDiv = (div)new div().setID("menu_icon");
		ul toolbar = new ul();
		toolbarTd.addElement(toolbarDiv);
		toolbarDiv.addElement(toolbar);
		//	Toolbar

		// 2006.03.16 ++ Shinjirito ++>>
		/*
		String menuSwitch = "HideMenu";
		String showTitle = Msg.getMsg(ws.ctx, "ShowMenu");
		String hideTitle = Msg.getMsg(ws.ctx, "HideMenu");;
		String s = null;
		if (ws != null && ws.ctx != null) {
			s = ws.ctx.getProperty("MenuOnOff");
			if (s != null) {
				menuSwitch = s;
			}
		}
		img menuImg = createImage(AD_Language, menuSwitch, "MenuOnOff", "menuSwitch('" + showTitle + "','" + hideTitle + "');", true, false);
		*/
//		toolbar.addElement(createImage(AD_Language, "MenuOnOff", "MenuOnOff", "menuSwitch();", true, false)); //clmg 2009/02
//		toolbar.addElement(WebEnv.NBSP); //clmg 2009/02/10
		toolbar.addElement(new li().addElement(createImage(AD_Language, "MenuOnOff", "MenuOnOff", "menuSwitch();", true, false)));
		// 2006.03.16 ++ Shinjirito ++<<

//		boolean needSave = (Env.getContextAsInt(wsc.ctx, ws.curTab.getWindowNo(), "NeedSave") == 0 ? false : true);
		boolean needSave = (wsc.ctx.getContextAsInt(ws.curTab.getWindowNo(), "NeedSave") == 0 ? false : true);
		boolean insertRecord = (! ws.curTab.isReadOnly());
		if (insertRecord) {
			insertRecord = ws.curTab.isInsertRecord();
		}

//		toolbar.addElement(createImage(AD_Language, "Ignore", "Ignore"));//clmg 2009/02
//		toolbar.addElement(WebEnv.NBSP);//clmg 2009/02
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Ignore", "Ignore")));//clmg 2009/02
		
//		toolbar.addElement(createImage(AD_Language, "Help", "Help",
//			"startPopup('WHelp?AD_Window_ID=" + ws.mWindow.getAD_Window_ID() + "');", true, false)); //clmg 2009/02
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Help", "Help",
				"startPopup('WHelp?AD_Window_ID=" + ws.mWindow.getAD_Window_ID() + "');", true, false)));//clmg 2009/02
		
//		toolbar.addElement(createImage(AD_Language, "New", "New", null, (! needSave && insertRecord), false));//clmg 2009/02
		toolbar.addElement(new li().addElement(createImage(AD_Language, "New", "New", 
				null, (! needSave && insertRecord), false)));//clmg 2009/02
		
//		toolbar.addElement(createImage(AD_Language, "Delete", "Delete",
//			"if (confirm(deleteText)) " + FORM_NAME + ".submit();", (! needSave && insertRecord), false));//clmg 2009/02
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Delete", "Delete",
				"if (confirm(deleteText)) " + FORM_NAME + ".submit();", (! needSave && insertRecord), false)));//clmg 2009/02
		
//		toolbar.addElement(createImage(AD_Language, "Save", "Save", "beforeSave(document." + FORM_NAME + ");", true, false));
//		toolbar.addElement(WebEnv.NBSP);//clmg 2009/02
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Save", 
				"Save", "beforeSave(document." + FORM_NAME + ");", true, false)));//clmg 2009/02
		
		// clmg 2009/03/06
		//		toolbar.addElement(createImage(AD_Language, "Refresh", "Refresh", null, ! needSave, false));
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Refresh", "Refresh", null, ! needSave, false)));
		
//		toolbar.addElement(createImage(AD_Language, "Find", "Find",
//				"openFindWindow('/compiere/ampiere/WFind\', '" + ws.curTab.getTableName() + "' );", 
//				true, false));//clmg 2009/02
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Find", "Find",
				"openFindWindow('/compiere/ampiere/WFind\', '" + ws.curTab.getTableName() + "' );", 
				true, false)));//clmg 2009/02
		

		
//		toolbar.addElement(createImage(AD_Language, "Attachment", "Attachment",
//			"startPopup('WAttachment');", 
//			ws.curTab.getCurrentRow() != -1 && ws.curTab.canHaveAttachment(), ws.curTab.hasAttachment()));//clmg 2009/02
		//clmg 2009/03/12
		boolean canHaveAttachment = ws.curTab.canHaveAttachment();
		if (ws.curTab.canHaveAttachment() && ws.curTab.getRecord_ID() == -1)    //	No Key
			canHaveAttachment = false; 
		
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Attachment", "Attachment",
				"startPopup('WAttachment');", 
				ws.curTab.getCurrentRow() != -1 && canHaveAttachment, ws.curTab.hasAttachment())));//clmg 2009/03/12
		
//		toolbar.addElement(createImage(AD_Language, "Multi", "Multi", null, true, !ws.curTab.isSingleRow()));
//		toolbar.addElement(WebEnv.NBSP);//clmg 2009/02
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Multi", "Multi", null, true, !ws.curTab.isSingleRow())));//clmg 2009/02
		
//		toolbar.addElement(createImage(AD_Language, "History", "History",
//				"openHistoryWindow('/compiere/ampiere/WHistory\', '" + ws.curTab.getTableName() + "' );", 
////				ws.mWindow.isTransaction()&&ws.curTab.getTabNo()==0, !ws.curTab.isOnlyCurrentRows()));
//				//TODO clmg
//				ws.mWindow.isTransaction()&&ws.curTab.getTabNo()==0, false));
		
		//clmg 2009/03/06 Historyはいらにぃ。 
//		toolbar.addElement(new li().addElement(createImage(AD_Language, "History", "History",
//				"openHistoryWindow('/compiere/ampiere/WHistory\', '" + ws.curTab.getTableName() + "' );", 
//				ws.mWindow.isTransaction()&&ws.curTab.getTabNo()==0, !ws.curTab.isOnlyCurrentRows()));
				//TODO clmg
//				ws.mWindow.isTransaction()&&ws.curTab.getTabNo()==0, false)));
		
//		toolbar.addElement(WebEnv.NBSP);
//		toolbar.addElement(createImage(AD_Language, "Report", "Report"));
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Report", "Report")));
		
		boolean isPrint = false;
		if ( ws.curTab.getAD_Process_ID() == 0 ) {
			isPrint = false;
		} else {
			isPrint = true;
		}
//		toolbar.addElement(createImage(AD_Language, "Print", "Print", null, isPrint, false));
//		toolbar.addElement(WebEnv.NBSP);
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Print", "Print", null, isPrint, false)));
		
//		toolbar.addElement(WebEnv.NBSP);//clmg 2009/02/10
		boolean isFirst = ws.curTab.getCurrentRow() < 1;
//		toolbar.addElement(createImage(AD_Language, "First", "First", null, !isFirst, false));
		toolbar.addElement(new li().addElement(createImage(AD_Language, "First", "First", null, !isFirst, false)));
		
//		toolbar.addElement(createImage(AD_Language, "Previous", "Previous", null, !isFirst, false));
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Previous", "Previous", null, !isFirst, false)));
		
		boolean isLast = ws.curTab.getCurrentRow()+1 == ws.curTab.getRowCount();
//		toolbar.addElement(createImage(AD_Language, "Next", "Next", null, !isLast, false));
//		toolbar.addElement(createImage(AD_Language, "Last", "Last", null, !isLast, false));
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Next", "Next", null, !isLast, false)));
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Last", "Last", null, !isLast, false)));
	

		

		// Add product lookup button
		String popupProduct = "startLookup(" + "'M_Product_ID'," + ws.mWindow.getWindowNo() + ", 3840, 'M_Product_ID', 'Y','');";
//		toolbar.addElement(createImage(AD_Language, "Product", "Product", popupProduct, true, false));
//		toolbar.addElement(WebEnv.NBSP);
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Product", "Product", popupProduct, true, false)));

//		toolbar.addElement(createImage(AD_Language, "Exit", "Exit"));
		toolbar.addElement(new li().addElement(createImage(AD_Language, "Exit", "Exit")));

		//  Tabs
		//clmg 2009/02/10
//		td tabbar = new td("tabHeader", AlignType.LEFT, AlignType.BOTTOM, false);
//		td tabbarTd = new td("tabHeader", AlignType.LEFT, AlignType.BOTTOM, false).setWidth("100%");
		div tabbar = (div)new div().setID("menu_tab");
//		tabbarTd.addElement(tabbar);
		//
		
		tabbar.addElement(new input(input.TYPE_HIDDEN, P_Tab, ""));

		// 2006.03.10 ++ Shinjirito ++>>
//		table tabTable = new table("0", "0", "0", null, null); //clmg 2009/02/10
		ul tabTable = new ul(); //clmg 2009/02/10
//		tr tabTr = new tr(); //clmg 2009/02/10
		boolean currentTab = false;
		// 2006.03.10 ++ Shinjirito ++<<

		for (int i = 0; i < ws.mWindow.getTabCount(); i++)
		{
			GridTab tab = ws.mWindow.getTab(i);
			if (tab.isSortTab())
				continue;

			// 2006.03.10 ++ Shinjirito ++>>
			String tabMouseOver = "";
			String tabMouseOut = "";
			String tabLeftId = "tabLeftId_" + Integer.toString(i);
			String tabRightId = "tabRightId_" + Integer.toString(i);
			String tabLeftClass = "tabLeft";
			String tabRightClass = "tabRight";
			// 2006.03.10 ++ Shinjirito ++<<

			span big = new span(tab.getName()); // clmg 2009/02/10
			if (ws.curTab.getTabNo() == i) {
				big.setClass("tabSelected");

				tabLeftClass += "Sel";
				tabRightClass += "Sel";
				currentTab = true;
			}
			else if (tab.getTabLevel() <= ws.curTab.getTabLevel() ||	// Same level / parent level
					(currentTab && tab.getTabLevel() == ws.curTab.getTabLevel() + 1))	// Child of current tab
			{
				big.setClass("tab");
//				big.setOnClick("document." + FORM_NAME + "." + P_Tab + ".value='" + i + "';" + FORM_NAME + ".submit();");
				big.setOnClick("beforeChangeTab('" + i + "');");//clmg 2009/03/24				

				tabMouseOver = "tabMouseOver('" + tabLeftId + "', '" + tabRightId + "');";
				tabMouseOut = "tabMouseOut('" + tabLeftId + "', '" + tabRightId + "');";
			}
			else
			{	// Grandson or under grandson level tab, disable it
				big.setClass("tabDisabled");
				tabLeftClass += "Dis";
				tabRightClass += "Dis";
			}
			if (ws.curTab.getTabNo() != i && currentTab && tab.getTabLevel() <= ws.curTab.getTabLevel()) {
				currentTab = false;
			}
			// 2006.03.10 -- Shinjirito -->>
			/*
			//  Status: Description
			if (tab.getDescription().length() > 0)
				big.setOnMouseOver("status='" + tab.getDescription() + "';return true;");

			tabbar.addElement(big);
			*/
			// 2006.03.10 -- Shinjirito --<<

			// 2006.03.10 ++ Shinjirito ++>>
			//clmg 2009/02/10
//			td tabTdLeft = new td(WebEnv.NBSP);
			span tabTdLeft = new span(WebEnv.NBSP);
			tabTdLeft.setClass(tabLeftClass);
//			tabTdLeft.setAlign(AlignType.CENTER);
//			tabTdLeft.setVAlign(AlignType.MIDDLE);
//			tabTdLeft.setNoWrap(false);
			//--
//			td tabTdRight = new td(tabRightClass, AlignType.CENTER, AlignType.MIDDLE, false); //clmg 2009/02/10
			li tabTdRight = (li)new li().setClass(tabRightClass); //clmg 2009/02/10
			tabTdLeft.setID(tabLeftId);
			tabTdRight.setID(tabRightId);
			if (tab.getDescription().length() > 0) {
				tabMouseOver += "status='" + tab.getDescription() + "';return true;";
			}
			if (tabMouseOver != null && ! "".equals(tabMouseOver)) {
				big.setOnMouseOver(tabMouseOver);
			}
			if (tabMouseOut != null && ! "".equals(tabMouseOut)) {
				tabMouseOut += "status='" + ws.curTab.getName() + "';return true;";
				big.setOnMouseOut(tabMouseOut);
			}
//			tabTdLeft.setStyle("");  //clmg 2009/02/10
//			tabTr.addElement(tabTdLeft); //clmg 2009/02/10
			tabTable.addElement(tabTdRight);//clmg 2009/02/10
			tabTdRight.addElement(tabTdLeft);//clmg 2009/02/10
			tabTdRight.addElement(big);
			tabTdRight.setStyle("");
//			tabTr.addElement(tabTdRight); //clmg 2009/02/10
			// 2006.03.10 ++ Shinjirito ++<<
		}

		// 2006.03.10 ++ Shinjirito ++>>
//		tabTable.addElement(tabTr); //clmg 2009/02/10
		//clmg 2009/02/10
		tabbar.addElement(tabTable);
//		tabbarTd.addElement(tabTable); //clmg 2009/02/10
		//--
		// 2006.03.10 ++ Shinjirito ++<<

		//	Top Table
		table topTable = (table)new table ("0", "0", "0", "100%", null).setStyle("margin:0 0 1em;"); //clmg 2009/02/16
//		table topTable = new table ().setWidth("100%"); //clmg 2009/02/10
		topTable.setID("WWindow.topTable");
		//clmg 2009/02/10
//		topTable.addElement(new tr(toolbar));
		topTable.addElement(new tr(toolbarTd));
//		topTable.addElement(new tr(tabbar));
		//
		myForm.addElement(topTable);
		myForm.addElement(tabbar); // clmg 2009/02/10
		
		//  Fields
		myForm.addElement(contentTable);

		//  Status Line
//		table statusTable = (table)new table ("0", "0", "0", "100%", null);//.setStyle("margin:0px"); //clmg 2009/02/10
		table statusTable = new table(); //clmg 2009/02/10
//		statusTable.setID("WWindow.statusLine");
		tr statusLine = new tr();
		//clmg 2009/02/10
//		statusLine.addElement(new td().setWidth("85%").setAlign(AlignType.LEFT)
//			.addElement(statusInfo));
//		statusLine.addElement(new td().setWidth("10%").setAlign(AlignType.RIGHT)
//			.addElement(new small(statusDB)));
//		statusLine.addElement(new td().setWidth("5%").setAlign(AlignType.RIGHT)
//			.addElement(createImage(AD_Language, "Save", "Save2", "beforeSave(document." + FORM_NAME + ");", true, false)));
//		statusTable.addElement(statusLine).setClass("windowCenter");
//		myForm.addElement(statusTable);
		
		div statusdiv = (div)new div().setClass("bottomMenuRight");
		td statusTd = new td();
		statusTd.addElement(new span().addElement(statusDB));
		statusTd.addElement(createImage(AD_Language, "Save", "Save2", "beforeSave(document." + FORM_NAME + ");", true, false).setHeight("27"));
		statusTd.addElement("&nbsp;&nbsp;&nbsp"); // TODO: clmg 2009/02/10. I do not know why this was happen. But space is required. 
		statusLine.addElement(statusTd);
		statusTable.addElement(statusLine);
		statusdiv.addElement(statusTable);
		//--
		
		//  fini
		/** @todo Dynamic Display */
	//	myForm.addElement(new script("dynDisplay(); createWCmd();"));   //  initial Display & set Cmd Window
		
		WebDoc doc = createPage(ws, wsc);

		// Add body onUnload event, close all popup window when unload 
		doc.getBody().setOnUnload("closeMyChildren();");

		bodyDiv.addElement(myForm); //clmg 2009/02/10	
		bodyDiv.addElement(statusdiv); // clmg 2009/02/10
		//	Main Table	
		doc.getTable().addElement(new tr()
			.addElement(
//				new td(null, AlignType.CENTER, AlignType.MIDDLE, //clmg 2009/02/10
					new td(null, AlignType.LEFT, AlignType.TOP, //clmg 2009/02/10 
//					true, myForm).setColSpan(2))); //clmg 2009/02/10
					true, bodyDiv))); //clmg 2009/02/10	
		//
		return doc;
	}   //  createLayout

	/**
	 *  Create Page.
	 *  - Set Header
	 *  @param ws status
	 *  @return WDoc page
	 */
	private static WebDoc createPage (WWindowStatus ws, WebSessionCtx wsc)
	{
		WebDoc doc = WebDoc.createWindow (ws.mWindow.getName());

		//doc.getHead().addElement(new link("css/displaytag.css", link.REL_STYLESHEET, link.TYPE_CSS));
		doc.getHead().addElement(new link("css/displaytagWithFixedWidth.css", link.REL_STYLESHEET, link.TYPE_CSS));
				
		// For date picker
		AmpiereUtil.addDatePicker(doc.getHead(), wsc);

//		if ( "Y".equals(Env.getContext( ws.ctx, ws.mWindow.getWindowNo(), "IsPrintStart" ) ) ) {
//			Env.setContext( wsc.ctx, ws.curTab.getWindowNo(), "IsPrintStart", false );
		if ( "Y".equals(ws.ctx.getContext( ws.mWindow.getWindowNo(), "IsPrintStart" ) ) ) {
			wsc.ctx.setContext( ws.curTab.getWindowNo(), "IsPrintStart", false );

			//	Create Process Instance
			MPInstance pInstance =
				new MPInstance(
						ws.ctx,
						ws.curTab.getAD_Process_ID(),
						ws.curTab.getRecord_ID()
						);

			if( !pInstance.save() ) {
				log.log(Level.SEVERE, "Instance run error." );
			}
//			Env.setContext( wsc.ctx, "AD_Process_ID", ws.curTab.getAD_Process_ID() );
//			Env.setContext( wsc.ctx, "AD_PInstance_ID", pInstance.getAD_PInstance_ID() );
			wsc.ctx.setContext( "AD_Process_ID", ws.curTab.getAD_Process_ID() );
			wsc.ctx.setContext( "AD_PInstance_ID", pInstance.getAD_PInstance_ID() );
			
			// For print popup window
			StringBuffer sb = new StringBuffer();
			sb.append( "openReportWindow(" )
			  .append( "\"/compiere/ampiere/WPrint\"," )
			  .append( "\"WPrint\" );" );
			doc.getHead().addElement(new script( sb.toString() ));
//		} else if ( "Y".equals(Env.getContext( ws.ctx, ws.curTab.getWindowNo(), "IsReportStart" ) ) ) {
//			Env.setContext( wsc.ctx, ws.curTab.getWindowNo(), "IsReportStart", false );
		} else if ( "Y".equals(ws.ctx.getContext( ws.curTab.getWindowNo(), "IsReportStart" ) ) ) {
			wsc.ctx.setContext( ws.curTab.getWindowNo(), "IsReportStart", false );
			// For print popup window
			StringBuffer sb = new StringBuffer();
			sb.append( "openReportWindow(" )
			  .append( "\"/compiere/ampiere/WReport\"," )
			  .append( "\"WReport\" );" );
			doc.getHead().addElement(new script( sb.toString() ));
		}

		//  Set Variables
		doc.getBody()
			.addElement(new script("deleteText='" + Msg.getMsg(ws.ctx, "DeleteRecord?") + "';"))
			.addElement(new script("saveErrorText='" + Msg.getMsg(ws.ctx, "SaveError") + "';"));
		//
		return doc;
	}   //  createPage

	
	/**************************************************************************
	 *  Create Image with name, id of button_name and set P_Command onClick
	 *  @param  AD_Language
	 *  @param  name        Name of the Image used also for Name24.gif
	 *  @param  js_command  Java script command, null results in 'submit();', an empty string disables OnClick
	 *  @param  enabled     Enable the immage button, if not uses the "D" image
	 *  @param  pressed     If true, use the "X" image
	 *  @return Image
	 */
	private static img createImage (String AD_Language, String name, String id, String js_command, boolean enabled, boolean pressed)
	{
		StringBuffer imgName = new StringBuffer(name);
		//modi-by-clmg TODO
//		if (!enabled)
//			imgName.append("D");
//		else if (pressed)
//			imgName.append("X");
//		imgName.append("24.gif");
		
		imgName.append("32.png");
		//
		//
		img img = new img (WebEnv.getImageDirectory(imgName.toString()), name);
		if (enabled){
			img.setAlt(Msg.getMsg(AD_Language, name));  //  Translate ToolTip
			img.setTitle(Msg.getMsg(AD_Language, name));  //  Translate ToolTip //clmg 2009/03/06
		}
			

		if (enabled) {
			if (!pressed) {
				img.setClass("imgButton");
			}
			else
			{
				img.setClass("imgButtonPressed");
			}
			img.setOnMouseOver("btnMouseOver('" + id + "');");
			img.setOnMouseOut("btnMouseOut('" + id + "');");
		} else {
			img.setClass("imgButtonD");
		}
		img.setID(id);
		img.setStyle("");

		if (js_command == null)
			js_command = FORM_NAME + ".submit();";
		if (js_command.length() > 0 && enabled)
			img.setOnClick("document." + FORM_NAME + "." + P_Command + ".value='" + name + "';" + js_command);
		//
		return img;
	}   //  createImage

	/**
	 *  Create enabled Image with name, id of button_name and sumbit command
	 *  @param  AD_Language
	 *  @param  name        Name of the Image used also for Name24.gif
	 *  @return Image
	 */
	private static img createImage (String AD_Language, String name, String id)
	{
		return createImage (AD_Language, name, id, null, true, false);
	}   //  createImage

	
	/**************************************************************************
	 *	Add Field to Line
	 *  @param wsc session context
	 *  @param line format element
	 *  @param field field
	 *  @param oData original data
	 *  @param hasDependents has Callout function(s)
	 */
	private void addField (WebSessionCtx wsc, tr line, GridField field, 
		Object oData, boolean hasDependents, boolean readOnly)
	{
		String columnName = field.getColumnName();
		//  Any Error?
		boolean error = field.isErrorValue();
		if (error)
			oData = field.getErrorValue();
		int dt = field.getDisplayType();
		boolean hasCallout = field.getCallout().length() > 0;

		/**
		 *  HTML Label Element
		 *      ID = ID_columnName
		 *
		 *  HTML Input Elements
		 *      NAME = columnName
		 *      ID = ID_columnName
		 */
		
		int display_length = field.getDisplayLength();
		if( display_length > 40 ){
			display_length = 48;
		} else {
			display_length = 20;			
		}
		
		WebField wField = new WebField (field.getWindowNo(), wsc,
			columnName, field.getHeader(), field.getDescription(),
			dt, field.getFieldLength(), display_length*12, field.isLongField(),
			// readOnly context check, mandatory no context check,  
			readOnly, field.isMandatory(false), error, 
			hasDependents, hasCallout, field.getAD_Process_ID(), field.isEncryptedField());

		line
			.addElement(wField.getLabel())
//			.addElement(wField.getField(field.getLookup(), oData, field.getAD_Column_ID()));
			.addElement(wField.getField(field.getLookupRefresh(), oData, field.getAD_Column_ID()));//clmg 2009/03/23
	}	//	addField
	
	
/**
 * field groupを追加する //clmg 2009/03/11
 * @param fieldGroup
 */
	private boolean isNewGroup(String fieldGroup)
	{
		boolean isnewgroup = false;
		if(m_oldFieldGroup == null){
			m_oldFieldGroup = "";
		}else if (fieldGroup == null || fieldGroup.length() == 0 || fieldGroup.equals(m_oldFieldGroup)){
			isnewgroup = false;
		}else if (!fieldGroup.equals(m_oldFieldGroup)){
			m_oldFieldGroup = fieldGroup;
			isnewgroup = true;
		}		
		return isnewgroup;
	}

	/**************************************************************************
	 * Start Button Process
	 * @param ws windows status
	 * @param wsc session context
	 * @param columnName column name
	 * @param processId process id
	 * @param batch true if background process
	 * @param value selected action value
	 */
	private void actionButton (WWindowStatus ws, WebSessionCtx wsc, String columnName, int processId, boolean batch, String value)
	{
		log.info("Process button : " + columnName + "  ProcessID : " + processId + "  Value : " + value);

		// save first	---------------
		// save it - of errors ignore changes
		if (ws.curTab.needSave(true, false)) {
			if (!ws.curTab.dataSave(true)) {
				ws.curTab.dataIgnore();
				log.log(Level.INFO, "Data save has been ignored.");
				return;
			}
		}

		int table_ID = ws.curTab.getAD_Table_ID();
		//	Record_ID
		int record_ID = ws.curTab.getRecord_ID();
		//	Record_ID - Language Handling
		if (record_ID == -1 && ws.curTab.getKeyColumnName().equals("AD_Language"))
//			record_ID = Env.getContextAsInt (wsc.ctx, ws.mWindow.getWindowNo(), "AD_Language_ID");
			record_ID = wsc.ctx.getContextAsInt (ws.mWindow.getWindowNo(), "AD_Language_ID");
		//	Record_ID - Change Log ID
		if (record_ID == -1 
			&& (processId == 306 || processId == 307))
		{
			Integer id = (Integer)ws.curTab.getValue("AD_ChangeLog_ID");
			record_ID = id.intValue();
		}
		//	Ensure it's saved
		if (record_ID == -1 && ws.curTab.getKeyColumnName().endsWith("_ID"))
		{
			// TODO show some error message
			log.log(Level.SEVERE, "SaveErrorRowNotFound");
			return;
		}

		/**
		 *  Start Process ----
		 */
		log.config("Process_ID=" + processId + ", Record_ID=" + record_ID);
		if (processId == 0) {
			return;
		}

		//	Save Selection
		if ("DocAction".equalsIgnoreCase(columnName)) {
			log.config("DocAction=" + value);
			Object orgValue = ws.curTab.getValue("DocAction");
			if (! value.equals(orgValue)) {
				ws.curTab.setValue("DocAction", value);
	
				if (ws.curTab.needSave(true, false)) {
					ws.curTab.dataSave(false);
				}
			}
		}

		//
		String title = columnName;
		ProcessInfo pi = new ProcessInfo(title, processId, table_ID, record_ID);
//		pi.setAD_User_ID (Env.getAD_User_ID(wsc.ctx));
//		pi.setAD_Client_ID (Env.getAD_Client_ID(wsc.ctx));
		pi.setAD_User_ID (wsc.ctx.getAD_User_ID());
		pi.setAD_Client_ID (wsc.ctx.getAD_Client_ID());
		pi.setIsBatch(batch);

		ProcessCtl processCtrl = ProcessCtl.getProcessInstance(ws.mWindow.getWindowNo(), pi, null, wsc.ctx);
		processCtrl.run();
		String summary = pi.getSummary();
		if (summary != null && summary.indexOf("@") != -1) {
			summary = Msg.parseTranslation(wsc.ctx, summary);
		}

		if (pi.isError()) {
			m_popupAlert = new StringBuffer();
			m_popupAlert.append(summary);
		}
	}	//	actionButton

	/**************************************************************************
	 *	Data Status Listener (row change)			^ | v
	 *  @param e event
	 */
	public void dataStatusChanged (DataStatusEvent e)
	{
		if (m_request == null) {
			return;
		}

		//  Confirm Error
		if ((e.isError() || e.isWarning()) && !e.isConfirmed())
		{
			WebSessionCtx wsc = WebSessionCtx.get(m_request);
			//	Set Message / Info
			StringBuffer sb = new StringBuffer();
			String msg = null;
			if (e.getAD_Message() != null || e.getInfo() != null)
			{
				msg = Msg.translate(wsc.ctx, e.getAD_Message());
				if (msg != null) {
					sb.append(msg);
				}
				String info = e.getInfo();
				if (info != null && info.length() > 0)
				{
					if (sb.length() > 0 && !sb.toString().trim().endsWith(":"))
						sb.append(": ");
					sb.append(info);
				}
				if (sb.length() > 0)
				{
					int pos = sb.indexOf("\n");
					if (pos != -1)  // replace CR/NL
						sb.replace(pos, pos+1, " - ");
				}
			}

			if (sb.length() > 0) {
				if (m_popupAlert != null) {
					if (msg != null && m_popupAlert.indexOf(msg) == -1) {
						m_popupAlert.append("\\n" + sb.toString());
					}
				} else {
					m_popupAlert = new StringBuffer();
					m_popupAlert.append(sb.toString());
				}
			}
			e.setConfirmed(true);   //  show just once - if MTable.setCurrentRow is involved the status event is re-issued
		}
	}	//	dataStatusChanged

	/**************************************************************************
	 *  Set Field New Value, and check lookup field
	 *  @param wsc web session
	 *  @param ws window status
	 *  @param mField field
	 *  @param value as Object
	 */
	private void setFieldNewValue (WebSessionCtx wsc, WWindowStatus ws, GridField mField, Object newValue)
	{
		if (mField.getDisplayType() == DisplayType.Search) {
//				mField.getDisplayType() == DisplayType.Location ||
//				mField.getDisplayType() == DisplayType.Account) {
			boolean popup = true;
			String columnName = mField.getColumnName();
			String values[] = m_request.getParameterValues(columnName);
			if (values != null && values.length == 2 && values[1].length() > 0) {
				NamePair np = null;
				if (values[0] != null && values[0].length() > 0) {
					try {
						int key = Integer.parseInt(values[0]);
						np = mField.getLookup().get(new Integer(key));
					} catch (Exception e) {
					}
				}
				String text = values[1].toUpperCase();
				String name = text;
				log.config(columnName + " - " + text);

				//	Exact first
				PreparedStatement pstmt = null;
				String finalSQL = Msg.parseTranslation(wsc.ctx, AmpiereUtil.getDirectAccessSQL(wsc.ctx, mField.getLookup(), columnName, 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(wsc.ctx, AmpiereUtil.getDirectAccessSQL(wsc.ctx, mField.getLookup(), columnName, 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)
				{
				}

				if (id <= 0 && np != null) {
					if (np.getName().equalsIgnoreCase(name)) {
						id = Integer.parseInt(np.getID());
					}
				}

				//	No (unique) result
				if (id <= 0)
				{
					if (id == -3)
						log.fine(columnName + " - Not Found - " + finalSQL);
					else
						log.fine(columnName + " - Not Unique - " + finalSQL);
				} else {
					log.fine(columnName + " - Unique ID=" + id);
					ws.curTab.setValue(mField, new Integer(id));
					popup = false;
				}

				if (popup) {
					// No (unique) result, open lookup window
					String col = mField.getLookup().getColumnName();
					if (col != null && col.indexOf(".") >= 0) {
						col = col.substring(col.indexOf(".") + 1);
					}
					String s = "startLookup('" + columnName + "'," + mField.getWindowNo() + "," + mField.getAD_Column_ID() + ",'" + col + "', 'N','" + values[1] + "');";
/*
					if (mField.getDisplayType() == DisplayType.Location) {
						s = "startLocation('" + columnName + "'," + mField.getWindowNo() + "," + mField.getAD_Column_ID() + ",'" + col + "','" + values[1] + "');";
					} else if (mField.getDisplayType() == DisplayType.Account) {
						s = "startAccount('" + columnName + "','" + values[1] + "');";
					} else {
						s = "startLookup('" + columnName + "'," + mField.getWindowNo() + "," + mField.getAD_Column_ID() + ",'" + col + "', 'N','" + values[1] + "');";
					}
*/
					m_popupLookup = s + "return false;";
				}
			}
		} else {
			ws.curTab.setValue(mField, newValue);
		}
	}   //  setFieldNewValue
    
    /**
     * Reset amount,price format.
     * @param wsc
     * @param ws
     */
    private void resetAmountformat(WebSessionCtx wsc, WWindowStatus ws) {
        GridField[] fields = ws.mWindow.getTab(0).getFields();
        int currencyId = 0;
        for (int i=0; i<fields.length; i++) {
            String fieldName = fields[i].getColumnName();
            if (fieldName.equals("C_Currency_ID") ) {
                if (fields[i].getValue() != null) {
                    currencyId = new Integer(fields[i].getValue().toString()).intValue();
                }
                break;
            }
        }
        
        if ( currencyId == 0 ) {
//            currencyId = Env.getContextAsInt(wsc.ctx, "$C_Currency_ID");
            currencyId = wsc.ctx.getContextAsInt("$C_Currency_ID");
        }
        
        MCurrency mCurrency = new MCurrency(wsc.ctx, currencyId, null);
        if ( mCurrency != null ) {
            wsc.amountFormat.setMinimumFractionDigits(mCurrency.getStdPrecision());
//            wsc.costPriceFormat.setMinimumFractionDigits(mCurrency.getStdPrecision());
        }
    }
    
    //modi-by-clmg
	/**************************************************************************
	 *	Return SingleRow Form details
	 *  @param action action
	 *  @param wsc web session context
	 *  @param ws window status
	 *  @return Form
	 *  今表示する必要ない項目をnone display で保持する。
	 */
	private WebDoc getSR_Form (String action, WebSessionCtx wsc, WWindowStatus ws)
	{
		log.fine("Tab=" + ws.curTab.getTabNo());

		/**********************
		 *  For all Fields
		 */
		table table = new table()
			.setAlign(AlignType.CENTER); 
//		table.setCellSpacing(0); //clmg 2009/02/10
//		table.setCellPadding(1); //clmg 2009/02/10
	//	table.setBorder(1).setBorderColor("#00FF00");	//	debug field lines
		StringBuffer scriptSrc = new StringBuffer();
		//modi by clmg
		StringBuffer scriptSrcHidden = new StringBuffer();
		//--modi
		//
		tr line = new tr();

//		if (ws.curTab.isDisplayed())
		//TODO clmg
		if (ws.curTab.isDisplayed(false))
		{
//			Env.setContext(wsc.ctx, ws.curTab.getWindowNo(), "Record_ID", ws.curTab.getRecord_ID());
			wsc.ctx.setContext(ws.curTab.getWindowNo(), "Record_ID", ws.curTab.getRecord_ID());
			int currentRow = ws.curTab.getCurrentRow();
			int noFields = ws.curTab.getFieldCount();
			for (int i = 0; i < noFields; i++)
			{
				GridField field = ws.curTab.getField(i);
				String columnName = field.getColumnName();

				/**
				 *  Get Data and convert to String (singleRow)
				 */
				Object oData = ws.curTab.getValue(field);

				
				/**
				 *  Display field
				 */
                if (!field.isSameLine())
                    line = new tr();
				if (field.isDisplayed(true))
				{
					// field group を追加。 //clmg 2009/03/12
					boolean isnewgroup = false;
					if(isNewGroup(field.getFieldGroup())){
						isnewgroup = true;
						line = new tr();
						line.addElement(new td().setColSpan(4).addElement(field.getFieldGroup()));
						table.addElement(line);
						line = new tr();
						line.addElement(new td().setColSpan(4).addElement(new hr()));
						table.addElement(line);
						
						line = new tr();
					}
					
					
					//
					boolean hasDependents = ws.curTab.hasDependants(columnName);
					boolean readOnly = (currentRow == -1 || ! field.isEditable(true));
					System.out.println("----begin--columnName="+columnName+",oData"+oData);					
					addField(wsc, line, field, oData, hasDependents, readOnly);
					System.out.println("---end--columnName="+columnName+",oData"+oData);
					table.addElement(line);
					//  Additional Values
					String dispLogic = field.getDisplayLogic();
					if (dispLogic != null && dispLogic.length() > 0)
					{
						dispLogic = dispLogic.replace('\'', '"');   //  replace ' with "
						dispLogic = dispLogic.replaceAll("\n", "");
						scriptSrc.append("document.").append(FORM_NAME)
							.append(".").append(columnName)
							.append(".displayLogic='").append(dispLogic).append("';\n");
					}
				}
				//DEBUG-CLMG, construct the html object even if this is not visible in current.
				else{
					//  Additional Values
					String dispLogic = field.getDisplayLogic();
					if (dispLogic != null && dispLogic.length() > 0)
					{
						boolean hasDependents = ws.curTab.hasDependants(columnName);
						boolean readOnly = (currentRow == -1 || ! field.isEditable(true));
						addField(wsc, line, field, oData, hasDependents, readOnly);
						table.addElement(line);
						
						dispLogic = dispLogic.replace('\'', '"');   //  replace ' with "
						dispLogic = dispLogic.replaceAll("\n", "");
						scriptSrc.append("document.").append(FORM_NAME)
							.append(".").append(columnName)
							.append(".displayLogic='").append(dispLogic).append("';\n");
						
						//get ID	
						int m_displayType = field.getDisplayType();
						String m_columnName = field.getColumnName();
						String htmlObjId = "";
						if (m_displayType == DisplayType.Search
								|| m_displayType == DisplayType.Location
								|| m_displayType == DisplayType.Account)
							{
								htmlObjId = (m_columnName + "D");
								scriptSrcHidden.append("Element.hide(\'").append(field.getColumnName()+"F")
								.append("\');\n");//clmg 2009/03/10
								scriptSrcHidden.append("Element.hide(\'").append(field.getColumnName()+"B")
								.append("\');\n");//clmg 2009/03/10
							} else {
								if (DisplayType.isLookup(m_displayType) 
									|| m_displayType == DisplayType.Locator) {
									htmlObjId = (m_columnName);
								} else if (m_displayType == DisplayType.YesNo) {
									htmlObjId = (m_columnName + "F");
								} else if (m_displayType == DisplayType.Button) {
									htmlObjId = (m_columnName);
								} else if (DisplayType.isDate(m_displayType)) {
									htmlObjId = (m_columnName + "F");
								} else if (DisplayType.isNumeric(m_displayType)) {
									htmlObjId = (m_columnName + "F");
								} else if (m_displayType == DisplayType.Text) {	// Strings
									htmlObjId = (m_columnName + "F");
								} else if (m_displayType == DisplayType.TextLong) {
									htmlObjId = (m_columnName + "F");
								} else if (m_displayType == DisplayType.Memo) {
									htmlObjId = (m_columnName + "F");
								} else {
									htmlObjId = (m_columnName + "F");
								}
							}

						scriptSrcHidden.append("Element.hide(\'").append(htmlObjId)
						.append("\');\n");	

						scriptSrcHidden.append("Element.hide(\'").append(field.getColumnName()+"L")
						.append("\');\n");

					}
					
				}
				//---
			}	//	for all fields
		}	//	displayed
		if (scriptSrc.length() > 0)
			table.addElement(new script(scriptSrcHidden.toString()));

		//modi-by-clmg
		table.addElement(new script(scriptSrc.toString()));
		//--
		
		//  Status Line
		int rowNo = ws.curTab.getCurrentRow();
		String statusDB = String.valueOf(rowNo+1) + " # " + ws.curTab.getRowCount();
		//
		return createLayout (action, table, wsc, ws, "", statusDB);
	}	//	getSR_Form
    //
	/**
	 * GridFieldによりhtml objectをゲットする。
	 * 主にはDisplayTypeにより、きめられること。
	 */
	private String getHtmlObjectName(GridField field){
		int m_displayType = field.getDisplayType();
		String m_columnName = field.getColumnName();
		String htmlObjId = "";
		if (m_displayType == DisplayType.Search
				|| m_displayType == DisplayType.Location
				|| m_displayType == DisplayType.Account)
			{
				htmlObjId = (m_columnName + "D");
			} else {
				if (DisplayType.isLookup(m_displayType) 
					|| m_displayType == DisplayType.Locator) {
					htmlObjId = (m_columnName);
				} else if (m_displayType == DisplayType.YesNo) {
					htmlObjId = (m_columnName + "F");
				} else if (m_displayType == DisplayType.Button) {
					htmlObjId = (m_columnName);
				} else if (DisplayType.isDate(m_displayType)) {
					htmlObjId = (m_columnName + "F");
				} else if (DisplayType.isNumeric(m_displayType)) {
					htmlObjId = (m_columnName + "F");
				} else if (m_displayType == DisplayType.Text) {	// Strings
					htmlObjId = (m_columnName + "F");
				} else if (m_displayType == DisplayType.TextLong) {
					htmlObjId = (m_columnName + "F");
				} else if (m_displayType == DisplayType.Memo) {
					htmlObjId = (m_columnName + "F");
				} else {
					htmlObjId = (m_columnName + "F");
				}
			}
		return htmlObjId;
	}
	/**
	 * GridFieldによりobjectの名前であるlabelをゲットする。
	 * 基本は、"L"を後ろにつけるだけ。
	 * @param field
	 * @return
	 */
	private String getHtmlObjectLabelName(GridField field){
		String m_columnName = field.getColumnName();
		String htmlObjId = "";
		htmlObjId = (m_columnName + "L");
		return htmlObjId;
	}
    
}   //  WWindow

