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

import java.io.*;
import org.apache.log4j.*;
import com.silverwrist.util.IOUtil;
import com.silverwrist.util.cache.CacheMap;
import com.silverwrist.venice.ui.*;
import com.silverwrist.venice.ui.helpers.*;

public class FrameServlet extends BaseServlet
{
  /*--------------------------------------------------------------------------------
   * Internal class for returning the framed data.
   *--------------------------------------------------------------------------------
   */

  static class FramedData implements ContentDirect
  {
    private String locator;               // static locator identity
    private File file;                    // the actual file we're retrieving
    private long last_update;             // when was file last updated?
    private boolean processed = false;    // have we processed this file?
    private String title = null;          // the actual title
    private String content = null;        // the actual content

    FramedData(String locator, String filename) throws ErrorBox
    {
      this.locator = locator;
      this.file = new File(filename);
      if (!(file.canRead()))
      { // the file does not exist!
	logger.error("FramedData: file \"" + filename + "\" not accessible");
	throw new ErrorBox(null,"The static document \"" + locator + "\" was not found on the disk.",null);

      } // end if

      this.last_update = file.lastModified();

    } // end constructor

    private synchronized void process()
    {
      if (processed)
      { // check to see if the file's been modified
	long new_last_update = file.lastModified();
	if (last_update!=new_last_update)
	{ // been updated - need to reprocess!
	  last_update = new_last_update;
	  title = null;
	  content = null;
	  processed = false;

	} // end if

      } // end if

      if (processed)
	return;  // don't need to re-process

      // Read in the whole thing.
      StringBuffer raw_data;
      try
      { // read in from the file
	raw_data = IOUtil.loadText(file);

      } // end try
      catch (IOException ioe)
      { // I/O exception - just discard
	title = locator;
	content = "I/O error reading " + locator + ": " + ioe.getMessage();
	return;

      } // end catch

      // make the upper-case search page and use that to locate the page title and body
      String search_page = raw_data.toString().toUpperCase();
      title = searchBetweenTags(raw_data,search_page,"TITLE");
      content = searchBetweenTags(raw_data,search_page,"BODY");
      if (content==null)
      { // no content?
	content = "No content seen on " + locator;
	processed = false;

      } // end if

      processed = true;  // set the flag to indicate we've got everything

    } // end process

    public boolean needFrame()
    {
      return true;

    } // end needFrame

    public int getMenuSelector()
    {
      return MENU_SELECTOR_NOCHANGE;

    } // end getMenuSelector

    public String getPageTitle(RequestOutput ro)
    {
      process();
      return title;

    } // end getPageTitle

    public String getPageQID()
    {
      return locator;

    } // end getPageQID

    public void render(RequestOutput out) throws IOException
    {
      process();
      out.write(content);
      out.flush();

    } // end render

  } // end class FramedData

  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

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

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

  private CacheMap cache = new CacheMap(15,25);

  /*--------------------------------------------------------------------------------
   * Internal operations
   *--------------------------------------------------------------------------------
   */

  private static String searchBetweenTags(StringBuffer data, String search, String tagname)
  {
    tagname = tagname.toUpperCase();
    String start = "<" + tagname;
    String end = "</" + tagname + ">";

    int startpos = search.indexOf(start);
    if (startpos<0)
      return null;
    startpos += start.length();

    int bkt_pos = search.indexOf('>',startpos);
    if (bkt_pos<0)
      return null;

    int end_pos = search.indexOf(end,++bkt_pos);
    if (end_pos<0)
      return data.substring(bkt_pos);
    else
      return data.substring(bkt_pos,end_pos);

  } // end searchBetweenTags

  /*--------------------------------------------------------------------------------
   * Implementations from class BaseServlet
   *--------------------------------------------------------------------------------
   */

  public Object process(RequestInput req) throws ThrowableContent
  {
    String page_name = req.getPathInfo().substring(1);
    FramedData rc = null;
    synchronized (cache)
    { // look up and see if we already have the page data cached
      rc = (FramedData)(cache.get(page_name));
      if (rc==null)
      { // we have to map the name to a static path and thence to a real filename
	HTMLRendering html = (HTMLRendering)(req.queryService(HTMLRendering.class));
	String locator = html.getStaticPath(page_name);
	String real_path = req.mapPath(locator);
	if (real_path==null)
	{ // the mapper doesn't work!
	  logger.error("FrameServlet: locator \"" + locator + "\" does not map");
	  return new ErrorBox(null,"The static document \"" + locator + "\" was not found.",null);

	} // end if

	// create new FramedData object and add it to the cache
	rc = new FramedData(locator,real_path);  // may throw an ErrorBox
	cache.put(page_name,rc);

      } // end if

    } // end synchronized block

    return rc;

  } // end process

} // end class FrameServlet
