/*
 * 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@ricochet.com>,
 * for Silverwrist Design Studios.  Portions created by Eric J. Bowersox are
 * Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.venice.ui.config;

import java.io.*;
import java.util.*;
import org.apache.log4j.*;
import org.w3c.dom.*;
import com.silverwrist.util.*;
import com.silverwrist.venice.core.CommunityContext;
import com.silverwrist.venice.except.*;
import com.silverwrist.venice.ui.*;
import com.silverwrist.venice.ui.dlg.Dialog;
import com.silverwrist.venice.ui.menus.CommunityMenu;
import com.silverwrist.venice.ui.menus.CommunityMenuFactory;
import com.silverwrist.venice.ui.menus.Menu;
import com.silverwrist.venice.ui.menus.MenuComponent;
import com.silverwrist.venice.ui.menus.MenuTemplate;
import com.silverwrist.venice.ui.rpc.XmlRpcMethod;
import com.silverwrist.venice.util.*;

public class RootConfig implements LinkTypes, ColorSelectors
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  private static final String VENICE_URL = "http://venice.sourceforge.net";
  private static final String VENICE_IMAGE = "powered-by-venice.gif";
  private static final int VENICE_IMAGE_WIDTH = 129;
  private static final int VENICE_IMAGE_HEIGHT = 103;
  private static final String VENICE_ALT = "Powered By Venice";

  private static Logger logger = Logger.getLogger(RootConfig.class);

  private static final Map s_link_types;

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

  private String m_script_directory;       // the scripts directory
  private String m_rpc_script_directory;   // the RPC scripts directory
  private String m_temp_directory;         // the temporary directory
  private String m_template_directory;     // the Velocity templates directory
  private String m_image_path;             // the images path
  private String m_static_path;            // the static files path
  private String m_external_static_path;   // the external static files path
  private String m_format_path;            // the JSP formatter path
  private String m_blank_photo_path;       // the "photo not available" path
  private Properties m_properties;         // the property list
  private String m_frame_jsp_name;         // the name of the frame JSP
  private String m_site_title;             // the title for the site
  private File stylesheet;                 // the stylesheet file reference
  private long stylesheet_lastchange;      // when was the stylesheet last changed?
  private boolean smart_tags;              // do we want to allow M$ IE6 Smart Tags?
  private String site_logo_img_tag;        // the <IMG> tag containing the site logo
  private String site_logo_href = null;    // the HREF to surround the site logo with
  private int site_logo_href_type = -1;    // the type of the above href
  private String venice_logo_tag;          // the HTML snippet containing the Venice logo
  private String m_page_icon_tags = null;  // the HTML snippet containing the page icons
  private String m_font_face;              // the default font face name
  private String m_base_font;              // the default <BASEFONT> tag
  private Map m_font_sizes;                // the stock font sizes
  private ColorPalette m_colors;             // all the colors
  private boolean html_comments;           // do we want to embed HTML comments?
  private ButtonHolder buttons;            // the button definitions
  private String[] content_hdr;            // the content header parts
  private Remapper remapper;               // the URL remapper
  private int m_rpc_timeout = 60;          // RPC session timeout
  private List m_xmlrpc_methods;           // the list of XML-RPC methods
  private StockMessages m_stock_messages;  // the stock messages
  private Map m_menus;                     // the menus
  private Map m_menu_templates;            // the menu templates
  private DialogManager m_dialogs;         // the dialog manager
  private SideBoxManager m_sideboxes;      // the sidebox manager
  private CommunityMenuFactory m_comm_menu_fact;  // the community menu factory
  private EmoticonManager m_emoticons;     // the emoticon manager

  /*--------------------------------------------------------------------------------
   * Constructor
   *--------------------------------------------------------------------------------
   */

  public RootConfig(String config_file, String root_file_path) throws ConfigException
  {
    // Load the configuration file.
    XMLLoader loader = XMLLoader.get();
    Document doc = loader.loadConfigDocument(config_file);
    Element root = loader.configGetRootElement(doc,"ui-config");
    DOMElementHelper root_h = new DOMElementHelper(root);

    // Get the <file-paths/> section.
    Element sect = loader.configGetSubSection(root_h,"file-paths");
    DOMElementHelper sect_h = new DOMElementHelper(sect);

    // Get the full pathname of the sidebox configuration file.
    String sidebox_config = loader.configGetSubElementText(sect_h,"sidebox-config");
    if (!(sidebox_config.startsWith("/")))
      sidebox_config = root_file_path + sidebox_config;

    // Get the full pathname of the services configuration file.
    String services_config = loader.configGetSubElementText(sect_h,"services-config");
    if (!(services_config.startsWith("/")))
      services_config = root_file_path + services_config;

    // Get the full pathname of the emoticon configuration file.
    String emoticon_config = loader.configGetSubElementText(sect_h,"emoticon-config");
    if (!(emoticon_config.startsWith("/")))
      emoticon_config = root_file_path + emoticon_config;

    // Get the full pathname of the script directory.
    m_script_directory = getRelativeDirectory(sect_h,"script-dir",root_file_path,true);

    // Get the full pathname of the RPC script directory.
    m_rpc_script_directory = getRelativeDirectory(sect_h,"rpc-script-dir",root_file_path,true);

    // Get the full pathname of the temporary directory.
    m_temp_directory = getRelativeDirectory(sect_h,"temp-dir",root_file_path,false);

    // Get the full pathname of the Velocity template directory.
    m_template_directory = getRelativeDirectory(sect_h,"template-dir",root_file_path,false);

    // Get the <uri-paths/> section.
    sect = loader.configGetSubSection(root_h,"uri-paths");
    sect_h = new DOMElementHelper(sect);

    // Get the images path.
    m_image_path = loader.configGetSubElementText(sect_h,"image");
    if (!(m_image_path.endsWith("/")))
      m_image_path = m_image_path + "/";

    // Get the static path.
    m_static_path = loader.configGetSubElementText(sect_h,"static");
    if (!(m_static_path.endsWith("/")))
      m_static_path = m_static_path + "/";

    // Get the external static path.
    m_external_static_path = loader.configGetSubElementText(sect_h,"external-static");
    if (!(m_external_static_path.endsWith("/")))
      m_external_static_path = m_external_static_path + "/";

    // Get the format JSP path.
    m_format_path = loader.configGetSubElementText(sect_h,"format-jsp");
    if (!(m_format_path.endsWith("/")))
      m_format_path = m_format_path + "/";

    // Get the pathname of the "photo not available" image.
    m_blank_photo_path = loader.configGetSubElementText(sect_h,"photo-not-avail");
    Element sect1 = sect_h.getSubElement("photo-not-avail");
    DOMElementHelper sect1_h = new DOMElementHelper(sect1);
    if (sect1_h.hasAttribute("fixup"))
      m_blank_photo_path = m_image_path + m_blank_photo_path;

    // Load the default properties from the resources.
    Properties defprops = new Properties();
    try
    { // load the properties from the resource
      defprops.load(getClass().getResourceAsStream("default-config.properties"));

    } // end try
    catch (IOException e)
    { // whoops!
      throw new ConfigException("unable to load default application properties");

    } // end catch

    m_properties = new Properties(defprops);  // create the actual properties

    // Get the <properties/> section.
    sect = loader.configGetSubSection(root_h,"properties");
   
    // Loop through the section to find <property/> tags and add them to the property list.
    NodeList nl;
    int i;
    if (sect!=null)
    { // get the child nodes
      nl = sect.getChildNodes();
      for (i=0; i<nl.getLength(); i++)
      { // see if the node is a property value
	Node n = nl.item(i);
	if ((n.getNodeType()==Node.ELEMENT_NODE) && n.getNodeName().equals("property"))
	{ // add the property value to the map
	  sect1 = (Element)n;
	  m_properties.setProperty(loader.configGetAttribute(sect1,"name"),loader.configGetText(sect1));
	  
	} // end if

      } // end for (all child nodes of <properties/>)

    } // end if (<properties/> section exists)

    // Get the <frame/> section.
    sect = loader.configGetSubSection(root_h,"frame");
    sect_h = new DOMElementHelper(sect);

    // Get the name of the frame JSP.
    String tmp = loader.configGetSubElementText(sect_h,"jsp-name");
    m_frame_jsp_name = m_format_path + tmp;

    // Get the site title.
    m_site_title = sect_h.getSubElementText("site-title");

    // Get the base font size.
    Integer bf_size = sect_h.getSubElementInt("basefont-size");
    if (bf_size==null)
      bf_size = new Integer(3);

    // Get the default stylesheet location.
    tmp = sect_h.getSubElementText("stylesheet");
    if ((tmp!=null) && !(tmp.startsWith("/")))
      tmp = root_file_path + tmp;
    if (tmp!=null)
    { // set up stylesheet file name and stylesheet change data
      stylesheet = new File(tmp);
      if (stylesheet.canRead())
	stylesheet_lastchange = stylesheet.lastModified();
      else
      { // the stylesheet file does not exist
	logger.fatal("specified <stylesheet/> file \"" + tmp + "\" does not exist");
	throw new ConfigException("specified <stylesheet/> file does not exist",
				  sect_h.getSubElement("stylesheet"));

      } // end else

    } // end if
    else
    { // just null these values out
      stylesheet = null;
      stylesheet_lastchange = 0;

    } // end else

    // Get the "Smart Tags" flag.
    smart_tags = sect_h.hasChildElement("ms-copyright-violations");

    // Retrieve the site logo.
    sect1 = loader.configGetSubSection(sect_h,"site-logo");
    sect1_h = new DOMElementHelper(sect1);
    StringBuffer tmpbuf = new StringBuffer("<img src=\"");
    tmpbuf.append(loader.configGetText(sect1_h)).append("\" alt=\"").append(m_site_title).append("\" width=\"");

    // Get the logo width.
    Integer itmp = sect1_h.getAttributeInt("width");
    if (itmp==null)
      itmp = new Integer(140);
    tmpbuf.append(itmp).append("\" height=\"");

    // Get the logo height.
    itmp = sect1_h.getAttributeInt("height");
    if (itmp==null)
      itmp = new Integer(80);
    tmpbuf.append(itmp).append("\" hspace=\"");

    // Get the horizontal spacing for the logo.
    itmp = sect1_h.getAttributeInt("hspace");
    if (itmp==null)
      itmp = new Integer(2);
    tmpbuf.append(itmp).append("\" vspace=\"");

    // Get the vertical spacing for the logo.
    itmp = sect1_h.getAttributeInt("vspace");
    if (itmp==null)
      itmp = new Integer(2);
    tmpbuf.append(itmp).append("\" border=\"0\" />");
    site_logo_img_tag = tmpbuf.toString();
    
    // Get the link URL of the logo.
    tmp = sect1.getAttribute("href");
    if (!(StringUtil.isStringEmpty(tmp)))
    { // save off the HREF, get the type of the link
      site_logo_href = tmp;
      tmp = loader.configGetAttribute(sect1,"type");
      itmp = (Integer)(s_link_types.get(tmp));
      if (itmp==null)
      { // this is not good!
	logger.fatal("<site-logo/> type=\"" + tmp + "\" is not a valid value");
	throw new ConfigException("invalid link type for <site-logo/>",sect1);

      } // end if

      site_logo_href_type = itmp.intValue();

    } // end if

    // Get the footer logo scale and build the HTML snippet that contains the Venice logo.
    itmp = sect_h.getSubElementInt("footer-logo-scale");
    if (itmp==null)
      itmp = new Integer(100);
    int tmp_width = (VENICE_IMAGE_WIDTH * itmp.intValue()) / 100;
    int tmp_height = (VENICE_IMAGE_HEIGHT * itmp.intValue()) / 100;
    venice_logo_tag = "<a href=\"" + VENICE_URL + "\" target=\"_blank\"><img src=\"" + m_image_path
                    + VENICE_IMAGE + "\" alt=\"" + VENICE_ALT + "\" width=\"" + tmp_width + "\" height=\""
                    + tmp_height + "\" border=\"0\" hspace=\"0\" vspace=\"0\" /></a>";

    // Get the page icon and icon type, and the "favorites icon" (MS-specific).
    String page_icon_1 = null, page_icon_2 = null;
    sect1 = sect_h.getSubElement("favicon");
    if (sect1!=null)
    { // get the URL and create the "shortcut icon" tag
      String url = loader.configGetText(sect1);
      page_icon_2 = "<link rel=\"SHORTCUT ICON\" href=\"" + url + "\" />\n";

    } // end if

    sect1 = sect_h.getSubElement("page-icon");
    if (sect1!=null)
    { // get the URL and type, and create the page icon tag
      String url = loader.configGetText(sect1);
      String type = loader.configGetAttribute(sect1,"type");
      page_icon_1 = "<link rel=\"icon\" href=\"" + url + "\" type=\"" + type + "\" />\n";
      if (page_icon_2==null)  // fill this in for the "shortcut icon" as well
	page_icon_2 = "<link rel=\"SHORTCUT ICON\" href=\"" + url + "\" />\n";

    } // end if

    if (page_icon_1==null)
      m_page_icon_tags = page_icon_2;  // just use "shortcut icon"
    else
      m_page_icon_tags = page_icon_1 + page_icon_2;  // use both tags

    // Get the <rendering/> section.
    sect = loader.configGetSubSection(root_h,"rendering");
    sect_h = new DOMElementHelper(sect);

    // Get the default font face name.
    m_font_face = loader.configGetSubElementText(sect_h,"font");
    m_base_font = "<basefont face=\"" + m_font_face + "\" size=\"" + bf_size.intValue() + "\" />";

    // Load the stock font sizes.
    sect1 = sect_h.getSubElement("font-sizes");
    HashMap tmap;
    if (sect1!=null)
    { // scan through this subsection to find the stock font sizes
      tmap = new HashMap();
      nl = sect1.getChildNodes();
      for (i=0; i<nl.getLength(); i++)
      { // loop through the subelements
	Node n = nl.item(i);
	if (n.getNodeType()==Node.ELEMENT_NODE)
	{ // retrieve the font size and add it to our map
	  DOMElementHelper h = new DOMElementHelper((Element)n);
	  tmap.put(n.getNodeName(),h.getElementText());

	} // end if

      } // end for

      // save off the returned sizes
      if (tmap.isEmpty())
	m_font_sizes = Collections.EMPTY_MAP;
      else
	m_font_sizes = Collections.unmodifiableMap(tmap);

    } // end if
    else  // no font sizes - just leave this empty
      m_font_sizes = Collections.EMPTY_MAP;

    // Load all the colors.
    m_colors = new ColorPalette(loader.configGetSubSection(sect_h,"colors"));

    // Set up the content header array.
    content_hdr = new String[5];
    content_hdr[0] = "<span class=\"chead1\">" + getFontTag(CONTENT_HEADER,"header") + "<b>";
    content_hdr[1] = "</b></font></span>";
    content_hdr[2] = "&nbsp;&nbsp;<span class=\"chead2\">" + getFontTag(CONTENT_HEADER,"subhead") + "<b>";
    content_hdr[3] = "</b></font></span>";
    content_hdr[4] = "<hr align=\"left\" size=\"2\" width=\"90%\" noshade=\"noshade\" />\n";

    // Get the "HTML Comments" flag.
    html_comments = sect_h.hasChildElement("html-comments");

    // Get the "Buttons" section and initialize it.
    sect1 = loader.configGetSubSection(sect_h,"buttons");
    buttons = new ButtonHolder(sect1,m_image_path);

    // Get the <remapper/> section.
    sect = loader.configGetSubSection(root_h,"remapper");

    // Initialize the remapper object.
    remapper = new Remapper(sect,this);

    // Get the <rpc/> section.
    sect = loader.configGetSubSection(root_h,"rpc");
    sect_h = new DOMElementHelper(sect);

    // Get the <session-timeout/> figure.
    if (sect_h.hasChildElement("session-timeout"))
    { // get the timeout value
      Integer xtmp = sect_h.getSubElementInt("session-timeout");
      if (xtmp==null)
	throw new ConfigException("<session-timeout/> value is not an integer",sect);
      m_rpc_timeout = xtmp.intValue();
      if (m_rpc_timeout<=0)
	throw new ConfigException("<session-timeout/> value is invalid",sect);

    } // end if

    // Get the <xmlrpc-methods/> section.
    sect1 = loader.configGetSubSection(sect_h,"xmlrpc-methods");
    nl = sect1.getChildNodes();
    ArrayList tmp_alist = new ArrayList();
    for (i=0; i<nl.getLength(); i++)
    { // look for methods
      Node n = nl.item(i);
      if (n.getNodeType()==Node.ELEMENT_NODE)
      { // look for a <method/> element and use it to initialize a method
	if (n.getNodeName().equals("method"))
	  tmp_alist.add(new XmlRpcMethod(this,(Element)n));

      } // end if

    } // end for

    if (tmp_alist.isEmpty())
      m_xmlrpc_methods = Collections.EMPTY_LIST;
    else
    { // save off the methods list
      tmp_alist.trimToSize();
      m_xmlrpc_methods = Collections.unmodifiableList(tmp_alist);

    } // end else

    // Get the <messages/> section.
    sect = loader.configGetSubSection(root_h,"messages");

    // Initialize the stock messages list.
    m_stock_messages = new StockMessages(sect);

    // Get the <menu-definitions/> section.
    sect = loader.configGetSubSection(root_h,"menu-definitions");

    tmap = new HashMap();
    nl = sect.getChildNodes();
    for (i=0; i<nl.getLength(); i++)
    { // look for <menudef> subnodes and use them to initialize menus
      Node n = nl.item(i);
      if (n.getNodeType()==Node.ELEMENT_NODE)
      { // verify that it's a menu definition, then get its ID and build a menu
	loader.configVerifyNodeName(n,"menudef");
	String menuid = loader.configGetAttribute((Element)n,"id");
	Menu m = new Menu((Element)n,this,menuid);
	tmap.put(menuid,m);

      } // end if
      // else just ignore it

    } // end for

    if (tmap.isEmpty())
      m_menus = Collections.EMPTY_MAP;
    else
      m_menus = Collections.unmodifiableMap(tmap);

    // Get the <menu-template-definitions/> section.
    sect = loader.configGetSubSection(root_h,"menu-template-definitions");

    tmap = new HashMap();
    nl = sect.getChildNodes();
    for (i=0; i<nl.getLength(); i++)
    { // look for <menudef> subnodes and use them to initialize menu templates
      Node n = nl.item(i);
      if (n.getNodeType()==Node.ELEMENT_NODE)
      { // verify that it's a menu template definition, then get its ID and build a menu
	loader.configVerifyNodeName(n,"menu-template");
	String menuid = loader.configGetAttribute((Element)n,"id");
	MenuTemplate m = new MenuTemplate((Element)n,this,menuid);
	tmap.put(menuid,m);

      } // end if
      // else just ignore it

    } // end for

    if (tmap.isEmpty())
      m_menu_templates = Collections.EMPTY_MAP;
    else
      m_menu_templates = Collections.unmodifiableMap(tmap);

    // Get the <dialog-definitions/> section.
    sect = loader.configGetSubSection(root_h,"dialog-definitions");

    // Initialize the dialog manager.
    m_dialogs = new DialogManager(this,sect);

    // done with the ui-config.xml file
    // Load up the sidebox-config.xml file.
    doc = loader.loadConfigDocument(sidebox_config);
    root = loader.configGetRootElement(doc,"sidebox-config");

    // Create the sidebox manager.
    m_sideboxes = new SideBoxManager(root);

    // done with the sidebox-config.xml file
    // Load up the services-config.xml file.
    doc = loader.loadConfigDocument(services_config);
    root = loader.configGetRootElement(doc,"services-config");
    root_h = new DOMElementHelper(root);

    // Get the community section and pass it to the CommunityMenuFactory.
    m_comm_menu_fact = new CommunityMenuFactory(root_h.getSubElement("community"),this);

    // done with the services-config.xml file
    // Load up the emoticon.xml file.
    doc = loader.loadConfigDocument(emoticon_config);
    root = loader.configGetRootElement(doc,"emoticon-config");

    // Load the emoticon manager.
    m_emoticons = new EmoticonManager(root);

  } // end constructor

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

  private static final String getRelativeDirectory(DOMElementHelper sect_h, String tagname, String root_file_path,
						   boolean addslash) throws ConfigException
  {
    XMLLoader loader = XMLLoader.get();

    // Get the full pathname of the directory.
    String rc = loader.configGetSubElementText(sect_h,tagname);
    if (!(rc.startsWith("/")))
      rc = root_file_path + rc;
    if (addslash && !(rc.endsWith("/")))
      rc += "/";

    // Test to make sure the directory exists.
    File tmp = new File(rc);
    if (!(tmp.isDirectory()))
    { // directory does not exist, throw exception
      logger.fatal("<" + tagname + "/> directory \"" + rc + "\" is not a directory");
      throw new ConfigException("specified <" + tagname + "/> is not a directory",
				sect_h.getSubElement(tagname));

    } // end if

    return rc;

  } // end getRelativeDirectory

  private final String mapFontSize(String sz)
  {
    String rc = (String)(m_font_sizes.get(sz));
    return ((rc==null) ? sz : rc);

  } // end mapFontSize

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

  public final String getTemporaryPath()
  {
    return m_temp_directory;

  } // end getTemporaryPath

  public final String getVelocityTemplateDirectory()
  {
    return m_template_directory;

  } // end getVelocityTemplateDirectory

  public final String getImagePath(String img)
  {
    return m_image_path + img;

  } // end getImagePath

  public final String getStaticPath(String s)
  {
    return m_static_path + s;

  } // end getImagePath

  public final String getExternalStaticPath(String s)
  {
    return m_external_static_path + s;

  } // end getExternalStaticPath

  public final String getFormatJSPPath(String jsp)
  {
    return m_format_path + jsp;

  } // end getFormatJSPPath

  public final String getScriptPath(String sname)
  {
    return m_script_directory + sname;

  } // end getScriptPath

  public final String getRPCScriptPath(String sname)
  {
    return m_rpc_script_directory + sname;

  } // end getRPCScriptPath

  public final String getFrameJSPName()
  {
    return m_frame_jsp_name;

  } // end getFrameJSPName

  public final String getPageTitle(String t)
  {
    if (m_site_title==null)
      return t;
    else
      return t + " - " + m_site_title;

  } // end getPageTitle

  public final String getBaseFontTag()
  {
    return m_base_font;

  } // end getBaseFontTag

  public final boolean usingStyleSheet()
  {
    return (stylesheet!=null);

  } // end usingStyleSheet

  public final boolean hasStyleSheetChanged()
  {
    if (stylesheet==null)
      return false;
    return (stylesheet.lastModified()!=stylesheet_lastchange);

  } // end hasStyleSheetChanged

  public final String loadStyleSheetData() throws IOException
  {
    StringBuffer raw_data;
    synchronized (this)
    { // If there's no stylesheet, don't bother.
      if (stylesheet==null)
	return null;

      // Load the stylesheet data.
      raw_data = IOUtil.loadText(stylesheet);
      stylesheet_lastchange = stylesheet.lastModified();

    } // end synchronized block
    
    // Set up the replacements map to replace the various parameters.
    HashMap vars = new HashMap();
    vars.put("font",m_font_face);
    m_colors.fillParameterMap("color.",vars);
    return StringUtil.replaceAllVariables(raw_data.toString(),vars);

  } // end loadStyleSheetData

  public final String getColor(int selector)
  {
    return m_colors.getColor(selector);

  } // end getColor

  public final String getColor(String name)
  {
    return m_colors.getColor(name);

  } // end getColor

  public final String getFontTag(int colorsel, int size)
  {
    return "<font face=\"" + m_font_face + "\" color=\"" + m_colors.getColor(colorsel) + "\" size=\"" + size + "\">";

  } // end getFontTag

  public final String getFontTag(String color, int size)
  {
    StringBuffer rc = new StringBuffer("<font face=\"");
    rc.append(m_font_face).append("\" size=\"").append(size).append("\"");
    if (color!=null)
      rc.append(" color=\"").append(m_colors.getColor(color)).append("\"");
    rc.append('>');
    return rc.toString();

  } // end getFontTag

  public final String getFontTag(int colorsel, String size)
  {
    StringBuffer rc = new StringBuffer("<font face=\"");
    rc.append(m_font_face).append("\" color=\"").append(m_colors.getColor(colorsel)).append('\"');
    if (size!=null)
      rc.append(" size=\"").append(mapFontSize(size)).append('\"');
    rc.append('>');
    return rc.toString();

  } // end getFontTag

  public final String getFontTag(String color, String size)
  {
    StringBuffer rc = new StringBuffer("<font face=\"");
    rc.append(m_font_face).append("\"");
    if (color!=null)
      rc.append(" color=\"").append(m_colors.getColor(color)).append("\"");
    if (size!=null)
      rc.append(" size=\"").append(mapFontSize(size)).append('\"');
    rc.append('>');
    return rc.toString();

  } // end getFontTag

  public final boolean useSmartTags()
  {
    return smart_tags;

  } // end useSmartTags

  public final boolean useHTMLComments()
  {
    return html_comments;

  } // end useHTMLComments

  public final String getSiteLogoImageTag()
  {
    return site_logo_img_tag;

  } // end getSiteLogoImageTag

  public final String getSiteLogoLink()
  {
    return site_logo_href;

  } // end getSiteLogoLink

  public final int getSiteLogoLinkType()
  {
    return site_logo_href_type;

  } // end getSiteLogoLinkType

  public final int convertLinkType(String str)
  {
    Integer tmp = (Integer)(s_link_types.get(str.trim().toLowerCase()));
    return (tmp==null) ? -1 : tmp.intValue();

  } // end convertLinkType

  public final String getStockMessage(String key)
  {
    return m_stock_messages.get(key);

  } // end getStockMessage

  public final String getStockMessage(String key, Map vars)
  {
    return m_stock_messages.getReplace(key,vars);

  } // end getStockMessage

  public final Remapper getRemapper()
  {
    return remapper;

  } // end getRemapper

  public final String getVeniceLogoTag()
  {
    return venice_logo_tag;

  } // end getVeniceLogoTag

  public final String getPageIconTags()
  {
    return m_page_icon_tags;

  } // end getPageIconTags

  public final String getContentHeader(String primary, String secondary)
  {
    StringBuffer buf = new StringBuffer(content_hdr[0]);
    buf.append(primary).append(content_hdr[1]);
    if (secondary!=null)
      buf.append(content_hdr[2]).append(secondary).append(content_hdr[3]);
    buf.append(content_hdr[4]);
    return buf.toString();

  } // end getContentHeader

  public final MenuComponent getMenu(String name)
  {
    return (MenuComponent)(m_menus.get(name));

  } // end getMenu

  public final MenuComponent getMenu(String name, Map vars)
  {
    return new Menu((Menu)(m_menus.get(name)),vars);

  } // end getMenu

  public final MenuTemplate getMenuTemplate(String name)
  {
    return (MenuTemplate)(m_menu_templates.get(name));

  } // end getMenuTemplate

  public final String getButtonVisual(String id)
  {
    return buttons.getButtonVisual(id);

  } // end getButtonVisual

  public final String getButtonInput(String id)
  {
    return buttons.getButtonInput(id);

  } // end getButtonInput

  public final Dialog getDialog(String name)
  {
    return m_dialogs.getDialog(name);

  } // end getDialog

  public final SideBoxManager getSideBoxManager()
  {
    return m_sideboxes;

  } // end getSideBoxManager

  public final String getBlankPhoto()
  {
    return m_blank_photo_path;

  } // end getBlankPhoto

  public final String getProperty(String name)
  {
    return m_properties.getProperty(name);

  } // end getProperty

  public final String getProperty(String name, String default_val)
  {
    return m_properties.getProperty(name,default_val);

  } // end getProperty

  public final CommunityMenu getCommunityMenu(CommunityContext comm)
  {
    return m_comm_menu_fact.createMenu(comm);

  } // end getCommunityMenu

  public final String getDefaultServletAddress(RequestInput inp, CommunityContext comm)
  {
    return m_comm_menu_fact.getDefaultServletAddress(inp,comm);

  } // end getDefaultServletAddress

  public final int getRpcSessionTimeout()
  {
    return m_rpc_timeout;

  } // end getRpcSessionTimeout

  public final List getXmlRpcMethods()
  {
    return m_xmlrpc_methods;

  } // end getXmlRpcMethods

  public final void addFormatParams(Map map)
  {
    // add font and colors first
    map.put("font",m_font_face);
    m_colors.fillParameterMap("color.",map);

    // now add font sizes
    for (Iterator it=m_font_sizes.entrySet().iterator(); it.hasNext(); )
    { // add the size parameters
      Map.Entry ntry = (Map.Entry)(it.next());
      map.put("size." + ntry.getKey().toString(),ntry.getValue());

    } // end for

  } // end addFormatParams

  public final EmoticonManager getEmoticonManager()
  {
    return m_emoticons;

  } // end getEmoticonManager

  /*--------------------------------------------------------------------------------
   * Static initializer
   *--------------------------------------------------------------------------------
   */

  static
  { // create the link types
    HashMap m = new HashMap();
    m.put("absolute",new Integer(ABSOLUTE));
    m.put("servlet",new Integer(SERVLET));
    m.put("frame",new Integer(FRAME));
    m.put("fullservlet",new Integer(FULLSERVLET));
    s_link_types = Collections.unmodifiableMap(m);

  } // end static initializer

} // end class RootConfig
