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

import java.util.*;
import javax.servlet.http.HttpServletResponse;
import org.w3c.dom.*;
import com.silverwrist.util.*;
import com.silverwrist.venice.except.*;
import com.silverwrist.venice.ui.*;
import com.silverwrist.venice.ui.helpers.*;
import com.silverwrist.venice.util.*;

public class Remapper
{
  /*--------------------------------------------------------------------------------
   * Remap entries class
   *--------------------------------------------------------------------------------
   */

  class RemapEntry implements LinkTypes
  {
    class RemapParameter
    {
      private String name;
      private String default_value;

      RemapParameter(Element cfg) throws ConfigException
      {
	XMLLoader loader = XMLLoader.get();
	name = loader.configGetAttribute(cfg,"name");
	DOMElementHelper h = new DOMElementHelper(cfg);
	default_value = h.getElementText();
	if (default_value==null)
          default_value = "";

      } // end constructor

      final void fillParameter(RequestInput req, Map vars)
      {
	String val = req.getParameter(name);
	if (val==null)
	  val = default_value;
	vars.put(name,val);

      } // end fillParameter

    } // end class RemapParameter

    private String source_path;   // source path to be matched
    private String target_url;    // target URL with replaceable parameters
    private int target_type;      // target URL type
    private List params;          // the parameters

    RemapEntry(Element cfg, RootConfig root) throws ConfigException
    {
      XMLLoader loader = XMLLoader.get();
      source_path = loader.configGetAttribute(cfg,"path");
      Element tsect = loader.configGetSubSection(cfg,"target");
      DOMElementHelper tsect_h = new DOMElementHelper(tsect);
      target_url = loader.configGetText(tsect_h);
      if (tsect_h.hasAttribute("type"))
      { // get and convert the target type
	target_type = root.convertLinkType(loader.configGetAttribute(tsect,"type"));
	if (target_type==-1)
	  throw new ConfigException("<target> has invalid type= attribute");

      } // end if
      else  // the target type is not specified - default it
	target_type = SERVLET;

      NodeList nl = cfg.getChildNodes();
      ArrayList tmp_params = new ArrayList(nl.getLength());
      for (int i=0; i<nl.getLength(); i++)
      { // look at each child node
	Node n = nl.item(i);
	if ((n.getNodeType()==Node.ELEMENT_NODE) && (n.getNodeName().equals("param")))
	{ // build a remap entry for this node
	  RemapParameter p = new RemapParameter((Element)n);
	  tmp_params.add(p);

	} // end if
	// else ignore the node

      } // end for

      if (tmp_params.isEmpty())
	params = Collections.EMPTY_LIST;
      else
      { // trim the ArrayList and make it read-only
	tmp_params.trimToSize();
	params = Collections.unmodifiableList(tmp_params);

      } // end else

    } // end constructor

    final String getSourcePath()
    {
      return source_path;

    } // end getSourcePath

    final Object remapRequest(RequestInput req)
    {
      HashMap vars = new HashMap();
      Iterator it = params.iterator();
      while (it.hasNext())
      { // collect parameters for replacment variables
	RemapParameter p = (RemapParameter)(it.next());
	p.fillParameter(req,vars);

      } // end while

      String url;
      if (vars.isEmpty())
	url = target_url;
      else
	url = StringUtil.replaceAllVariables(target_url,vars);
      return new Redirect(url,target_type);

    } // end remapRequest

  } // end class

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

  private Map entries;

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

  Remapper(Element cfg, RootConfig root) throws ConfigException
  {
    HashMap tmp_entries = new HashMap();
    NodeList nl = cfg.getChildNodes();
    for (int i=0; i<nl.getLength(); i++)
    { // look at each child node
      Node n = nl.item(i);
      if ((n.getNodeType()==Node.ELEMENT_NODE) && (n.getNodeName().equals("remap")))
      { // build a remap entry for this node
	RemapEntry ntry = new RemapEntry((Element)n,root);
	tmp_entries.put(ntry.getSourcePath(),ntry);

      } // end if
      // else ignore the node

    } // end for

    if (tmp_entries.isEmpty())
      entries = Collections.EMPTY_MAP;
    else
      entries = Collections.unmodifiableMap(tmp_entries);

  } // end constructor

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

  public final Object remapRequest(RequestInput req)
  {
    RemapEntry ntry = (RemapEntry)(entries.get(req.getServletPath()));
    if (ntry==null)
      return new HTTPError(HttpServletResponse.SC_NOT_FOUND,"remapped URL not found");
    return ntry.remapRequest(req);

  } // end remapRequest

} // end class Remapper
