/*
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * (the "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
 * 
 * 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 the Venice Web Communities System.
 * 
 * The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
 * for Silverwrist Design Studios.  Portions created by Eric J. Bowersox are
 * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.dynamo.dialog;

import java.io.*;
import java.util.*;
import org.w3c.dom.*;
import com.silverwrist.util.xml.*;
import com.silverwrist.dynamo.except.*;
import com.silverwrist.dynamo.iface.*;
import com.silverwrist.dynamo.util.*;

class IntegerField extends CommonTextField
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  private static final double LN10 = Math.log(10.0);

  /*--------------------------------------------------------------------------------
   * Attributes
   *--------------------------------------------------------------------------------
   */

  private int m_min_value;
  private int m_max_value;

  /*--------------------------------------------------------------------------------
   * Constructors
   *--------------------------------------------------------------------------------
   */

  IntegerField(Element elt) throws DialogException
  {
    super("text",numDigits(elt),elt);
    XMLLoader loader = XMLLoader.get();
    DOMElementHelper h = new DOMElementHelper(elt);
    int min = Integer.MIN_VALUE;
    int max = Integer.MAX_VALUE;
    try
    { // get the min and max values from the config item
      if (h.hasAttribute("min"))
	min = loader.getAttributeInt(elt,"min");
      if (h.hasAttribute("max"))
	max = loader.getAttributeInt(elt,"max");

    } // end try
    catch (XMLLoadException e)
    { // translate the exception
      throw new DialogException(e);

    } // end catch

    if (max<min)
    { // assign the values the "wrong" way round
      m_min_value = max;
      m_max_value = min;

    } // end if
    else
    { // assign the values normally
      m_min_value = min;
      m_max_value = max;

    } // end else

  } // end elt

  protected IntegerField(IntegerField other)
  {
    super(other);
    m_min_value = other.m_min_value;
    m_max_value = other.m_max_value;

  } // end constructor

  /*--------------------------------------------------------------------------------
   * Internal operations
   *--------------------------------------------------------------------------------
   */

  private static final int numDigits(int v)
  {
    if (v==0)
      return 1;
    else if (v>0)
      return 1 + (int)(Math.floor(Math.log((double)v) / LN10));
    else
      return 2 + (int)(Math.floor(Math.log((double)(-v)) / LN10));

  } // end numDigits

  private static final int numDigits(int min, int max)
  {
    return Math.max(numDigits(min),numDigits(max));

  } // end numDigits

  private static final int numDigits(Element elt) throws DialogException
  {
    XMLLoader loader = XMLLoader.get();
    DOMElementHelper h = new DOMElementHelper(elt);
    int min = Integer.MIN_VALUE;
    int max = Integer.MAX_VALUE;
    try
    { // get the min and max values from the config item
      if (h.hasAttribute("min"))
	min = loader.getAttributeInt(elt,"min");
      if (h.hasAttribute("max"))
	max = loader.getAttributeInt(elt,"max");

    } // end try
    catch (XMLLoadException e)
    { // translate the exception
      throw new DialogException(e);

    } // end catch

    return numDigits(min,max);

  } // end numDigits

  /*--------------------------------------------------------------------------------
   * Abstract implementations from class BaseDialogField
   *--------------------------------------------------------------------------------
   */

  public Object clone()
  {
    return new IntegerField(this);

  } // end clone

  /*--------------------------------------------------------------------------------
   * Overrides from class CommonDialogField
   *--------------------------------------------------------------------------------
   */

  protected void renderField(TextRenderControl control, Map render_params)
      throws IOException, RenderingException
  {
    super.renderField(control,render_params);
    PrintWriter wr = control.getWriter();
    wr.write("&nbsp;(" + m_min_value + " - " + m_max_value + ")");

  } // end renderField

  protected void validateContents(Request r, Object data) throws ValidationException
  {
    if (data==null)
      return;
    try
    { // convert to an integer and chack against range
      int x = Integer.parseInt(data.toString());
      if ((m_min_value>Integer.MIN_VALUE) && (x<m_min_value))
      { // value is too small
	ValidationException ve = new ValidationException(IntegerField.class,"DialogMessages","int.tooSmall");
	ve.setParameter(0,getCaption());
	ve.setParameter(1,String.valueOf(m_min_value));
	throw ve;

      } // end if

      if ((m_max_value<Integer.MAX_VALUE) && (x>m_max_value))
      { // value is too large
	ValidationException ve = new ValidationException(IntegerField.class,"DialogMessages","int.tooLarge");
	ve.setParameter(0,getCaption());
	ve.setParameter(1,String.valueOf(m_max_value));
	throw ve;

      } // end if

    } // end try
    catch (NumberFormatException e)
    { // integer conversion failed - throw an error
      ValidationException ve = new ValidationException(IntegerField.class,"DialogMessages","text.notInteger");
      ve.setParameter(0,getCaption());
      throw ve;

    } // end catch

  } // end validateContents

  public Object getValue()
  {
    String s = (String)(super.getValue());
    if (s==null)
      return null;

    try
    { // map the return value to an Integer
      return new Integer(s);

    } // end try
    catch (NumberFormatException e)
    { // this is not supposed to happen
      throw new IllegalStateException("IntegerField.getValue(): value is not an integer!");

    } // end catch

  } // end getValue

  public boolean containsValue()
  {
    return (super.getValue()!=null);

  } // end containsValue

  public void setValue(Object obj)
  {
    if (obj==null)
    { // deal with null values early
      super.setValue(null);
      return;

    } // end if

    int real_val;
    if (obj instanceof Number)
      real_val = ((Number)obj).intValue();
    else
    { // convert the value to a string, then to integer
      try
      { // perform the conversion
	real_val = Integer.parseInt(obj.toString());

      } // end try
      catch (NumberFormatException e)
      { // just use a sensible default
	real_val = m_min_value;

      } // end catch

    } // end else

    // Constrain the value.
    if (real_val<m_min_value)
      real_val = m_min_value;
    else if (real_val>m_max_value)
      real_val = m_max_value;

    // Now actually set it.
    super.setValue(String.valueOf(real_val));

  } // end setValue

  public void setValueFrom(Request r)
  {
    RequestHelper rh = new RequestHelper(r);
    this.setValue(rh.getParameterString(getName()));

  } // end setValueFrom

} // end class IntegerField
