/*
 * 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.helpers;

import java.io.*;
import java.util.*;
import org.apache.log4j.*;
import org.w3c.dom.*;
import com.silverwrist.util.*;
import com.silverwrist.venice.core.*;
import com.silverwrist.venice.except.*;
import com.silverwrist.venice.security.*;
import com.silverwrist.venice.util.*;

public class ImportHelper
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  private static Category logger = Category.getInstance(ImportHelper.class);

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

  private int processed = 0;
  private int errors = 0;
  private String message = null;

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

  public ImportHelper(AdminOperations adm, InputStream xml_data)
  {
    XMLLoader loader = XMLLoader.get();
    Document xmldoc;

    try
    { // load the XML data!
      xmldoc = loader.loadPostData(xml_data);

    } // end try
    catch (ValidationException e)
    { // serious parser error!
      message = "<B>Error parsing XML: " + StringUtil.encodeHTML(e.getMessage()) + "</B>\n";
      return;

    } // end catch

    Element root = xmldoc.getDocumentElement();
    if (!(root.getTagName().equals("venice-import-users")))
    { // wrong document type!
      message = "<B>XML Error: Document is not a &lt;venice-import-users/&gt; document</B>\n";
      return;

    } // end if

    SecurityInfo sinf = adm.getSecurityInfo();
    Role default_role = sinf.getDefaultRole("Global.NewUser");
    ArrayList scroll = new ArrayList();
    NodeList nl = root.getChildNodes();
    for (int i=0; i<nl.getLength(); i++)
    { // get each node from the list, see if it's a Venice user
      Node n = nl.item(i);
      if ((n.getNodeType()==Node.ELEMENT_NODE) && n.getNodeName().equals("venice-user"))
      { // this is a Venice user record - first parse it out into binary data
	processed++;
	DOMElementHelper h = new DOMElementHelper((Element)n);
	String id = h.getElement().getAttribute("id");
	String username = null, password = null, reminder = null, description = null;
	String zonehint = null;
	Role r = default_role;
	boolean confirm = false, locked = false, hideaddr = false, hidephone = false, hidefax = false;
	boolean hideemail = false;
	VCard vcard = null;

	// BUILD PHASE - Build the data to be used for this user.
	try
	{ // parse out the info
	  username = h.getSubElementText("username");
	  if (username==null)
	    throw new ValidationException("no <username/> element found");
	  username = username.trim();
	  if (!(IDUtils.isValidVeniceID(username)))
	    throw new ValidationException("<username/> \"" + username + "\" is not a valid Venice ID");
	  password = h.getSubElementText("password");
	  if (password==null)
	    throw new ValidationException("no <password/> element found");
	  password = password.trim();
	  reminder = h.getSubElementText("password-reminder");
	  if (reminder!=null)
	    reminder = reminder.trim();
	  description = h.getSubElementText("description");
	  if (description!=null)
	    description = description.trim();
	  Element opts = h.getSubElement("options");
	  if (opts!=null)
	  { // parse out the options
	    DOMElementHelper hopts = new DOMElementHelper(opts);
	    if (hopts.hasAttribute("role"))
	    { // get the role from the file and return it
	      r = sinf.getRole(opts.getAttribute("role"));
	      if (r==null)
		throw new ValidationException("role not defined: " + opts.getAttribute("role"));

	    } // end if

	    confirm = hopts.hasAttribute("confirmed");
	    locked = hopts.hasAttribute("locked");
	    hideaddr = hopts.hasAttribute("hideaddr");
	    hidephone = hopts.hasAttribute("hidephone");
	    hidefax = hopts.hasAttribute("hidefax");
	    hideemail = hopts.hasAttribute("hideemail");
	    if (hopts.hasAttribute("zonehint"))
	      zonehint = opts.getAttribute("zonehint").trim();

	  } // end if
	  // else just leave things as the default

	  opts = h.getSubElement("vCard");
	  if (opts==null)
	    throw new ValidationException("no <vCard/> element found");
	  vcard = new VCard(opts);

	} // end try
	catch (ValidationException e)
	{ // record the error and continue
	  logger.error("caught ValidationException in build phase(" + id + ")",e);
	  String tmp = "<B>Error in element \"" + StringUtil.encodeHTML(id) + "\":</B> "
	             + StringUtil.encodeHTML(e.getMessage());
	  scroll.add(tmp);
	  errors++;
	  continue;

	} // end catch

	// EXECUTE PHASE - make this user go!
	try
	{ // create the user context
	  AdminUserContext uc = adm.createNewAccount(username,password,reminder,confirm,locked,r,description);

	  // set up the contact info
	  ContactInfo ci = uc.getContactInfo();
	  ci.setPrivateAddress(hideaddr);
	  ci.setPrivatePhone(hidephone);
	  ci.setPrivateFax(hidefax);
	  ci.setPrivateEmail(hideemail);
	  ci.importVCard(vcard);
	  uc.putContactInfo(ci);

	  // set up the timezone
	  String tmp = vcard.getTimeZone();
	  if (tmp!=null)
	  { // get a "generic" time zone and convert it to a real one
	    TimeZone zone_raw = TimeZone.getTimeZone("GMT" + tmp);
	    String[] ids = TimeZone.getAvailableIDs(zone_raw.getRawOffset());
	    TimeZone zone = null;
	    if (ids.length>0)
	    { // OK, there's at least one time zone...which one do we pick?
	      if (zonehint!=null)
	      { // use the "zonehint" to get the right time zone
		for (int j=0; (zone==null) && (j<ids.length); j++)
		  if (ids[j].indexOf(zonehint)>=0)
		    zone = TimeZone.getTimeZone(ids[j]);

	      } // end if

	      if (zone==null)
		zone = TimeZone.getTimeZone(ids[0]);

	    } // end if
	    else  // just use the raw timezone
	      zone = zone_raw;
	    uc.setTimeZone(zone);

	  } // end if

	} // end try
	catch (AccessError ae)
	{ // caught an access error creating user
	  logger.error("caught AccessError in execute phase(" + id + ")",ae);
	  String tmp = "<B>Unable to create \"" + username + "\" (element \"" + StringUtil.encodeHTML(id)
	             + "\"):</B> " + StringUtil.encodeHTML(ae.getMessage());
	  scroll.add(tmp);
	  errors++;
	  continue;

	} // end catch
	catch (DataException de)
	{ // caught a database error creating the user
	  logger.error("caught DataException in execute phase(" + id + ")",de);
	  String tmp = "<B>Unable to create \"" + username + "\" (element \"" + StringUtil.encodeHTML(id)
	             + "\"):</B> database error: " + StringUtil.encodeHTML(de.getMessage());
	  scroll.add(tmp);
	  errors++;
	  continue;

	} // end catch

	// this user was created successfully!
	String tmp = "[id " + StringUtil.encodeHTML(id) + "] user \"" + username + "\" created successfully.";
	scroll.add(tmp);

      } // end if

    } // end for

    // Gather the scroll items together to form the message.
    message = StringUtil.join(scroll,"<BR>\n");

  } // end constructor

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

  public final int getProcessed()
  {
    return processed;

  } // end getProcessed

  public final int getErrors()
  {
    return errors;

  } // end getErrors

  public final String getMessage()
  {
    return message;

  } // end getMessage

} // end class ImportHelper
