/*
 * 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) 2002-03 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.dynamo.servlet;

import java.io.*;
import java.util.*;
import org.apache.log4j.Logger;
import com.silverwrist.util.*;

/**
 * Manages the browser capabilities database.  The database is based on the standard BROWSCAP.INI data file
 * format, Microsoft-compatible; this code turns the database into a series of 
 * {@link com.silverwrist.dynamo.servlet.BrowserDatabaseEntry BrowserDatabaseEntry} objects which can be
 * searched for a match.
 * <P>BROWSCAP.INI managed by Gary J. Keith, &lt;http://www.garykeith.com/index.asp&gt;
 *
 * @author Eric J. Bowersox &lt;erbo@silcom.com&gt;
 * @version X
 */
public class BrowserDatabase
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  private static Logger logger = Logger.getLogger(BrowserDatabase.class);

  private static BrowserDatabase _self = null;  // our singleton instance

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

  private boolean m_broken = false;                    // true if we had an error in loading
  private ArrayList m_browser_list = new ArrayList();  // the actual list

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

  /**
   * Creates the <CODE>BrowserDatabase</CODE> object, loading the database from the <CODE>browscap.ini</CODE>
   * file resource.
   */
  private BrowserDatabase()
  {
    InputStream stm = null;
    BufferedReader rdr = null;
    try
    { // load the contents of the browscap.ini file
      stm = this.getClass().getResourceAsStream("browscap.ini");
      rdr = new BufferedReader(new InputStreamReader(stm));
      String line;
      BrowserDatabaseEntry current = null;
      while ((line = rdr.readLine())!=null)
      { // read in lines from the resource
	line = line.trim();
	if ((line.length()==0) || line.startsWith(";"))
	  continue;  // blank line or comment
	if (line.startsWith("[") && line.endsWith("]"))
	{ // start of new browser entry
	  current = new BrowserDatabaseEntry(line.substring(1,line.length()-1));
	  m_browser_list.add(current);

	} // end if

	if (current!=null)
	{ // break the line at the equals sign
	  int p = line.indexOf('=');
	  if (p!=-1)
	  { // separate the name and value, and stow them
	    String name = line.substring(0,p).trim();
	    String value = line.substring(p+1).trim();
	    if (value.startsWith("#"))
	      value = value.substring(1);
	    current.addValue(name,value);

	  } // end if

	} // end if

      } // end while

    } // end try
    catch (IOException e)
    { // WTF?  this is bad!
      logger.fatal("Error loading BROWSCAP.INI database",e);
      m_broken = true;

    } // end catch
    finally
    { // shut down the stream
      IOUtils.shutdown(rdr);
      IOUtils.shutdown(stm);

    } // end finally

  } // end constructor

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

  /**
   * Looks up an entry in the browser database.
   *
   * @param agent The User-Agent string from the browser to look up.
   * @return The {@link com.silverwrist.dynamo.servlet.BrowserDatabaseEntry BrowserDatabaseEntry} matching the
   *         specified User-Agent.  If no match can be found, returns <CODE>null</CODE>.
   */
  BrowserDatabaseEntry lookup(String agent)
  {
    if (m_broken)
      return null;  // database wasn't loaded

    Iterator it = m_browser_list.iterator();
    while (it.hasNext())
    { // look for the browser database entry
      BrowserDatabaseEntry bde = (BrowserDatabaseEntry)(it.next());
      if (bde.match(agent))
	return bde;

    } // end while

    return null;

  } // end lookup

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

  /**
   * Returns the singleton instance of <CODE>BrowserDatabase</CODE>.
   *
   * @return The singleton instance of <CODE>BrowserDatabase</CODE>.
   */
  public static BrowserDatabase get()
  {
    if (_self==null)
      _self = new BrowserDatabase();
    return _self;

  } // end get

} // end class BrowserDatabase
