/*
 * 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.awt.Dimension;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.log4j.*;
import com.silverwrist.util.StringUtil;
import com.silverwrist.venice.core.*;
import com.silverwrist.venice.except.*;

public class TopicPosts implements JSPRender
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

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

  private static int SCALING_NUM = 1;
  private static int SCALING_DENOM = 2;

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

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

  private VeniceEngine engine;
  private CommunityContext comm;
  private ConferenceContext conf;
  private TopicContext topic;
  private int first;
  private int last;
  private boolean show_advanced;
  private boolean no_bozos;
  private int unread;
  private List messages;
  private TopicVisitOrder visit_order;
  private String topic_stem;
  private String topic_qid;
  private String cache_locator = null;
  private HashSet bozo_uids = new HashSet();
  private Dimension photo_size = null;
  private HashMap uid_photos = null;

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

  public TopicPosts(HttpServletRequest request, VeniceEngine engine, UserContext user, CommunityContext comm,
		    ConferenceContext conf, TopicContext topic, int first, int last, boolean read_new,
		    boolean show_advanced, boolean no_bozos) throws DataException, AccessError
  {
    if (logger.isDebugEnabled())
      logger.debug("TopicPosts: comm=" + comm.getCommunityID() + ", conf=" + conf.getConfID() + ", topic="
		   + topic.getTopicNumber() + ", range=[" + first + ", " + last + "], rnm=" + read_new
		   + ", shac=" + show_advanced + ", nbz=" + no_bozos);
    this.engine = engine;
    this.comm = comm;
    this.conf = conf;
    this.topic = topic;
    this.first = first;
    this.last = last;
    this.show_advanced = show_advanced;
    this.no_bozos = no_bozos;
    this.unread = topic.getUnreadMessages();
    if (read_new)
      topic.setUnreadMessages(0);
    if (logger.isDebugEnabled())
      logger.debug(this.unread + " unread messages");
    this.messages = topic.getMessages(first,last);
    this.visit_order = TopicVisitOrder.retrieve(request.getSession(true),conf.getConfID());
    if (visit_order!=null)
      visit_order.visit(topic.getTopicNumber());
    List aliases = conf.getAliases();
    topic_stem = (String)(aliases.get(0)) + "." + topic.getTopicNumber() + ".";
    topic_qid = "go/" + comm.getAlias() + "!" + (String)(aliases.get(0)) + "." + topic.getTopicNumber();

    // build up the list of users IN THIS VIEW that are bozo-filtered
    HashSet saw_users = new HashSet();
    if (conf.displayPostPictures() && user.displayPostPictures())
    { // build up the mapping of UIDs to photo URLs
      Dimension psz = engine.getUserPhotoSize();
      photo_size = new Dimension((psz.width * SCALING_NUM) / SCALING_DENOM,
				 (psz.height * SCALING_NUM) / SCALING_DENOM);
      uid_photos = new HashMap();

    } // end if

    Iterator it = messages.iterator();
    while (it.hasNext())
    { // get the user IDs of all messages on this page
      TopicMessageContext msg = (TopicMessageContext)(it.next());
      Integer the_uid = new Integer(msg.getCreatorUID());
      boolean get_photo;
      if (!(saw_users.contains(the_uid)))
      { // only check user IDs once per display operation
	saw_users.add(the_uid);
	get_photo = true;
	if (topic.isBozo(the_uid.intValue()))
	{ // shall we get the user photo?
	  bozo_uids.add(the_uid);
	  get_photo = no_bozos;

	} // end if

	if (conf.displayPostPictures() && user.displayPostPictures() && get_photo)
	{ // look up the user photo URL
	  UserProfile prof = user.getProfile(the_uid.intValue());
	  String url = prof.getPhotoURL();
	  if (url!=null)
	    uid_photos.put(the_uid,url);

	} // end else if

      } // end if

    } // end while

  } // end constructor

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

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

  } // end retrieve

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

  public String getPageTitle(RenderData rdat)
  {
    return topic.getName() + ": " + topic.getTotalMessages() + " Total; " + unread + " New; Last: "
           + rdat.formatDateForDisplay(topic.getLastUpdateDate());

  } // end getPageTitle

  public String getPageQID()
  {
    return topic_qid;

  } // end getPageQID

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

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

  } // end store

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

  } // end getTargetJSPName

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

  public static String getPosterName(TopicMessageContext msg)
  {
    try
    { // have to guard agains a DataException here
      return msg.getCreatorName();

    } // end try
    catch (DataException de)
    { // just return "unknown" on failure
      return "(unknown)";

    } // end catch

  } // end getPosterName

  public static String getMessageBodyText(TopicMessageContext msg)
  {
    try
    { // have to guard against a DataException here
      return msg.getBodyText();

    } // end try
    catch (DataException de)
    { // just return an error message
      return "<EM>(Unable to retrieve message data: " + StringUtil.encodeHTML(de.getMessage()) + ")</EM>";

    } // end catch

  } // end getMessageBodyText

  public int getCommunityID()
  {
    return comm.getCommunityID();

  } // end getCommunityID

  public int getConfID()
  {
    return conf.getConfID();

  } // end getConfID

  public int getTopicNumber()
  {
    return topic.getTopicNumber();

  } // end getTopicNumber

  public int getNextTopicNumber()
  {
    if (visit_order!=null)
      return visit_order.getNext();
    else
      return -1;

  } // end getNextTopicNumber

  public String getConfLocator()
  {
    StringBuffer buf = new StringBuffer("sig=");
    buf.append(comm.getCommunityID()).append("&conf=").append(conf.getConfID());
    return buf.toString();

  } // end getConfLocator

  public String getLocator()
  {
    if (cache_locator==null)
    { // build up the standard locator
      StringBuffer buf = new StringBuffer("sig=");
      buf.append(comm.getCommunityID()).append("&conf=").append(conf.getConfID()).append("&top=");
      buf.append(topic.getTopicNumber());
      cache_locator = buf.toString();

    } // end if

    return cache_locator;

  } // end getLocator

  public String getNextLocator()
  {
    StringBuffer buf = new StringBuffer("sig=");
    buf.append(comm.getCommunityID()).append("&conf=").append(conf.getConfID());
    if (visit_order!=null)
      buf.append("&top=").append(visit_order.getNext());
    return buf.toString();

  } // end getNextLocator

  public String getRestoreLocator()
  {
    StringBuffer buf = new StringBuffer("rtop=");
    buf.append(topic.getTopicNumber()).append("&rct=").append(unread);
    return buf.toString();

  } // end getRestoreLocator

  public String getIdentifyingData()
  {
    StringBuffer buf = new StringBuffer("Posts ");
    buf.append(first).append(" through ").append(last).append(" in topic #").append(topic.getTopicID());
    return buf.toString();

  } // end getIdentifyingData

  public String getTopicName()
  {
    return topic.getName();

  } // end getTopicName

  public int getTotalMessages()
  {
    return topic.getTotalMessages();

  } // end getTotalMessages

  public int getNewMessages()
  {
    return unread;

  } // end getNewMessages

  public Date getLastUpdate()
  {
    return topic.getLastUpdateDate();

  } // end getLastUpdate

  public boolean isTopicHidden()
  {
    return topic.isHidden();

  } // end isTopicHidden

  public boolean canDoNextTopic()
  {
    if (visit_order!=null)
      return visit_order.isNext();
    else
      return false;

  } // end canDoNextTopic

  public boolean canFreezeTopic()
  {
    return topic.canFreeze();

  } // end canFreezeTopic

  public boolean isTopicFrozen()
  {
    return topic.isFrozen();

  } // end isTopicFrozen

  public boolean canArchiveTopic()
  {
    return topic.canArchive();

  } // end canArchiveTopic

  public boolean isTopicArchived()
  {
    return topic.isArchived();

  } // end isTopicArchived

  public boolean canDeleteTopic()
  {
    return topic.canDelete();

  } // end canDeleteTopic

  public boolean canScrollUp()
  {
    return (first>0);

  } // end canScrollUp

  public String getScrollUpLocator()
  {
    int new_first = first - engine.getNumPostsPerPage();
    int new_last = first - 1;
    if (new_first<0)
    { // normalize so we start at 0
      new_last += (-new_first);
      new_first = 0;

    } // end if

    StringBuffer buf = new StringBuffer("p1=");
    buf.append(new_first).append("&p2=").append(new_last);
    return buf.toString();

  } // end getScrollUpLocator

  public boolean canScrollDown()
  {
    return ((topic.getTotalMessages() - (1 + last))>0);

  } // end canScrollDown

  public String getScrollDownLocator()
  {
    int new_last = last + engine.getNumPostsPerPage();
    int my_last = topic.getTotalMessages() - 1;
    if (new_last>my_last)
      new_last = my_last;  // normalize so we end at the last post
    StringBuffer buf = new StringBuffer("p1=");
    buf.append(last+1).append("&p2=").append(new_last);
    return buf.toString();

  } // end getScrollDownLocator

  public boolean canScrollToEnd()
  {
    return ((topic.getTotalMessages() - (1 + last))>0);

  } // end canScrollToEnd

  public String getScrollToEndLocator()
  {
    int my_last = topic.getTotalMessages();
    StringBuffer buf = new StringBuffer("p1=");
    buf.append(my_last-engine.getNumPostsPerPage()).append("&p2=").append(my_last-1);
    return buf.toString();

  } // end getScrollToEndLocator

  public Iterator getMessageIterator()
  {
    return messages.iterator();

  } // end getMessageIterator()

  public boolean emitBreakLinePoint(int msg)
  {
    return (msg==(topic.getTotalMessages()-unread));

  } // end emitBreakLinePoint

  public boolean showAdvanced()
  {
    return show_advanced && (last==first);

  } // end showAdvanced

  public boolean displayPostBox()
  {
    boolean flag1 = conf.canPostToConference();
    boolean flag2 = (topic.isFrozen() ? topic.canFreeze() : true);
    boolean flag3 = (topic.isArchived() ? topic.canArchive() : true);
    return flag1 && flag2 && flag3;

  } // end displayPostBox

  public String getDefaultPseud()
  {
    return conf.getDefaultPseud();

  } // end getDefaultPseud

  public String getMessageReference(TopicMessageContext msg)
  {
    return topic_stem + msg.getPostNumber();

  } // end getMessageReference

  public int getNumPostsPerPage()
  {
    return engine.getNumPostsPerPage();

  } // end getNumPostsPerPage

  public boolean displayAttachmentInNewWindow(TopicMessageContext msg)
  {
    if (!(msg.hasAttachment()))
      return false;
    String type = msg.getAttachmentType();
    return (type.startsWith("text/") || type.startsWith("image/"));

  } // end displayAttachmentInNewWindow

  public boolean bozoFilterUser(int uid)
  {
    if (no_bozos)
      return false;
    else
      return bozo_uids.contains(new Integer(uid));

  } // end bozoFilterUser

  public boolean showBozoFilteredIndicator(int uid)
  {
    if (no_bozos)
      return bozo_uids.contains(new Integer(uid));
    else
      return false;

  } // end showBozoFilteredIndicator

  public boolean showFilterButton(int uid)
  {
    return !(bozo_uids.contains(new Integer(uid))) && topic.canSetBozo(uid);

  } // end showFilterButton

  public String getUserPhotoTag(int uid, RenderData rdat)
  {
    if (photo_size==null)
      return "";  // user photos not enabled
    StringBuffer buf = new StringBuffer("<IMG SRC=\"");
    String url = (String)(uid_photos.get(new Integer(uid)));
    if (url==null)
      url = rdat.getPhotoNotAvailURL();
    buf.append(url).append("\" ALT=\"\" WIDTH=").append(photo_size.width).append(" HEIGHT=");
    buf.append(photo_size.height).append(" ALIGN=LEFT BORDER=0 HSPACE=2 VSPACE=2>");
    return buf.toString();

  } // end getUserPhotoTag

  public boolean displayPostPictures()
  {
    return (photo_size!=null);

  } // end displayPostPictures

} // end class TopicPosts
