/*
 * @(#)HTMLFieldRendererImpl.java
 *
 * Copyright 1999-2002 by Oracle Corporation,
 * 500 Oracle Parkway, Redwood Shores, California, 94065, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of Oracle Corporation.
 */

package oracle.jdeveloper.html;

import com.sun.java.util.collections.HashMap;
import javax.servlet.jsp.PageContext;
import java.lang.reflect.Method;

import oracle.jbo.JboException;
import oracle.jbo.common.JBOClass;
import oracle.jbo.AttributeDef;
import oracle.jbo.AttributeHints;
import oracle.jbo.LocaleContext;
import oracle.jbo.Row;
import oracle.jbo.RowSet;
import oracle.jbo.html.DataSource;
import oracle.jbo.html.HtmlServices;

/**
 * This class provides a base implementation of the <tt>HTMLFieldRenderer</tt>
 * interface. Use this class as
 * the base class for any new field renderers.
 *
 *
 *
 **/
public abstract class HTMLFieldRendererImpl implements HTMLFieldRenderer
{
   protected   PageContext    page;
   protected   DataSource     ds;
   protected   AttributeDef   attrDef;
   protected   HashMap        htmlAttributes;
   protected   String         sPrompt;
   protected   String         sFormName;
   protected   LocaleContext  locale;
   
   public HTMLFieldRendererImpl()
   {
      htmlAttributes = new HashMap();
   }

   public void setPageContext(PageContext pageContext)
   {
      this.page = pageContext;
   }

   public PageContext getPageContext()
   {
      return page;
   }
   
   public void setDatasource(DataSource dataSource)
   {
      this.ds = dataSource;
      locale = ds.getApplicationModule().getSession().getLocaleContext();
   }

   public DataSource getDatasource()
   {
      return ds;
   }
   
   public void setAttributeDef(AttributeDef aDef)
   {
      this.attrDef = aDef;

      setFieldName(attrDef.getName());
      setCSSClassName("cls" + attrDef.getName());

      int maxLength;
      int maxWidth = -1;
      String hintWidth = null;
      
      AttributeHints hints = attrDef.getUIHelper();
      if (hints != null)
      {
         hintWidth = hints.getHintValue(locale, AttributeHints.ATTRIBUTE_CTL_DISPLAYWIDTH);
      }

      // Honor hint value only if it has been set.
      if (hintWidth != null)
      {
         maxWidth = Integer.parseInt(hintWidth);
      }

      if (attrDef.getPrecision() == 0)
      {
         // it's probably a date field
         maxLength = 10;
         if (hintWidth == null)
         {
            maxWidth = 11;
         }
      }
      else
      {
         maxLength = attrDef.getPrecision();

         if (attrDef.getScale() > 0)
            maxLength += 1;

         if (hintWidth == null)
         {
            if (attrDef.getPrecision() > 70)
            {
               maxWidth = 70;
            }
            else
            {
               maxWidth = attrDef.getPrecision() + 5;
            }
         }
      }

      setDisplayWidth(maxWidth);
      
      // Do not set the maxLength when formating is involved because we don't know
      // how long it could be
      if (hints == null || !hints.hasFormatInformation(locale))
      {
         setMaxDataLength(maxLength);
      }
   }
   
   public AttributeDef getAttributeDef()
   {
      return attrDef;
   }
   
   /**
   *	Sets this FORM field's name. This will be the name of the input parameter
   *   when the HTML form is submitted.
   * <p>
   * @param sName name of this FORM field.
   */
   public void setFieldName(String sName)
   {
      htmlAttributes.put("NAME", sName);
   }

   /**
   *	Gets this FORM field's name. This will be the name of the input parameter
   *   when the HTML form is submitted.
   * <p>
   * @return this FORM field's name.
   */ 
   public String getFieldName()
   {
      return (String)htmlAttributes.get("NAME");
   }

   /**
   *	Sets the display width, in characters, of this field.
   * <p>
   * @param nWidth the display width, in characters.
   */
   public void setDisplayWidth(int nWidth)
   {
      if (nWidth < 0)
      {
         htmlAttributes.remove("SIZE");
      }
      else
      {
         htmlAttributes.put("SIZE", Integer.toString(nWidth));
      }
   }

   /**
   *	Gets the display width, in characters, of this field.
   * <P>
   * @return the display width, in characters.
   */
   public int  getDisplayWidth()
   {
      String size = (String)htmlAttributes.get("SIZE");
      if (size == null)
      {
         return -1;
      }
      
      try
      {
         return Integer.parseInt(size);
      }
      catch (NumberFormatException ex)
      {
         return -1;
      }
      
   }

   /**
   *	Sets the display height, in characters, of this field.
   *  Used for TextArea only.
   * <p>
   * @param nHeight the display height, in characters.
   */
   public void  setDisplayHeight(int nHeight)
   {
      if (nHeight < 0)
      {
         htmlAttributes.remove("ROWS");
      }
      else
      {
         htmlAttributes.put("ROWS", Integer.toString(nHeight));
      }
   }

   /**
   *	Gets the display height, in characters, of this field.
   * <p>
   * @return the display height, in characters.
   */ 
   public int getDisplayHeight()
   {
      String rows = (String)htmlAttributes.get("ROWS");
      if (rows == null)
      {
         return 1;
      }
      
      try
      {
         return Integer.parseInt(rows);
      }
      catch (NumberFormatException ex)
      {
         return 1;
      }
   }

   /**
   *	Sets the maximum input length, in characters, of this field. The user will
   * not be able to enter more than <tt>nLength</tt> characters.
   * <p>
   * @param nLength the maximum input length, in characters.
   */
   public void setMaxDataLength(int nLength)
   {
      if (nLength < 0)
      {
         htmlAttributes.remove("MAXLENGTH");
      }
      else
      {
         htmlAttributes.put("MAXLENGTH", Integer.toString(nLength));
      }
   }

   /**
   * Gets the maximum input length, in characters, of this field. This is the maximum
   * number of characters the user can enter in the field.
   * <p>
   *	@return the maximum input length, in characters.
   */
   public int  getMaxDataLength()
   {
      String sLength = (String)htmlAttributes.get("MAXLENGTH");

      if (sLength == null)
      {
         return -1;
      }

      try
      {
         return Integer.parseInt(sLength);
      }
      catch (NumberFormatException ex)
      {
         return -1;
      }
   }

   public void setHtmlAttributes(HashMap attrs)
   {
      htmlAttributes.putAll(attrs); 
   }

   /**
   *	Sets the prompt to be displayed next to this input field.
   * <p>
   * @param sPrompt the prompt for this input field.
   */ 
   public void setPromptText(String sPrompt)
   {
      this.sPrompt = sPrompt;
   }

   /**
   *	Gets the prompt to be displayed next to this input field.
   * <p>
   * @return the prompt displayed next to this input field.
   */ 
   public String getPromptText()
   {
      if (sPrompt == null && ds != null && attrDef != null)
      {
         sPrompt = ds.getAttributeLabel(attrDef);
      }
      
      return sPrompt;
   }

   /**
   *	Sets the CSS (cascading style sheet) class name to be used by this field. You
   * can the use this class name
   * in your CSS file to change the visual attributes of the field.
   * <p>
   * @param sClass the class name of the CSS.
   */ 
   public void setCSSClassName(String sClass)
   {
      htmlAttributes.put("CLASS", sClass);
   }

   /**
   * Gets the name of the CSS (cascading style sheet) used by this field.
   * <p>
   *	@return the class name of the CSS.
   */ 
   public String getCSSClassName()
   {
      return (String)htmlAttributes.get("CLASS");
   }

   /**
   * Sets this field's current value.
   * <p>
   * @param sValue current value of this field.
   */ 
   public void setValue(String value)
   {
      htmlAttributes.put("VALUE", value);
   }
   
   /**
   * Gets this field's current value.
   *	<p>
   * @return this field's current value.
   */ 
   public String getValue()
   {
      return (String)htmlAttributes.get("VALUE");
   }

   // HTMLRenderingContext implementation
   public void setFormName(String sFormName)
   {
      this.sFormName = sFormName;
   }

   public String getFormName()
   {
      return this.sFormName;
   }

   protected Object lookup(String name, String property, String scope)
   {
      try
      {
         Class cls = JBOClass.forName("org.apache.struts.util.RequestUtils");
      
         Method lookup = cls.getMethod("lookup", new Class[]{ PageContext.class, String.class, String.class, String.class });
         return lookup.invoke(null, new Object[]{ page, name, property, scope });
      }
      catch (java.lang.ClassNotFoundException ex)
      {
         throw new JboException(ex.getMessage());
      }
      catch (java.lang.NoSuchMethodException ex)
      {
         throw new JboException(ex.getMessage());
      }
      catch (java.lang.reflect.InvocationTargetException ex)
      {
         throw new JboException(ex.getMessage());
      }
      catch (java.lang.IllegalAccessException ex)
      {
         throw new JboException(ex.getMessage());
      }
   }
   
   // Use (RowSet, attributeName)
   protected String getHTMLValue(Row row, RowSet rs, String attrName)
   {
      return getHTMLValue(row, rs.getViewObject().findAttributeDef(attrName));
   }
   
   // Use attributeDef member
   protected String getHTMLValue(Row row)
   {
      return getHTMLValue(row, attrDef);
   }

   // Return a String representation for HTML of the attribute value
   private String getHTMLValue(Row row, AttributeDef aDef)
   {
      if (row == null)
      {
         // Use BEAN_KEY = org.apache.struts.taglib.html.BEAN
         // We know the bean always return a String
         return (String) lookup("org.apache.struts.taglib.html.BEAN", aDef.getName(), null);
      }
      else
      {
         return HtmlServices.getAttributeStringValue(row, aDef, locale);
      }
   }
   
   protected void setValueFromRow(Row row)
   {
      // If the value is already set, it mean the default behavior need
      // to be overwritten so we keep this value.
      if (getValue() == null)
      {
         setValue(getHTMLValue(row));
      }
   }

   protected HTMLInputElement getHiddenFieldForValue()
   {
      return HTMLInputElement.getHidden(HtmlServices.getHiddenAttributeName(getFieldName()), getValue());
   }
}
