/*
 * 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.lang.reflect.*;
import java.util.*;
import org.w3c.dom.*;
import com.silverwrist.util.*;
import com.silverwrist.venice.except.*;
import com.silverwrist.venice.ui.dlg.Dialog;

class DialogManager
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  private static final String default_package;
  private static final Class[] default_ctor_args = { RootConfig.class, Element.class };

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

  private Map dialog_instance_map;

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

  DialogManager(RootConfig cfg, Element elt) throws ConfigException
  {
    HashMap tmp_map = new HashMap();
    NodeList nl = elt.getChildNodes();
    Object[] args = null;
    for (int i=0; i<nl.getLength(); i++)
    { // look at each node in the node list
      Node n = nl.item(i);
      if ((n.getNodeType()==Node.ELEMENT_NODE) && (n.getNodeName().equals("dialog")))
      { // create a dialog node
	DOMElementHelper h = new DOMElementHelper((Element)n);
	Dialog dlg;
	if (h.hasAttribute("class"))
	{ // create a dialog of a custom class
	  try
	  { // get the classname and augment it if necessary
	    String cname = h.getElement().getAttribute("class");
	    if (cname.indexOf('.')<0)
	      cname = default_package + cname;

	    // load the class of the dialog and test it
	    Class klass = Class.forName(cname);
	    int xmod = klass.getModifiers();
	    if (   Modifier.isAbstract(xmod) || Modifier.isInterface(xmod)
		|| !(Dialog.class.isAssignableFrom(klass)))
	      throw new ConfigException("invalid dialog class specification",h.getElement());

	    // get the appropriate constructor
	    Constructor ctor = klass.getConstructor(default_ctor_args);

	    // Create the constructor args array.
	    if (args==null)
	    { // allocate the array, and its first element (never changes)
	      args = new Object[default_ctor_args.length];
	      args[0] = cfg;

	    } // end if

	    // Create the new dialog instance.
	    args[1] = h.getElement();
	    dlg = (Dialog)(ctor.newInstance(args));

	  } // end try
	  catch (ClassNotFoundException cnfe)
	  { // the classname is not valid
	    throw new ConfigException("invalid dialog class specification",h.getElement());

	  } // end catch
	  catch (NoSuchMethodException nsme)
	  { // the constructor was not found
	    throw new ConfigException("invalid dialog class specification",h.getElement());

	  } // end catch
	  catch (SecurityException se)
	  { // unable to access the constructor
	    throw new ConfigException("invalid dialog class specification",h.getElement());

	  } // end catch
	  catch (InstantiationException ie)
	  { // unable to instantiate (shouldn't happen)
	    throw new InternalStateError("new dialog InstantiationException (shouldn't happen)");

	  } // end catch
	  catch (IllegalAccessException iae)
	  { // unable to access constructor
	    throw new ConfigException("invalid dialog class specification",h.getElement());

	  } // end catch
	  catch (IllegalArgumentException ae)
	  { // argument errors (shouldn't happen)
	    throw new InternalStateError("new dialog IllegalArgumentException (shouldn't happen)");

	  } // end catch
	  catch (InvocationTargetException ite)
	  { // exception in the constructor
	    Throwable t = ite.getTargetException();
	    if (t instanceof ConfigException)
	      throw (ConfigException)t;
	    throw new InternalStateError("unknown exception " + t.getClass().getName()
					 + " in Dialog constructor");

	  } // end catch
	  catch (ClassCastException cce)
	  { // this should not happen
	    throw new InternalStateError("new dialog cast to Dialog failed (shouldn't happen)");

	  } // end catch

	} // end if (custom class)
	else  // just do the old-fashioned way
	  dlg = new Dialog(cfg,h.getElement());

	// add to temporary map
	tmp_map.put(dlg.getName(),dlg);

      } // end if
      // else ignore the element

    } // end for

    // Save off the map.
    if (tmp_map.isEmpty())
      dialog_instance_map = Collections.EMPTY_MAP;
    else
      dialog_instance_map = Collections.unmodifiableMap(tmp_map);

  } // end constructor

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

  public final Dialog getDialog(String name)
  {
    Dialog dlg = (Dialog)(dialog_instance_map.get(name));
    if (dlg==null)
      return null;
    return (Dialog)(dlg.clone());

  } // end getDialog

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

  static
  {
    String s = Dialog.class.getName();
    int p = s.lastIndexOf('.');
    default_package = s.substring(0,p+1);

  } // end static initializer

} // end class DialogManager
