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

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.log4j.*;
import com.silverwrist.venice.core.*;
import com.silverwrist.venice.except.*;
import com.silverwrist.venice.servlets.format.*;

public class Settings extends VeniceServlet
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  private static final String UNJOIN_CONFIRM_ATTR = "servlets.Settings.unjoin.confirm";
  private static final String UNJOIN_CONFIRM_PARAM = "confirm";

  private static Category logger = Category.getInstance(Settings.class.getName());

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

  private static int findHotlistIndex(List hotlist, ServletRequest request) throws ErrorBox
  {
    String foo = request.getParameter("sig");
    if (foo==null)
      throw new ErrorBox(null,"Parameter not specified!","settings?cmd=H");
    int cid;
    try
    { // this is the community id of the hotlist entry
      cid = Integer.parseInt(foo);

    } // end try
    catch (NumberFormatException nfe)
    { // conversion error...
      throw new ErrorBox(null,"Parameter invalid!","settings?cmd=H");

    } // end catch

    foo = request.getParameter("conf");
    if (foo==null)
      throw new ErrorBox(null,"Parameter not specified!","settings?cmd=H");
    int confid;
    try
    { // this is the conference id of the hotlist entry
      confid = Integer.parseInt(foo);

    } // end try
    catch (NumberFormatException nfe)
    { // conversion error...
      throw new ErrorBox(null,"Parameter invalid!","settings?cmd=H");

    } // end catch

    for (int i=0; i<hotlist.size(); i++)
    { // look at the hotlist entries to find the right index
      ConferenceHotlistEntry hle = (ConferenceHotlistEntry)(hotlist.get(i));
      if (   (hle.getConference().getConfID()==confid)
	  && (hle.getConference().getEnclosingCommunity().getCommunityID()==cid))
	return i;

    } // end for

    throw new ErrorBox(null,"Hotlist entry not found!","settings?cmd=H");

  } // end findHotlistIndex

  private static int getBoxIDParameter(ServletRequest request) throws ErrorBox
  {
    String foo = request.getParameter("box");
    if (foo==null)
      throw new ErrorBox(null,"Parameter not specified!","settings?cmd=B");
    try
    { // parse the integer and get the box ID
      return Integer.parseInt(foo);

    } // end try
    catch (NumberFormatException e)
    { // error in parsing...
      throw new ErrorBox(null,"Parameter invalid!","settings?cmd=B");

    } // end catch

  } // end getBoxIDParameter

  /*--------------------------------------------------------------------------------
   * Overrides from class HttpServlet
   *--------------------------------------------------------------------------------
   */

  public String getServletInfo()
  {
    String rc = "Settings servlet - Handles per-user customization and settings information\n"
              + "Part of the Venice Web Communities System\n";
    return rc;

  } // end getServletInfo

  /*--------------------------------------------------------------------------------
   * Overrides from class VeniceServlet
   *--------------------------------------------------------------------------------
   */

  protected VeniceContent doVeniceGet(HttpServletRequest request, VeniceEngine engine,
				      UserContext user, RenderData rdat)
      throws ServletException, IOException, VeniceServletResult
  {
    String cmd = getStandardCommandParam(request);

    if (cmd.equals("H"))
    { // "H" - Manage Conference Hotlist
      try
      { // return the hotlist viewer
	setMyLocation(request,"settings?cmd=H");
	return new Hotlist(user);

      } // end try
      catch (DataException de)
      { // oops...can't get it!
	return new ErrorBox("Database Error","Error getting hotlist: " + de.getMessage(),"top");

      } // end catch

    } // end if ("H" command)

    if (cmd.equals("HU") || cmd.equals("HD") || cmd.equals("HX"))
    { // one of the commands for modifying the user hotlist
      try
      { // start by getting the hotlist and localizing the entry we want to modify
	List hotlist = user.getConferenceHotlist();
	int ndx = findHotlistIndex(hotlist,request);
	ConferenceHotlistEntry hle = (ConferenceHotlistEntry)(hotlist.get(ndx));
	ConferenceContext conf = hle.getConference();

	if (cmd.equals("HX"))
	  conf.removeFromHotlist();  // pretty straightforward
	else
	{ // moving up or down - find the entry to switch places with
	  int other_ndx;
	  if (cmd.equals("HU"))
	  { // moving up!
	    if (ndx==0)
	      return null;  // can't move up from here
	    other_ndx = ndx - 1;

	  } // end if
	  else
	  { // moving down
	    other_ndx = ndx + 1;
	    if (other_ndx==hotlist.size())
	      return null;  // can't move down from here

	  } // end else

	  // find the sequence numbers and the other conference object
	  int my_seq = hle.getSequence();
	  hle = (ConferenceHotlistEntry)(hotlist.get(other_ndx));
	  ConferenceContext other_conf = hle.getConference();
	  int other_seq = hle.getSequence();

	  // now reset the sequences
	  conf.setHotlistSequence(other_seq);
	  boolean restore = true;
	  try
	  { // reset the other conference sequence, too
	    other_conf.setHotlistSequence(my_seq);
	    restore = false;

	  } // end try
	  finally
	  { // restore the original conference sequence on error
	    if (restore)
	      conf.setHotlistSequence(my_seq);

	  } // end finally

	} // end else (moving up or down)

      } // end try
      catch (DataException de)
      { // there's a data exception somewhere
	return new ErrorBox("Database Error","Error adjusting hotlist: " + de.getMessage(),"settings?cmd=H");

      } // end catch

      try
      { // return the hotlist viewer
	setMyLocation(request,"settings?cmd=H");
	return new Hotlist(user);

      } // end try
      catch (DataException de)
      { // oops...can't get it!
	return new ErrorBox("Database Error","Error getting hotlist: " + de.getMessage(),"top");

      } // end catch

    } // end if (one of the "H" subcommands)

    if (cmd.equals("S"))
    { // "S" - display the user's community list 
      try
      { // return the community list viewer
	setMyLocation(request,"settings?cmd=S");
	return new UserCommunityList(user);

      } // end try
      catch (DataException de)
      { // oops...can't get it!
	return new ErrorBox("Database Error","Error getting communities list: " + de.getMessage(),"top");

      } // end catch
     
    } // end if ("S" command)

    if (cmd.equals("SX"))
    { // "SX" - unjoin the specified community
      CommunityContext comm = getCommunityParameter(request,user,true,"settings?cmd=S");

      if (!(comm.canUnjoin()))
	return new ErrorBox("Community Error","You cannot unjoin this community.","settings?cmd=S");
      
      // OK, let's test for a confirmation...
      if (ConfirmBox.isConfirmed(request,UNJOIN_CONFIRM_ATTR,UNJOIN_CONFIRM_PARAM))
      { // OK, if you say so, let's unjoin!
	try
	{ // do the unjoin now...
	  comm.unjoin();

	} // end try
	catch (AccessError ae)
	{ // access error
	  return new ErrorBox("Access Error","Unable to unjoin community: " + ae.getMessage(),
			      "settings?cmd=S");

	} // end catch
	catch (DataException de)
	{ // data exception doing something
	  return new ErrorBox("Database Error","Database error unjoining community: " + de.getMessage(),
			      "settings?cmd=S");

	} // end catch

	// after which, redirect back to the top
	throw new RedirectResult("settings?cmd=S");

      } // end if
      else
      { // not a proper confirmation - display the confirm box
	String message = "Are you sure you want to unjoin the '" + comm.getName() + "' community?";
	return new ConfirmBox(request,UNJOIN_CONFIRM_ATTR,UNJOIN_CONFIRM_PARAM,"Unjoining Community",
			      message,"settings?cmd=SX&sig=" + comm.getCommunityID(),"settings?cmd=S");

      } // end else

    } // end if ("SX" command)

    if (cmd.equals("B"))
    { // "B" - Configure Sideboxes
      try
      { // return the sidebox viewer
	setMyLocation(request,"settings?cmd=B");
	return new SideBoxList(engine,user);

      } // end try
      catch (DataException de)
      { // Database error getting sidebox list
	return new ErrorBox("Database Error","Error getting sidebox list: " + de.getMessage(),"top");

      } // end catch

    } // end if ("B" command)

    if (cmd.equals("BU") || cmd.equals("BD") || cmd.equals("BX"))
    { // move sidebox up or down in list, or delete it
      int boxid = getBoxIDParameter(request);
      try
      { // get the box ID, find it in the list
	List sidebox_list = user.getSideBoxList();
	UserSideBoxDescriptor prev = null;
	UserSideBoxDescriptor curr = null;
	Iterator it = sidebox_list.iterator();
	boolean found = false;
	while (!found && it.hasNext())
	{ // track the previous descriptor so we can do the swap
	  prev = curr;
	  curr = (UserSideBoxDescriptor)(it.next());
	  if (curr.getID()==boxid)
	  { // found it - trip the loop exit
	    found = true;
	    if (cmd.equals("BD"))
	    { // make "prev" actually be the NEXT descriptor
	      if (it.hasNext())
		prev = (UserSideBoxDescriptor)(it.next());
	      else
		prev = null;

	    } // end if

	  } // end if (found)

	} // end while

	if (found)
	{ // the current one needs to be operated on
	  if (cmd.equals("BX"))
	    curr.remove();  // remove the "current" sidebox
	  else if (prev!=null)
	  { // exchange the sequence numbers of "curr" and "prev"
	    int seq_curr = curr.getSequence();
	    int seq_prev = prev.getSequence();
	    curr.setSequence(seq_prev);  // do the first "set"
	    boolean restore = true;
	    try
	    { // do the second "set"
	      prev.setSequence(seq_curr);
	      restore = false;

	    } // end try
	    finally
	    { // restore first if second failed
	      if (restore)
		curr.setSequence(seq_curr);

	    } // end finally

	  } // end else if
	  // else just fall out and do nothing

	} // end if
	// else just fall out and don't do anything

      } // end try
      catch (DataException de)
      { // there was a data problem
	return new ErrorBox("Database Error","Error adjusting sidebox list: " + de.getMessage(),
			    "settings?cmd=B");

      } // end catch

      try
      { // return the sidebox viewer
	setMyLocation(request,"settings?cmd=B");
	return new SideBoxList(engine,user);

      } // end try
      catch (DataException de)
      { // Database error getting sidebox list
	return new ErrorBox("Database Error","Error getting sidebox list: " + de.getMessage(),"top");

      } // end catch

    } // end if ("BD"/"BU"/"BX" commands)

    // command not found!
    logger.error("invalid command to Settings.doGet: " + cmd);
    return new ErrorBox("Internal Error","Invalid command to Settings.doGet","top");

  } // end doVeniceGet

  protected VeniceContent doVenicePost(HttpServletRequest request, VeniceEngine engine,
				       UserContext user, RenderData rdat)
      throws ServletException, IOException, VeniceServletResult
  {
    String cmd = getStandardCommandParam(request);

    if (cmd.equals("BA"))
    { // "BA" - add new sidebox
      int boxid = getBoxIDParameter(request);
      try
      { // add the sidebox
	user.addSideBox(boxid);

      } // end try
      catch (DataException de)
      { // error adding to sideboxes
	return new ErrorBox("Database Error","Error adding to sidebox list: " + de.getMessage(),
			    "settings?cmd=B");

      } // end catch

      try
      { // return the sidebox viewer
	setMyLocation(request,"settings?cmd=B");
	return new SideBoxList(engine,user);

      } // end try
      catch (DataException de)
      { // Database error getting sidebox list
	return new ErrorBox("Database Error","Error getting sidebox list: " + de.getMessage(),"top");

      } // end catch

    } // end if ("BA" command)

    // command not found!
    logger.error("invalid command to Settings.doGet: " + cmd);
    return new ErrorBox("Internal Error","Invalid command to Settings.doGet","top");

  } // end doVenicePost

} // end class Settings
