/*
 * BICatalogAppSettings.java
 *
 * Copyright © 1994-2004, Oracle. All rights reserved. Oracle grants
 * you ("Licensee") a non-exclusive, royalty-free, worldwide license to use,
 * modify and redistribute this software in source and binary code form, provided
 * that (i) this copyright notice and license appear on all copies of the
 * software; (ii) Licensee does not utilize the software in a manner disparaging
 * to Oracle; and (iii) Licensee does not utilize the software in a manner that
 * violates the terms of any Licensee agreement with Oracle.
 */
package samples.javaclient;

import java.io.StringReader;
import java.io.PrintWriter;
import java.io.StringWriter;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import oracle.xml.parser.v2.DOMParser;

import oracle.dss.util.persistence.AggregateInfo;
import oracle.dss.util.persistence.BIPersistenceException;
import oracle.dss.util.persistence.Persistable;
import oracle.dss.util.persistence.PersistableAttributes;

import oracle.dss.security.BIUser;

/**
 * This is the application settings class. It currently stores the following:
 * <ol>
 * <li>The active path of the ObjectChooser</li>
 * <li>The six most recently used (MRU) components in the catalog </li>
 * </ol>
 */
public class BICatalogAppSettings implements Persistable {
  // Contains the last path used by the ObjectChooser
  private String m_lastPath  = "";

  // PersistableAttributes, are used for multiple set/get-Persistable
  // attributes calls
  private PersistableAttributes m_persistableAttributes;

  // Contains the MRUs
  private Vector m_mru       = new Vector();

  // Maximum number MRUs
  private int    m_mruLength = 6;

  /**
   * Add an MRU item
   *
   * @param name   the mru value to add
   */
  public void addMRU(String name) {
    // If the MRU value already exists, then remove it
    m_mru.remove(name);

    // If MRU size is at maximum length, remove the oldest (first) one
    if (m_mru.size() == m_mruLength) {
      m_mru.removeElementAt(0);
    }
    // add the mru item
    m_mru.addElement(name);
  }

  /**
   * Get the current path
   *
   * @return  The current path
   */
  public String getLastPath() {
    return m_lastPath;
  }

  /**
   * Retrieve the PersistableAttributes, a component has to return these. The
   * only required setting is the objecttype. It is advisable to return the
   * instance that was supplied by the setPersistable attributes in order to
   * allow the NamedObjects to work properly
   *
   * @return the PersistableAttributes
   */
  public PersistableAttributes getPersistableAttributes(
                                 PersistableAttributes attrs) {
    // Retrieve the Persistable attributes
    if (m_persistableAttributes == null) {
      // If there are no attributes, create them
      m_persistableAttributes = new PersistableAttributes();
      m_persistableAttributes.setObjectType("ApplicationSettings");
    }
    return m_persistableAttributes;
  }

  /**
   * Retrieve the Persistable components, used when a component contains other
   * Persistable components. For example a Graph containing a Query and the
   * Query containing Calculations and Selections. Not used in this component
   *
   * @return an array of AggregateInfos
   */
  public AggregateInfo[] getPersistableComponents() {
    // This component does not have aggregates, we can return null
    return null;
  }

  /**
   * Retrieve the settings state as XML
   *
   * @return a string with the xml representation of the settings
   */
  public String getXMLAsString() throws BIPersistenceException {
    String _xml = null;
    try {
      // Create a string writer to write our xml to
      StringWriter _stringWriter = new StringWriter();
      // Create a printWriter based on the StringWriter to make writing easier
      PrintWriter _pw = new PrintWriter(_stringWriter);

      // Start writing the XML in the writer
      // Write the xml header
      _pw.println("<?xml version=\"1.0\"?>");
      // Write our top XML tag
      _pw.println("<ApplicationSettings>");
      // Add the mru items in the MRU tag element
      for (Enumeration en = m_mru.elements(); en.hasMoreElements();) {
        _pw.println("  <MRU>"+en.nextElement()+"</MRU>");
      }
      // write the current path in the Path element
      _pw.println("  <Path>"+m_lastPath+"</Path>");
      // close our top tag
      _pw.println("</ApplicationSettings>");
      // close the writer
      _pw.close();

      // Convert the writer to a String
      _xml = _stringWriter.toString();
    }
    catch (Exception e) {
      throw new BIPersistenceException("Error creating XML", e);
    }
    // return the xml String
    return _xml;
  }

  /**
   * Initialize the component with environment settings, useful for
   * communication between an application and a component. In this case we do
   * nothing
   *
   * @param a Hashtable with the environment settings
   */
  public void initialize(Hashtable env) {
    // This component does nothing during initialization
  }

  /**
   * Get all the MRU items
   *
   * @return an enumeration of MRU items
   */
  public Enumeration MRUs() {
    return m_mru.elements();
  }

  /**
   * Remove an mru item
   *
   * @param name   the mru value to remove
   */
  public void removeMRU(String name) {
    m_mru.remove(name);
  }

  /**
   * Set the current path
   *
   * @param path   The current path
   */
  public void setLastPath(String path) {
    m_lastPath = path;
  }

  /**
   * Apply the PersistableAttributes. We just keep them around for the
   * getPersistable attributes.
   *
   * @param the PersistableAttributes
   */
  public void setPersistableAttributes(PersistableAttributes attrs) {
    // Persistable attributes are needed for the next
    // getPersistableAttributes call
    m_persistableAttributes = attrs;
  }

  /**
   * Apply the Persistable components. Not used in this component
   *
   * @param an array of AggregateInfos
   */
  public void setPersistableComponents(AggregateInfo[] persistables) {
    // This component does not have aggregates we can ignore this
  }

  /**
   * Apply the XML string to the settings state. We will first parse the String
   * in an XMLDocument, and then we will query the DOM document for the state
   * and apply it ourselves.
   *
   * @param a string with the xml representation of the settings
   */
  public boolean setXMLAsString(String xml) throws BIPersistenceException {
    // We will use the Oracle parser to parse this XML String
    Document _doc     = null;

    // Create an oracle.xml.parser.v2.DOMParser to parse the XML into the
    // document.
    DOMParser _parser = new DOMParser();

    // Open a reader on the String
    StringReader _reader = new StringReader(xml);

    try {
      // Parse the document from the Reader
      _parser.parse(_reader);

      // Get the parsed XML Document from the parser
      _doc = _parser.getDocument();

      // Now get the rootElement <ApplicationSettings>
      Element _root = _doc.getDocumentElement();

      // Reset the contents of settings
      reset();

      // Get the MRU elements
      NodeList _mruList = _root.getElementsByTagName("MRU");

      // Check if there are MRU items
      if (_mruList != null) {
        for (int i = 0; i < _mruList.getLength(); i++) {

          // Get the mru Node for this index
          Node mruNode = _mruList.item(i);

          // Get the mru value from the node
          String _mruValue = mruNode.getFirstChild().getNodeValue();

          // add the mru value to the list
          addMRU(_mruValue);
        }
      }

      // Get the path element
      NodeList _pathList = _root.getElementsByTagName("Path");
      // Check whether there is a path item
      if (_pathList != null && _pathList.getLength() > 0) {
        // Get the first path Node
        Node _pathNode = _pathList.item(0);
        // If there is a path value
        if (_pathNode.getFirstChild() != null)
        {
          // get the node path value and assign it to the path
          setLastPath(_pathNode.getFirstChild().getNodeValue());
        }
      }
    }
    catch (Exception e) {
      throw new BIPersistenceException("Error parsing/Applying XML", e);
    }
    return true;
  }

  /**
   * Reset the settings state.
   */
  private void reset() {
    m_mru.clear();
    m_lastPath = "";
  }
}
