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

import java.io.Writer;
import java.io.IOException;
import java.util.*;
import javax.servlet.*;
import com.silverwrist.util.StringUtil;
import com.silverwrist.venice.core.*;
import com.silverwrist.venice.except.*;

public class FindData implements JSPRender, SearchMode
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  // Attribute name for request attribute
  protected static final String ATTR_NAME = "com.silverwrist.venice.content.FindData";

  // The various display categories
  public static final int FD_COMMUNITIES = 0;
  public static final int FD_USERS = 1;
  public static final int FD_CATEGORIES = 2;

  // The titles and URLs of the header data
  private static Vector header_titles = null;
  private static Vector header_urls = null;

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

  private VeniceEngine engine;
  private UserContext user;
  private int disp;
  private int field = -1;
  private int mode = -1;
  private String term = null;
  private int offset = 0;
  private CategoryDescriptor cat = null;
  private List subcats = null;
  private List results = null;
  private int find_count = -1;

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

  public FindData(VeniceEngine engine, UserContext user, int disp)
  {
    this.engine = engine;
    this.user = user;
    this.disp = disp;

    if (header_titles==null)
    { // construct the title and URL vectors
      header_titles = new Vector();
      header_titles.add("Communities");
      header_titles.add("Users");
      header_titles.add("Categories");
      header_titles.trimToSize();

      header_urls = new Vector();
      header_urls.add("find?disp=" + String.valueOf(FD_COMMUNITIES));
      header_urls.add("find?disp=" + String.valueOf(FD_USERS));
      header_urls.add("find?disp=" + String.valueOf(FD_CATEGORIES));
      header_urls.trimToSize();

    } // end if

  } // end constructor

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

  private static int getParamInt(ServletRequest request, String name, int default_val)
  {
    String str = request.getParameter(name);
    if (str==null)
      return -1;

    try
    { // parse the integer value
      return Integer.parseInt(str);

    } // end try
    catch (NumberFormatException nfe)
    { // in case of conversion error, return default
      return default_val;

    } // end catch

  } // end getParamInt

  private static boolean isImageButtonClicked(ServletRequest request, String name)
  {
    String val = request.getParameter(name + ".x");
    return (val!=null);

  } // end isImageButtonClicked

  /*--------------------------------------------------------------------------------
   * External static functions
   *--------------------------------------------------------------------------------
   */

  public static int getNumChoices()
  {
    return FD_CATEGORIES + 1;

  } // end getNumChoices

  public static FindData retrieve(ServletRequest request)
  {
    return (FindData)(request.getAttribute(ATTR_NAME));

  } // end retrieve

  /*--------------------------------------------------------------------------------
   * Implementations from interface VeniceContent
   *--------------------------------------------------------------------------------
   */

  public String getPageTitle(RenderData rdat)
  {
    return "Find";

  } // end getPageTitle

  public String getPageQID()
  {
    return null;

  } // end getPageQID

  /*--------------------------------------------------------------------------------
   * Implementations from interface JSPRender
   *--------------------------------------------------------------------------------
   */

  public void store(ServletRequest request)
  {
    request.setAttribute(ATTR_NAME,this);

  } // end store

  public String getTargetJSPName()
  {
    return "find.jsp";

  } // end getTargetJSPName

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

  public void writeHeader(RenderData rdat, Writer out) throws IOException
  {
    rdat.writeContentSelectorHeader(out,"Find:",header_titles,header_urls,disp);

  } // end writeHeader

  public int getDisplayOption()
  {
    return disp;

  } // end getDisplayOption

  public int getSearchField()
  {
    return field;

  } // end getSearchField

  public boolean searchFieldIs(int value)
  {
    return (value==field);

  } // end searchFieldIs

  public int getSearchMode()
  {
    return mode;

  } // end getSearchMode

  public boolean searchModeIs(int value)
  {
    return (value==mode);

  } // end searchModeIs

  public String getSearchTerm()
  {
    return term;

  } // end getSearchTerm

  public CategoryDescriptor getCategory()
  {
    return cat;

  } // end getCategory

  public List getSubCategoryList()
  {
    return subcats;

  } // end getSubCategoryList

  public List getResultsList()
  {
    return results;

  } // end getResultsList

  public int getNumResultsDisplayed()
  {
    return engine.getStdNumSearchResults();

  } // end getNumResultsDisplayed

  public int getFindCount()
  {
    return find_count;

  } // end getFindCount

  public int getOffset()
  {
    return offset;

  } // end getOffset

  public void loadGet(int catid) throws DataException
  {
    if (disp==FD_COMMUNITIES)
    { // fill in the list of subcategories and of communities in this category
      cat = user.getCategoryDescriptor(catid);
      subcats = cat.getSubCategories();
      if (cat.getCategoryID()>=0)
      { // fill in the communities that are in this category
	results = user.getCommunitiesInCategory(cat,offset,getNumResultsDisplayed());
	find_count = user.getNumCommunitiesInCategory(cat);

      } // end if
      field = FIELD_COMMUNITY_NAME;

    } // end if
    else if (disp==FD_USERS)
      field = FIELD_USER_NAME;

    mode = SEARCH_PREFIX;
    term = "";

  } // end loadGet

  public void loadPost(ServletRequest request) throws ValidationException, DataException
  {
    int catid = -1;

    // Retrieve all the posted parameters from the form and validate them.  First validate the
    // category ID (if specified) and the field identifier.
    switch (disp)
    {
      case FD_COMMUNITIES:
        catid = getParamInt(request,"cat",-1);
	if (!engine.isValidCategoryID(catid))
	  throw new ValidationException("The category ID parameter is not valid.");
        field = getParamInt(request,"field",FIELD_COMMUNITY_NAME);
	if ((field!=FIELD_COMMUNITY_NAME) && (field!=FIELD_COMMUNITY_SYNOPSIS))
	  throw new ValidationException("The field search parameter is not valid.");
        break;

      case FD_USERS:
        field = getParamInt(request,"field",FIELD_USER_NAME);
	if (   (field!=FIELD_USER_NAME) && (field!=FIELD_USER_DESCRIPTION) && (field!=FIELD_USER_GIVEN_NAME)
	    && (field!=FIELD_USER_FAMILY_NAME))
	  throw new ValidationException("The field search parameter is not valid.");
	break;

      case FD_CATEGORIES:
	// no parameters to set here - there's no "field" for category search
        break;

      default:
	throw new InternalStateError("loadPost failure - invalid display parameter");

    } // end switch

    // Validate the search mode parameter.
    mode = getParamInt(request,"mode",SEARCH_PREFIX);
    if ((mode!=SEARCH_PREFIX) && (mode!=SEARCH_SUBSTRING) && (mode!=SEARCH_REGEXP))
      throw new ValidationException("The search mode parameter is not valid.");

    // Retrieve the search term parameter.
    term = request.getParameter("term");
    if (term==null)
      term = "";

    // Retrieve the offset and find count parameters.
    offset = getParamInt(request,"ofs",0);
    find_count = getParamInt(request,"fcount",-1);

    // Adjust the search return offset based on the command button click.
    int count = getNumResultsDisplayed();
    if (isImageButtonClicked(request,"search"))
      offset = 0;
    else if (isImageButtonClicked(request,"previous"))
    { // adjust the offset in the reverse direction
      offset -= count;
      if (offset<0)
	offset = 0;

    } // end else if
    else if (isImageButtonClicked(request,"next"))
      offset += count;  // go forwards instead
    else
      throw new ValidationException("Unable to determine what action triggered the form.");

    // Run the actual search.
    switch (disp)
    {
      case FD_COMMUNITIES:
	if (catid>=0)
	{ // retrieve the category descriptor and the subcategory list
	  cat = user.getCategoryDescriptor(catid);
	  subcats = cat.getSubCategories();
	  if (cat.getCategoryID()>=0)
	  { // fill in the communities that are in this category
	    results = user.getCommunitiesInCategory(cat,offset,count);
	    if (find_count<0)
	      find_count = user.getNumCommunitiesInCategory(cat);

	  } // end if

	} // end if
	else
	{ // retrieve the community search data
	  results = user.searchForCommunities(field,mode,term,offset,count);
	  if (find_count<0)
	    find_count = user.getSearchCommunityCount(field,mode,term);

	} // end else
	break;

      case FD_USERS:
	results = engine.searchForUsers(field,mode,term,offset,count);
	if (find_count<0)
	  find_count = engine.getSearchUserCount(field,mode,term);
	break;

      case FD_CATEGORIES:
	results = user.searchForCategories(mode,term,offset,count);
	if (find_count<0)
	  find_count = user.getSearchCategoryCount(mode,term);
	break;

    } // end switch

  } // end loadPost

  public static String getCatJumpLink(RenderData rdat, int catid)
  {
    return rdat.getEncodedServletPath("find?disp=" + String.valueOf(FD_COMMUNITIES) + "&cat="
				      + String.valueOf(catid));

  } // end getCatJumpLink

} // end class FindData
