/*
 * 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 Community 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) 2001 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.venice.servlets.format;

import java.util.*;
import java.io.Writer;
import java.io.IOException;
import javax.servlet.ServletRequest;
import com.silverwrist.util.StringUtil;
import com.silverwrist.venice.except.ValidationException;

public class ContentDialog implements Cloneable, ContentRender, ColorSelectors
{
  /*--------------------------------------------------------------------------------
   * Attributes
   *--------------------------------------------------------------------------------
   */

  private String title;                   // dialog title
  private String subtitle;                // dialog subtitle
  private String formname;                // name of the built-in form
  private String action;                  // action applet
  private String error_message = null;    // error message
  private String instructions = null;     // instructions
  private Hashtable hidden_fields;        // list of all hidden fields & values
  private Hashtable command_buttons;      // command buttons by name
  private Vector command_order;           // command buttons in order (left to right)
  private Hashtable form_fields;          // form fields by name
  private Vector form_order;              // form fields in order (top to bottom)

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

  public ContentDialog(String title, String subtitle, String formname, String action)
  {
    this.title = title;
    this.subtitle = subtitle;
    this.formname = formname;
    this.action = action;
    hidden_fields = new Hashtable();
    command_buttons = new Hashtable();
    command_order = new Vector();
    form_fields = new Hashtable();
    form_order = new Vector();

  } // end constructor

  protected ContentDialog(ContentDialog other)
  {
    this.title = other.title;
    this.subtitle = other.subtitle;
    this.formname = other.formname;
    this.action = other.action;
    this.instructions = other.instructions;
    this.hidden_fields = (Hashtable)(other.hidden_fields.clone());
    command_buttons = new Hashtable();
    command_order = new Vector();
    form_fields = new Hashtable();
    form_order = new Vector();

    Enumeration enum = other.command_order.elements();
    while (enum.hasMoreElements())
    { // share the command buttons with the new dialog
      CDCommandButton button = (CDCommandButton)(enum.nextElement());
      addCommandButton(button);

    } // end while

    enum = other.form_order.elements();
    while (enum.hasMoreElements())
    { // clone the form fields and put them in the new dialog
      CDFormField field = (CDFormField)(enum.nextElement());
      addFormField(field.duplicate());

    } // end while

  } // end constructor

  /*--------------------------------------------------------------------------------
   * Internal functions
   *--------------------------------------------------------------------------------
   */

  private boolean anyRequired()
  {
    boolean rc = false;
    Enumeration enum = form_order.elements();
    while (!rc && enum.hasMoreElements())
    { // look for the first field that's marked "required"
      CDFormField fld = (CDFormField)(enum.nextElement());
      rc = fld.isRequired();

    } // end while

    return rc;

  } // end anyRequired

  /*--------------------------------------------------------------------------------
   * Overrideable operations
   *--------------------------------------------------------------------------------
   */

  protected void validateWholeForm() throws ValidationException
  { // do nothing at this level
  } // end validateWholeForm

  /*--------------------------------------------------------------------------------
   * Implementations from interface VeniceContent
   *--------------------------------------------------------------------------------
   */

  public String getPageTitle(RenderData rdat)
  {
    return title;

  } // end getPageTitle

  public String getPageQID()
  {
    return null;

  } // end getPageQID

  /*--------------------------------------------------------------------------------
   * Implementations from interface ContentRender
   *--------------------------------------------------------------------------------
   */

  public void renderHere(Writer out, RenderData rdat) throws IOException
  {
    Enumeration enum;

    // Output the content header
    rdat.writeContentHeader(out,title,subtitle);

    if (error_message!=null)
    { // print the error message
      out.write("<TABLE BORDER=0 ALIGN=CENTER CELLPADDING=6 CELLSPACING=0><TR VALIGN=TOP>"
		+ "<TD ALIGN=CENTER CLASS=\"content\">\n" + rdat.getStdFontTag(CONTENT_ERROR,3) + "<B>");
      out.write(StringUtil.encodeHTML(error_message));
      out.write("</B></FONT>\n</TD></TR></TABLE>\n");

    } // end if

    // Output the start of the form
    out.write("<FORM NAME=\"" + formname + "\" METHOD=POST ACTION=\"" + rdat.getEncodedServletPath(action)
	      + "\"><DIV CLASS=\"content\">" + rdat.getStdFontTag(CONTENT_FOREGROUND,2) + "\n");

    enum = hidden_fields.keys();
    while (enum.hasMoreElements())
    { // output all the hidden fields
      String name = (String)(enum.nextElement());
      String value = (String)(hidden_fields.get(name));
      out.write("<INPUT TYPE=HIDDEN NAME=\"" + name + "\" VALUE=\"" + value + "\">\n");

    } // end while

    if (instructions!=null)
      out.write(StringUtil.encodeHTML(instructions));
    if (anyRequired())
    { // print the "required fields" instruction
      if (instructions!=null)
	out.write("<P>");
      out.write("Required fields are marked with a " + rdat.getRequiredBullet() + ".<BR>\n");

    } // end if
    else if (instructions!=null)
      out.write("<BR>\n");

    out.write("<TABLE BORDER=0 ALIGN=CENTER CELLPADDING=6 CELLSPACING=0>\n");

    if (form_order.size()>0)
    { // render the form elements now
      enum = form_order.elements();
      while (enum.hasMoreElements())
      { // render all the fields in order
	CDFormField fld = (CDFormField)(enum.nextElement());
	fld.renderHere(out,rdat);

      } // end while

    } // end if

    out.write("</TABLE>\n");

    if (command_order.size()>0)
    { // render the command buttons at the bottom
      boolean is_first = true;
      out.write("<DIV ALIGN=CENTER CLASS=\"content\">");
      enum = command_order.elements();
      while (enum.hasMoreElements())
      { // render each of the command buttons in the list
	CDCommandButton button = (CDCommandButton)(enum.nextElement());
	if (is_first)
	  is_first = false;
	else
	  out.write("&nbsp;&nbsp;");
	button.renderHere(out,rdat);

      } // end while

      out.write("</DIV>\n");

    } // end if

    out.write("</FONT></DIV></FORM>\n");

  } // end renderHere

  /*--------------------------------------------------------------------------------
   * Operations usable only from derived classes
   *--------------------------------------------------------------------------------
   */

  protected CDFormField modifyField(String name)
  {
    return (CDFormField)(form_fields.get(name));
    
  } // end modifyField

  /*--------------------------------------------------------------------------------
   * External operations
   *--------------------------------------------------------------------------------
   */

  public void setTitle(String title)
  {
    this.title = title;

  } // end setTitle

  public void setSubtitle(String subtitle)
  {
    this.subtitle = subtitle;

  } // end setSubtitle

  public void setErrorMessage(String message)
  {
    this.error_message = message;

  } // end setErrorMessage

  public void setInstructions(String instructions)
  {
    this.instructions = StringUtil.encodeHTML(instructions);

  } // end setInstructions

  public void setHiddenField(String name, String value)
  {
    if (value!=null)
      hidden_fields.put(name,value);

  } // end setHiddenField

  public void removeHiddenField(String name)
  {
    hidden_fields.remove(name);

  } // end removeHiddenField

  public void addCommandButton(CDCommandButton button, int position)
  {
    command_buttons.put(button.getName(),button);
    if (position<0)
      command_order.addElement(button);
    else
      command_order.insertElementAt(button,position);

  } // end addCommandButton

  public void addCommandButton(CDCommandButton button)
  {
    addCommandButton(button,-1);

  } // end addCommandButton

  public void addFormField(CDFormField field, int position)
  {
    String name = field.getName();
    if (name!=null)
      form_fields.put(name,field);
    if (position<0)
      form_order.addElement(field);
    else
      form_order.insertElementAt(field,position);

  } // end addFormField

  public void addFormField(CDFormField field)
  {
    addFormField(field,-1);

  } // end addFormField

  public boolean isButtonClicked(ServletRequest request, String name)
  {
    CDCommandButton button = (CDCommandButton)(command_buttons.get(name));
    if (button!=null)
      return button.isClicked(request);

    // now look in all form fields for the embedded button
    Enumeration enum = form_order.elements();
    while (enum.hasMoreElements())
    { // zap the state of the fields
      CDFormField fld = (CDFormField)(enum.nextElement());
      button = fld.findButton(name);
      if (button!=null)
	return button.isClicked(request);

    } // end while

    return false;

  } // end isButtonClicked

  public void loadValues(ServletRequest request)
  {
    // Look for the values of the hidden fields first.
    Enumeration enum = hidden_fields.keys();
    Hashtable updates = new Hashtable();
    while (enum.hasMoreElements())
    { // get updates to the hidden field values
      String name = (String)(enum.nextElement());
      String value = request.getParameter(name);
      if (value!=null)
	updates.put(name,value);
    
    } // end while

    hidden_fields.putAll(updates);  // make all the updates be recognized

    // Now look for the values of the form fields.
    enum = form_order.elements();
    while (enum.hasMoreElements())
    { // look for the first field that's marked "required"
      CDFormField fld = (CDFormField)(enum.nextElement());
      String name = fld.getName();
      if (name!=null)  // load the parameter value
	fld.setValue(request.getParameter(name));

    } // end while

  } // end loadValues

  public void clearAllFields()
  {
    Enumeration enum = form_order.elements();
    while (enum.hasMoreElements())
    { // zap the state of the fields
      CDFormField fld = (CDFormField)(enum.nextElement());
      fld.setValue(null);

    } // end while

  } // end clearAllFields

  public String getFieldValue(String fieldname)
  {
    String value = (String)(hidden_fields.get(fieldname));
    if (value!=null)
      return value;

    CDFormField fld = (CDFormField)(form_fields.get(fieldname));
    if (fld!=null)
      return fld.getValue();
    else
      return null;

  } // end getFieldValue

  public void setFieldValue(String fieldname, String value)
  {
    CDFormField fld = (CDFormField)(form_fields.get(fieldname));
    if (fld!=null)
      fld.setValue(value);
    else if (value!=null)
      setHiddenField(fieldname,value);

  } // end setFieldValue

  public Object getFieldObjValue(String fieldname)
  {
    String value = (String)(hidden_fields.get(fieldname));
    if (value!=null)
      return value;

    CDFormField fld = (CDFormField)(form_fields.get(fieldname));
    if (fld!=null)
      return fld.getObjValue();
    else
      return null;

  } // end getFieldObjValue

  public void setFieldObjValue(String fieldname, Object value)
  {
    CDFormField fld = (CDFormField)(form_fields.get(fieldname));
    if (fld!=null)
      fld.setObjValue(value);
    else if (value!=null)
      setHiddenField(fieldname,value.toString());

  } // end setFieldObjValue

  public boolean isFieldEnabled(String fieldname)
  {
    CDFormField fld = (CDFormField)(form_fields.get(fieldname));
    if (fld!=null)
      return fld.isEnabled();
    else
      return false;

  } // end isFieldEnabled

  public void setFieldEnabled(String fieldname, boolean flag)
  {
    CDFormField fld = (CDFormField)(form_fields.get(fieldname));
    if (fld!=null)
      fld.setEnabled(flag);

  } // end setFieldEnabled

  public void validate() throws ValidationException
  {
    // validate each field in isolation
    Enumeration enum = form_order.elements();
    while (enum.hasMoreElements())
    { // look for the first field that's marked "required"
      CDFormField fld = (CDFormField)(enum.nextElement());
      fld.validate();

    } // end while

    // now validate the form as a whole
    validateWholeForm();

  } // end validate

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

  } // end clone

} // end class Dialog
