/*
 * AnalyzerConnection.java
 *
 * Copyright (c) 2003, Oracle Corporation. 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.analyzer;

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.io.File;

import java.lang.Exception;
import java.lang.Integer;

import java.sql.*;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.JToggleButton;

import oracle.dss.appmodule.client.BISession;
import oracle.dss.appmodule.client.BISessionException;
import oracle.dss.bicontext.ManagerFactory;
import oracle.dss.connection.client.Connection;
import oracle.dss.connection.common.ConnectionException;
import oracle.dss.connection.common.CB;
import oracle.dss.dataSource.client.QueryManager;
import oracle.dss.metadataManager.client.MetadataManager;
import oracle.dss.metadataManager.common.MDRoot;
import oracle.dss.metadataManager.common.MM;
import oracle.dss.metadataUtil.MDU;
import oracle.dss.metadataUtil.PropertyBag;
import oracle.dss.persistence.PSRConstants;
import oracle.dss.persistence.persistencemanager.common.PersistenceManagerRuntimeException;
import oracle.dss.security.BIUser;
import oracle.dss.util.DefaultErrorHandler;

import oracle.jdbc.OracleDriver;

/**
 * Connection to the OLAP Catalog and to the BI Beans Catalog.
 * This class performs all the tasks related to connecting to OLAP and
 * the BI Beans Catalog, including auto-connecting from a configuration template, 
 * presenting a dialog to get connection
 * information from the user, connecting to the catalogs, and saving
 * connection information in the configuration file.
 * <p>
 * As part of the connection, this class makes 
 * the following assumptions:
 * <ul>
 * <li>The BI Beans Catalog is installed in the same database as OLAP (source of the data).</li>
 * <li>User is an RDBMS user.</li>
 * <li>A connection to the database is made using the id/pwd supplied by the user.  If the user
 * is successfully authenticated, then the user is automatically added to the BI Beans Catalog.
 * </ul>
 * <p>
 * This class uses several helper objects to access information in the 
 * configuration file:
 * a {@link BIConfigReader},
 * a {@link PersistenceConnection},
 * an {@link OLAPConnection},
 * and a {@link DADFile}.
 * 
 * <p>
 * The main Analyzer class constructs an AnalyzerConnection in its {@link Analyzer#jbInit} method.
 * If the user is automatically connecting, then the Analyzer constructor 
 * calls the {@link #autoConnect} method of this class.
 * If the user is not automatically connecting to the database, then
 * the Analyzer constructor calls the {@link #showConnectDialog} method of this
 * class to display the dialog that collects connection information from the user.
 * <p>
 * This connection is also where other objects get the MetadataManager and
 * the QueryManager for the application. 
 * For example, {@link Analyzer#initializeUI} calls the {@link #getMetadataManager} method
 * of the AnalyzerConnection, and then sets the MetadataManager on the different
 * Explorers.
 */
public class AnalyzerConnection {
  /*
   * User connection fields
   * The assumption here is that the Catalog and OLAP source are the same database 
   * instance
   */
  /**
   * "I" button for displaying more or less information.
   */
  JToggleButton m_moreButton;
  /**
   * Panel that the "I" button displays or hides.
   */
  JPanel m_catalogPanel;
  /**
   * Label for the Catalog UserName in m_catalogPanel.
   * Does not appear if the user connects to a file-based BI Beans Catalog.
   */
  JLabel m_userLabel;
  /**
   * Label for the Catalog User password in m_catalogPanel.
   * Does not appear if the user connects to a file-based BI Beans Catalog.
   */
  JLabel m_passwordLabel;
  /**
   * Label for the Root folder name in a file-based BI Beans Catalog.
   */
  JLabel m_directoryLabel;
  /**
   * Field for the user name.
   */
  JTextField m_OLAPUserName;
  /**
   * Field for the password.
   */
  JPasswordField m_OLAPPassword;
  /**
   * Field for the host name.
   */
  JTextField m_host;    
  /**
   * Field for the port name.
   */
  JTextField  m_port;
  /**
   * Field for the SID.
   */
  JTextField m_sid;  
  /**
   * Field for the user name for connecting to the BI Beans Catalog.
   * Not used if the user connects to file-based BI Beans Catalog.
   */
  JTextField m_catalogUserName;
  /**
   * Field for the password for connecting to the BI Beans Catalog.
   * Not used if the user connects to file-based BI Beans Catalog.
   */
  JPasswordField m_catalogPassword;
  /**
   * Drop-down for selecting a file-based or database BI Beans Catlog.
   */
  JComboBox m_catalogType;
  /**
   * Field for the root folder in a file-based BI Beans Catalog.
   */
  JTextField m_catalogRootFolder;
  /**
   * The configuration file to read.
   */
  String m_configFile;
  /**
   * Default name of the configuration file:"AnalyzerConfig.xml".
   */
  String m_defaultConfigFile = "analyzerConfig.xml";
  /**
   * Default name of the DAD file: "analyzerCatalog.dad".
   */
  String m_defaultCatalogFile = "analyzerCatalog.dad";
  /**
   * The BISession for the application.
   */
  BISession m_session;
  /**
   * The MetadataManager for the application.
   */
  MetadataManager m_metadataManager;
  /**
   * The QueryManager for the application.
   */
  QueryManager m_queryManager;

  /**
   * Whether the BI Beans Catalog is database (true) or file-based (false).
   */
  boolean m_useDatabaseCatalog = false;
  /**
   * Whether the application is connected to the database.
   */
  boolean m_connected = false;
  /**
   * The directory where the user's start-up configuration file is found
   */
   private String m_homeDirectory;
  /**
   * Text for the user name label: "User Name:"
   */
  private static final String OLAP_USER = "User Name:";  
  /**
   * Text for the password label: "Password:".
   */
  private static final String OLAP_PASSWORD = "Password:";  
  /**
   * Text for the dialog box title: "Database Connection Information".
   */
  private static final String m_title = "Database Connection Information";
  /**
   * Text for the file-based Catalog option in the catalog type box: "File System".
   */
  private static final String FILE_SYSTEM = "File System";
  /**
   * Text for the database Catalog option in the catalog type box: "Database".
   */
  private static final String DATABASE = "Database";
  /**
   * Text for the catalog details panel: "Catalog Details:".
   */
  private static final String CATALOG_DETAILS = "Catalog Details:";
  /**
   * Text for the BI Beans Catalog user name label in the catalog details panel:
   * "User Name:"
   */
  private static final String CATALOG_USER = "User Name:";
  /**
   * Text for the BI Beans Catalog password label in the catalog details panel:
   * "Password:"
   */
  private static final String CATALOG_PASSWORD = "Password:";  
  /**
   * Text for the BI Beans Catalog root folder label in the catalog details panel:
   * "Root Folder:".
   */
  private static final String CATALOG_ROOT = "Root Folder:";  
  /**
   * Text for the catalog type drop-down label:"Catalog Type:".
   */
  private static final String CATALOG_TYPE = "Catalog Type:";
  /**
   * Text for the host name label: "Host Name:".
   */
  private static final String HOST = "Host Name:";
  /**
   * Text for the port label: "Port:".
   */
  private static final String PORT = "Port:";
  /**
   * Text for the SID label: "SID:".
   */
  private static final String SID = "SID:";
  /**
   * Text for the Connect button: "Connect".
   */
  private static final String CONNECT = "Connect";
  /**
   * Text for the Cancel button: "Cancel".
   */
  private static final String CANCEL = "Cancel";

  /**
   * The Connection dialog.
   */
  JDialog m_dialog;
  /**
   * The Analyzer application that this Connection connects to the database.
   */
  Analyzer m_analyzer;
  /**
   * The configuration file reader.
   */
  BIConfigReader m_reader;
  /**
   * The OLAP Connection for the application.
   */
  OLAPConnection m_olap;

  /**
   * Constructor.
   * The constructor reads the BIConfig file for the application (Analyzer.xml)
   * if one exists.
   * The Analyzer.jbInit method constructs an instance of this class.
   * 
   * @param analyzer The Analyzer main application class.
   */
  public AnalyzerConnection(Analyzer analyzer)   {
    // Store pointer to the main application class
    m_analyzer = analyzer;

    /*
     * The configuration file contains the default connect information for the user
     * This configuration file is stored in the users document/home directory
     * Create the user's home directory if necessary
     */
    
    m_homeDirectory = System.getProperty("user.home") + System.getProperty("file.separator") +
                      "analyzer" + System.getProperty("file.separator");                        
    m_configFile =  m_homeDirectory + "analyzer.xml";                           
    File homeDir = new File(m_homeDirectory.substring(0, m_homeDirectory.length()-1));
      
    if (!homeDir.isDirectory()) {
      try {
        boolean success = homeDir.mkdir();
      }
      catch (Exception e) {
        System.out.println("Unable to create analyzer home.  Defaulting to user home.");
        m_homeDirectory = System.getProperty("user.home") + System.getProperty("file.separator");
        m_configFile =  m_homeDirectory + "analyzer.xml";     
      }
    }

    try { 
        m_reader = new BIConfigReader(m_configFile);
    }
    catch (Exception e) {
      System.out.println("Unable to read file: " + m_configFile + ".");
    }

  }

  /**
   * Auto-connects to the database.  This uses the configuration details that are 
   * specified in the analyzerTemplate.xml file.
   * 
   * @return <code>true</code> if the connection is successful, 
   *         <code>false</code> if it is not.
   */
  public boolean autoConnect() {
    try {
      String    configFile = "/analyzerTemplate.xml";

      /*
       * Create a new BISession and extract key attributes, including the MetadataManager &
       * QueryManager.  The MM and QM are created automatically when the session is created
       */
      m_session = new BISession(configFile);
      ManagerFactory mf = m_session.getManagerFactory();
      m_metadataManager = (MetadataManager) mf.lookupManager(
                           ManagerFactory.METADATA_MANAGER, null, true);

      m_queryManager = (QueryManager) mf.lookupManager(
                       ManagerFactory.QUERY_MANAGER, null, true);
      m_connected = true;
    }
    catch (Exception e) {
      m_session = null;
      m_metadataManager = null;
      m_queryManager = null;
      m_connected = false;
      e.printStackTrace();
      AnalyzerUtilities au = new AnalyzerUtilities(m_analyzer);
      au.showErrorMessage("Unable to connect to the database using the information specified in the config file.", e);      
      return false;
    }
    
    return true;
  }

  /**
   * Displays the connection dialog box, which asks the user for connection
   * information. 
   * This method uses the collected information to connect both to the
   * OLAP Catalog and to the BI Beans Catalog.
   * 
   * @param parentFrame The Analyzer main application class.
   */
  public void showConnectDialog(JFrame parentFrame) {
    /*
     * Set up dialog fields
     */
    m_dialog = new JDialog(parentFrame, m_title);
    m_dialog.setModal(true);

    // Default fonts
    Font font = new Font("Dialog", 0, 12);
    Font normal = new Font("Dialog", 0, 12);

    // Image displayed on left hand side of dialog
    JLabel lblImage = new JLabel();
    ImageIcon imageConnect = new ImageIcon(
                               Analyzer.class.getResource("images/connect.gif"));     
    lblImage.setIcon(imageConnect);    

    // User ID, Password, Host, Port and Sid
    JLabel lblUserID = new JLabel(OLAP_USER);
    lblUserID.setFont(font);    
    m_OLAPUserName = new JTextField();
    m_OLAPUserName.setFont(normal);
    m_OLAPUserName.setColumns(15);

    JLabel lblPwd = new JLabel(OLAP_PASSWORD);
    lblPwd.setFont(font);    
    m_OLAPPassword = new JPasswordField();
    m_OLAPPassword.setFont(font);

    m_OLAPPassword.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        connect();
        if (isConnected()) {
          disposeConnectDialog();
        }          
      }
    });

    // Host, Port and SID fields
    JLabel lblHost = new JLabel(HOST);
    lblHost.setFont(font);    
    m_host = new JTextField();
    m_host.setFont(normal);
    JLabel lblPort = new JLabel(PORT);
    lblPort.setFont(font);    
    m_port = new JTextField();
    m_port.setFont(normal);
    JLabel lblSID = new JLabel(SID);
    lblSID.setFont(font);    
    m_sid = new JTextField();
    m_sid.setFont(normal);

    // The Catalog could be file system or database
    JLabel lblCatalogType = new JLabel(CATALOG_TYPE);
    lblCatalogType.setFont(font);    
    m_catalogType = new JComboBox();
    m_catalogType.setFont(normal);    
    m_catalogType.addItem(FILE_SYSTEM);
    m_catalogType.addItem(DATABASE);

    m_catalogType.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        // User selects file based catalog - set up connection dialog appropriately
        int _top = 5;
        if (m_catalogType.getSelectedIndex() == 0) {
          m_useDatabaseCatalog = false;
          m_catalogPanel.removeAll();
          m_catalogPanel.add(m_directoryLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0));
          m_catalogPanel.add(m_catalogRootFolder, new GridBagConstraints(1, 0, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));    
        }
        else {
          m_useDatabaseCatalog = true;
          m_catalogPanel.removeAll();
          m_catalogPanel.add(m_userLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0));
          m_catalogPanel.add(m_catalogUserName, new GridBagConstraints(1, 0, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));    
          m_catalogPanel.add(m_passwordLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(_top, 0, 0, 0), 0, 0));    
          m_catalogPanel.add(m_catalogPassword, new GridBagConstraints(1, 1, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(_top, 5, 0, 5), 0, 0));          
        }
        m_dialog.pack();
        m_dialog.validate();
        m_dialog.repaint();

      }
    });

    /*
     * Set up catalog fields
     */
    m_catalogPanel = new JPanel(new GridBagLayout());
    m_catalogPanel.setBorder(BorderFactory.createTitledBorder(CATALOG_DETAILS));
    m_catalogPanel.setVisible(false);
    m_catalogUserName = new JTextField();
    m_catalogUserName.setFont(normal);
    m_catalogUserName.setColumns(15);    
    m_catalogPassword = new JPasswordField();
    m_catalogPassword.setFont(font);     
    m_catalogRootFolder = new JTextField();
    m_userLabel = new JLabel(CATALOG_USER);
    m_userLabel.setFont(font);
    m_passwordLabel = new JLabel(CATALOG_PASSWORD);
    m_passwordLabel.setFont(font);
    m_directoryLabel = new JLabel(CATALOG_ROOT);
    m_directoryLabel.setFont(font);

    // The More button will show/hide the Catalog connection details
    m_moreButton = new JToggleButton(new ImageIcon(
                             Analyzer.class.getResource("images/infoDown.gif")));
    m_moreButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        // Show the Catalog fields on the dialog
        if (m_moreButton.isSelected()) {
          m_moreButton.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/infoUp.gif")));
          m_catalogPanel.setVisible(true);
        }
        else {
          m_moreButton.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/infoDown.gif")));
          m_catalogPanel.setVisible(false);          
        }
        m_dialog.pack();
        m_dialog.validate();
        m_dialog.repaint();
        
      }
    });

    // Show the more if there are no defaults (try to make it obvious to the user
    // that the fields need to be filled in
    if (m_reader == null)
      m_moreButton.doClick();
    int _top = 5;
    m_catalogPanel.add(m_directoryLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0));
    m_catalogPanel.add(m_catalogRootFolder, new GridBagConstraints(1, 0, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));    
        
    /*
     * Now that we have all the fields defined, specify defaults.  Two configurations files
     * found in the user's home will contain this information.  One contains all the connection
     * parameters, the other contains the id/pwd for the catalog.  This file was read
     * in the constructor for this class
     */
    if (m_reader != null ) {
      // get the OLAP defaults
      m_olap = m_reader.getOLAPConnection();
      m_host.setText(m_olap.getHostName());    
      m_port.setText(m_olap.getPortNumber());
      m_sid.setText(m_olap.getSID());

      // Is the Catalog File-system or database?
      if (m_reader.getPersistenceConnection().getPersistenceType().equalsIgnoreCase("FILE")) {
        // File based catalog, so get the root folder
        m_catalogType.setSelectedIndex(0);
        String rootFolder = m_reader.getPersistenceConnection().getRootFolder();

        // If the directory does not exist, then set the root folder to the user home
        File folder = new File(rootFolder);
        if (folder.isDirectory())
          m_catalogRootFolder.setText(folder.toString());
        else
          m_catalogRootFolder.setText(m_homeDirectory);
      }          
      else
        // Database Catalog, so get the database connection details
        m_catalogType.setSelectedIndex(1);        
        PersistenceConnection pc = m_reader.getPersistenceConnection();

        try {
          m_catalogUserName.setText(pc.getDADFile().getUserName());
          m_catalogPassword.setText(pc.getDADFile().getPassword());        
        }
        catch (Exception e) {
          System.out.println("Unable to open Catalog DAD file: " + pc.getDADFileName());
        }
    }
    else {
      // there is no analyzer.xml file, so the default catalog will be file system
      m_catalogRootFolder.setText(m_homeDirectory);    
      m_catalogType.setSelectedIndex(0);
    }
    
    JPanel panel = new JPanel();
    GridBagLayout gridBagLayout1 = new GridBagLayout();
    panel.setLayout(gridBagLayout1);


    /*
     * 1. Update the fields for the dialog
     * 2. Add the fields to the dialog
     * 3. Show the dialog
     */
    
    // creates the connect button and handles the case where the connect button
    // is pressed
    JButton connectButton = new JButton(CONNECT);

    connectButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        connect();

        if (isConnected())
          disposeConnectDialog();
      }
    });

    // creates the cancel button and handles the case where the cancel button
    // is pressed - basically, close the dialog box.
    JButton cancelButton = new JButton(CANCEL);
    cancelButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        m_dialog.dispose();
        m_dialog = null;
      }
    });

    // panel for catalog type and info button
    JPanel catTypePanel = new JPanel(new BorderLayout());
    catTypePanel.add(m_catalogType, BorderLayout.CENTER);
    catTypePanel.add(m_moreButton, BorderLayout.EAST);
    
    // create a panel for the buttons
    JPanel buttonsPanel = new JPanel();
    buttonsPanel.add(connectButton);
    buttonsPanel.add(cancelButton);
    
    panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 10, 10));        
    panel.add(lblImage, new GridBagConstraints(0, 0, 1, 8, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(10, 10, 0, 15), 0, 0));    
    panel.add(lblUserID, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(15, 0, 0, 0), 0, 0));
    panel.add(m_OLAPUserName, new GridBagConstraints(2, 0, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(15, 10, 0, 20), 0, 0));    
    panel.add(lblPwd, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(_top, 0, 0, 0), 0, 0));    
    panel.add(m_OLAPPassword, new GridBagConstraints(2, 1, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(_top, 10, 0, 20), 0, 0));
    panel.add(lblHost, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(_top, 0, 0, 0), 0, 0));
    panel.add(m_host, new GridBagConstraints(2, 2, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(_top, 10, 0, 20), 0, 0));
    panel.add(lblPort, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(_top, 0, 0, 0), 0, 0));
    panel.add(m_port, new GridBagConstraints(2, 3, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(_top, 10, 0, 20), 0, 0));
    panel.add(lblSID, new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(_top, 0, 0, 0), 0, 0));
    panel.add(m_sid, new GridBagConstraints(2, 4, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(_top, 10, 0, 20), 0, 0));
    panel.add(lblCatalogType, new GridBagConstraints(1, 5, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(_top, 0, 0, 0), 0, 0));
    panel.add(catTypePanel, new GridBagConstraints(2, 5, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(_top, 10, 0, 20), 0, 0));    
    panel.add(m_catalogPanel, new GridBagConstraints(1, 6, 3, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(_top, 0, 0, 20), 0, 0));
    panel.add(buttonsPanel, new GridBagConstraints(2, 7, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(_top, 10, 0, 20), 0, 0));    

    // put all these together into the dialog box
    m_dialog.getContentPane().add(panel, BorderLayout.CENTER);
    m_dialog.pack();

    // Set the location of the dialog relative to another window - in this case, "this"
    // refers to a frame
    m_dialog.setLocationRelativeTo(m_analyzer);
    
    // display connect dialog
    m_dialog.setVisible(true);
  }

  /**
   * Disposes of the connect dialog.  
   */
   public void disposeConnectDialog() {
      m_dialog.dispose();

   }
   
  /**
   * Displays a confirmation dialog that asks if the user wants to disconnect.
   * 
   * @param parentFrame The Analyzer main application class.
   */
  public void showDisconnectDialog(JFrame parentFrame) {

    int option = JOptionPane.showConfirmDialog(parentFrame,
                   "Are you sure you want to disconnect?", parentFrame.getTitle(),
                   JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
    if (option == JOptionPane.YES_OPTION) 
      // Clean up the UI
      m_analyzer.disconnectCleanUp();

      // Disconnect from the database
      disconnect();
      
  }

  /**
   * Gets the BISession for this connection.
   * 
   * @return The BISession for this connection.
   */
  public BISession getBISession() {
    return m_session;
  }

  /**
   * Returns the MetadataManager that the application uses.
   * The connect method instantiates the MetadataManager that this method returns.
   * <p>2
   * The Analyzer.initializeUI method calls this method to set the
   * MetadataManager on the Explorers.
   * 
   * @return The MetadataManager for the application.
   * 
   * @see #connect
   * @see Analyzer#initializeUI
   * @see AnalyzerUtilities#construct
   */
  public MetadataManager getMetadataManager() {
    return m_metadataManager;
  }

  /**
   * Returns the QueryManager that the application uses.
   * The Analyzer.newPresentation method calls this method to set the
   * QueryManager on the NewPresentationWizard.
   * The AnalyzerUtilities.construct method calls this method to provide
   * the QueryManager to the presentation that it is loading.
   * 
   * @return QueryManager used by the application
   * 
   * @see Analyzer#newPresentation
   * @see AnalyzerUtilities#construct
   */
  protected QueryManager getQueryManager() {
    return m_queryManager;
  }  

  /**
   * Indicates whether the application is connected to the database.
   * 
   * @return <code>true</code> is connected to the database,
   *         <code>false</code> if it is not.
   */
  protected boolean isConnected() {
    return m_connected;
  }

  /**
   * Connects to the OLAP service and to the BI Beans Catalog, using connection
   * information from the BI Configuration file and from the BIConnectionDialog.
   */
  protected void connect() {
    /* 
     * Try to connect to the catalog based on the information collected in method
     *    showConnectDialog()
     *  - File based must be a valid directory (validated in showConnectDialog())
     *  - Database must be a valid connection.  The OLAP user will be the catalog
     *    user.  If the OLAP user is not a Catalog user & the catalog is not a 
     *    Discoverer Catalog (D4OSYS) - add user to the catalog
     *  - The assumption here is that if the user is utilizing the database catalog, 
     *    then the database catalog is in the same database instance as the OLAP data
     * If unable to connect, tell user what to do to set up connection
     * 
     */
      // set up the session
      if (m_session != null) {
        try {
          m_session.disconnect();
        }
        catch (Exception e) {
          System.out.println("Unable to disconnect from session.");
        }
        m_session = null;
      }
      m_session = new BISession();
      DefaultErrorHandler _handler = new DefaultErrorHandler();
      _handler.setDebugMode(DefaultErrorHandler.SHOW_NONE);
      m_session.addErrorHandler(_handler);

      // use the OLAP user for the BI User.  This means the OLAP user must be a valid
      // user in the catalog
      m_session.setBIUser(new BIUser(m_OLAPUserName.getText()));
      
      try {
          m_session.connect();
      }
      catch (Exception e)  {
          e.printStackTrace();
      }

      MetadataManager _mm = null;
      Connection olapCon = null;
      Connection catalogCon = null;

      /*
       * Try to connect to OLAP
       */
      try {
        olapCon = getOLAPConnection();
      }
      catch (ConnectionException ce) {
        showConnectionError(ce);
        return;
      }
      
      /*
       * Try to connect to the catalog
       */
      if (m_useDatabaseCatalog) {
        // for shared JDBC connections with OLAP Connection. Note, this is the
        // only way to connect to a Discoverer Catalog
        if (m_catalogUserName.getText().equalsIgnoreCase("D4OSYS") ||
            m_catalogUserName.getText().equalsIgnoreCase(""))
        
            catalogCon = getCatalogConnection(olapCon);
        
        // for non-shared JDBC connections with OLAP Connection
        else 
            catalogCon = getCatalogConnection();
      }
      else
        catalogCon = getLocalCatalogConnection();
        
      if (catalogCon == null)
        return;

      try {
          /*
           * Create MetadataManager based on the two connections above
           * (this is set up automatically when connection details are read from
           * a configuration file)
           */
          _mm = new MetadataManager();
          _mm.setSession(m_session);

          // The MetadataManager will merge details from OLAP and the Catalog
          _mm.setConnection(olapCon);            
          _mm.setConnection(catalogCon);
          _mm.attach();

          //Now that we're successfully connected, cache key properties
          m_metadataManager = _mm;
          m_queryManager = new QueryManager();
          m_queryManager.setSession(m_session);
          m_queryManager.setMetadataManager(m_metadataManager);
          m_connected = true;   

          // Save the connection details
          saveConnectionSettings();
      }
      catch (Exception e) {
          // The _mm.attach method call can fail if the user - who is a valid
          // database user, is not a valid catalog user
          showConnectionError(e);
      }
  }

  /**
   * Creates and returns a Connection to the OLAP Catalog.
   * This method sets user and connection information, which was collected
   * in the dialog box or in the reading of the config file, on the connection
   * object. 
   * Then it calls the connect method of the Connection.
   * 
   * @return A connection to the OLAP Catalog.
   * 
   * @throws ConnectionException If the connection fails.
   */
  private Connection getOLAPConnection () throws ConnectionException {
      // setting up a connection to the OLAP catalog
      Connection _con = new Connection();
      _con.setSession(m_session);
      _con.setDriverType(MM.MDM);
      _con.setUsername(m_OLAPUserName.getText().toUpperCase());
      _con.setPassword(new String(m_OLAPPassword.getPassword()));
      _con.setHostName(m_host.getText());
      _con.setSID(m_sid.getText());
      Integer port = new Integer(m_port.getText());
      _con.setPortNumber(port.intValue());
      _con.setJdbcDriverType("thin");      
      _con.connect();

      return _con;      
  }

  /**
   * Creates and returns a Connection to the BI Beans Catalog.
   * This method will share the JDBC connection with the OLAP Connection
   * @param OLAPConnection The Catalog will reuse the OLAP's JDBC connection
   * @return A Connection to the BI Beans Catalog.
   */
  private Connection getCatalogConnection(Connection OLAPConnection) {

      Connection _con = new Connection();
      _con.setSession(m_session);
      _con.setDriverType(MDU.PERSISTENCE);
          
      // sharing same connection with OLAP connection
      PropertyBag _bag = new PropertyBag();
      _bag.setStrPropertyValue(CB.CONNECTION, CB.CONNECTION);
      try {
          Object driverObject = OLAPConnection.getDriverSpecificObject(_bag);
          _con.setConnectionObject(driverObject);
      }
      
      catch (Exception e) {
        System.out.println("Error when attempting to use OLAP JDBC connection for the Catalog");
      }
                        
      return _con;
    
  }

  /**
   * Creates and returns a Connection to the BI Beans Catalog in the database.
   * This method will create a separate JDBC Connection.
   * This method sets user and connection information, which was collected
   * in the dialog box or in the reading of the config file, on the connection
   * object. 
   * Then it calls the connect method of the Connection.
   * 
   * @return A Connection to the BI Beans Catalog.
   */
  private Connection getCatalogConnection() {

      Connection _con = new Connection();
      _con.setSession(m_session);
      _con.setDriverType(MDU.PERSISTENCE);
      _con.setUsername(m_catalogUserName.getText());
      _con.setPassword(new String(m_catalogPassword.getPassword()));
      _con.setHostName(m_host.getText());
      Integer port = new Integer(m_port.getText());
      _con.setPortNumber(port.intValue());
      _con.setSID(m_sid.getText());
      _con.setJdbcDriverType("thin");        

      boolean canRecover = true;
      /*
       * Attempt to connect to the catalog.  If the BIUser user is invalid, then check
       * to see if there is a user in the catalog that has the same name - but with 
       * different case (e.g.  BIBDEMO vs bibdemo).  If the user is not in the 
       * catalog, add the user.
       */
      try {
        _con.connect();
      }
      catch (Exception ex) {
        /*
         * If the reason for the error is an invalid catalog user, then
         * try to recover.  Parse the error message to find out
         */ 
         if (ex instanceof PersistenceManagerRuntimeException) {
           String message = ex.toString();
           if (message.indexOf(AnalyzerUtilities.ERR_INVALID_BIUSER) > 0) {             
             // Attempt to recover the user.  If successful, try to reconnect
             canRecover = recoverUser();
             connect();
             return null;
           }
           else {
             canRecover = false;
             showConnectionError(ex);
           }
         }                  
        else {
          canRecover = false;
          showConnectionError(ex);
        }          
       }        

      return _con;    
  }

  /**
   * Creates and returns a Connection to the BI Beans Catalog.
   * The Catalog here is a File-based Catalog.
   * This method will share the JDBC connection with the OLAP Connection   
   * @return A Connection to the BI Beans Catalog.
   */
  private Connection getLocalCatalogConnection() {

      Connection _con = new Connection();
      _con.setSession(m_session);
      _con.setDriverType(MDU.PERSISTENCE);
                 
      // Use local catalog
      _con.setProperty(PSRConstants.STORAGEMANAGER_DRIVER, 
                       "oracle.dss.persistence.storagemanager.bi.BIFileStorageManagerImpl");
      String initialDirectory = null;

      // Default to the user's home directory if they did not specify anything
      if (m_catalogRootFolder.getText().length() == 0) 
        initialDirectory = m_homeDirectory;
      else 
        initialDirectory = m_catalogRootFolder.getText();

      _con.setProperty(PSRConstants.INITIAL_PATHNAME , initialDirectory);
        
      return _con;
    
  }

  
  /**
   * Displays error connection information.
   * This method uses an AnalyzerUtilities object to display an error
   * message.
   * 
   * @param e The exception that contains error text.
   */
   // cr required?
  private void showConnectionError(Exception e) {
    String message = null;
        
    AnalyzerUtilities au = new AnalyzerUtilities(m_analyzer);
    message = au.getErrorText(e);
    au.showErrorMessage(message, e);
  }
  
  /**
   * Attempts to recover from an invalid application user.  This method is only called
   * if the OLAP User was authenticated.  The assumption is that if the user is 
   * successfully authenticated by the database, then the user should have rights
   * to the catalog.
   * <p>
   * This method uses a JDBC connection to execute SQL statements in the
   * database.
   * 
   * @return <code>true</code> if the user is recovered,
   *         <code>false</code> if the user cannot be recovered.
   */
  private boolean recoverUser() {
    /*
     * Collect connection details and make a JDBC connection
     */
    String loginUser = m_session.getBIUser().getName();
    String username = m_catalogUserName.getText();
    String password = new String(m_catalogPassword.getPassword());
    String thinConn = "jdbc:oracle:thin:@" + m_host.getText() + ":" + 
                      m_port.getText() + ":" + m_sid.getText();
    String subjName = null;
    String subjType = null;
    String strUniqueID = null;
    Statement stmt = null;
    ResultSet rs = null;
    java.sql.Connection con = null;
                      
    try {                      
      Driver d = new OracleDriver();
      con = DriverManager.getConnection(thinConn,username,password);  

      /*
       * Search for the BIUser in the catalog.  Update the catalog if nec.
       */ 
      stmt = con.createStatement();
      rs = stmt.executeQuery(
        "select SUBJECT_ID, SUBJECT_NAME, SUBJECT_TYPE " +
        "from BISM_SUBJECTS where lower(SUBJECT_NAME) = '" +
         loginUser.toLowerCase() + "'");

      boolean isFound = false;
      
      while (rs.next() && !isFound) {
        subjName = rs.getString("SUBJECT_NAME");
        subjType = rs.getString("SUBJECT_TYPE");

        // Check that the user (subjName) is a User and not a Group
        if (subjType.equalsIgnoreCase("U"))
          isFound = true;
      }

      rs.close();
      stmt.close();

      /*
       * subjName will have a value if the case was incorrect.  Correct the mistake
       * and return TRUE - the user was recovered
       * 
       * if subjName does not have a value, add the user to the catalog
       */
      if (subjName != null) {
        m_OLAPUserName.setText(subjName);
        con.close();
        return true;
      }
      else {
        // the user is not found.  Add the user to the catalog
        // Get a unique id for the catalog user
        CallableStatement cstmt = con.prepareCall("begin ? := bism_utils.get_guid; end;");
        cstmt.registerOutParameter(1, java.sql.Types.VARBINARY); 
        cstmt.execute();
        strUniqueID = cstmt.getString(1);
        cstmt.close();

        /*
         * In a batch script:
         * 1.  Add the user to the BISM_SUBJECTS table
         * 2.  Add the user to the BISM_GROUPS table
         * 3.  Set default privileges for the user in the BISM_PRIVILEGES table
         */
        
        // Insert SQL
        String users      = "insert into bism_subjects values('" +
                            strUniqueID + "', '" + loginUser + "', 'u')";
        String groups     = "insert into bism_groups values('" +
                            strUniqueID + "', '" + strUniqueID + "')";
        String permissions = "insert into bism_permissions values('" + 
                              strUniqueID + "','31',40)";
                              
        con.setAutoCommit(false);                      
        stmt = con.createStatement();
        stmt.addBatch(users);
        stmt.addBatch(groups);
        stmt.addBatch(permissions);
        int [] updateCounts = stmt.executeBatch();

        stmt.close();
        con.commit();
        
        // Close connection.  Return that the user was successfully recovered
        con.close();
        return true;
        
      }
    }
    catch (Exception e) {
      System.out.println("ERROR ADDING USER TO THE CATALOG");
      System.out.println("--------------------------------");
      e.printStackTrace();
     }
     // The following block is executed in case there is an error.  Need to 
     // rollback changes and close the connection
     try { con.rollback(); }
     catch (Exception e) { System.out.println("No rollback applied."); }
     try { con.close(); }
     catch (Exception e) { System.out.println("Error closing JDBC connection."); }

     return false;
  }
  
  /**
   * Saves the connection settings.  
   * This method saves settings in the user's home directory.
   * That way, the user will not have to continually re-enter the fields when
   * reconnecting.
   */
   private void saveConnectionSettings() {
     /* Save the fields that the user entered    
        If there was not a default configuration file, use the template delivered with
        the application to create the BIConfigReader object
     */
     if (m_reader == null) {
       try {
          m_reader = new BIConfigReader("/" + m_defaultConfigFile);
       }
       catch (Exception e) {
          System.out.println("Unable to get default configuration from jar file.");
       }
     } 

     // OLAP connection
     OLAPConnection olap = m_reader.getOLAPConnection();
     olap.setHostName(m_host.getText());
     olap.setPortNumber(m_port.getText());
     olap.setSID(m_sid.getText());

     // Persistence connection
     PersistenceConnection persist = m_reader.getPersistenceConnection();
     String dadFilename = m_homeDirectory + m_defaultCatalogFile;
     

     if (m_useDatabaseCatalog) {
       persist.setHostName(m_host.getText());
       persist.setPortNumber(m_port.getText());
       persist.setSID(m_sid.getText());
       persist.setPersistenceType("RDBMS");
       persist.setDADFileName(dadFilename);
       

       try {
         DADFile dad = persist.getDADFile();
         dad.setUserName(m_catalogUserName.getText());
         dad.setPassword(new String(m_catalogPassword.getPassword()));
       }
       catch (Exception e) {
         System.out.println("Unable to save config file.");
       }
        
     }
     else {  
       // Persisting to the file system, set the root folder
       persist.setPersistenceType("FILE");
       persist.setRootFolder(m_catalogRootFolder.getText());
     }

     // Write the Config files to the file system         
     try {
        m_reader.writeToLocalFile(m_configFile, dadFilename);
     }
     catch (Exception e) {
        System.out.println("Unable to save config file.");       
     }

   }
  /**
   * Disconnects the application from the MetadataManager and its associated
   * connections.  Disconnects the current user session.
   * Subclasses should override this method to add additional cleanup code.
   */
  protected void disconnect() {
    try {
      // detach from MetadataManager and disconnect the current session
      m_session.disconnect();
      m_connected = false;
      m_metadataManager.detach();

      // clean up
      m_session = null;
      m_metadataManager = null;
      m_queryManager = null;
      m_analyzer.enableMenus();
    }
    catch (Exception ex) {
      AnalyzerUtilities au = new AnalyzerUtilities(m_analyzer);
      au.showErrorMessage(null, ex);
    }
  }

  /**
   * Gets the root folder name for the application.
   * 
   * @return Root folder in the BI Beans Catalog to which the application is
   *         connected.
   *         
   * @throws Throwable If an error occurs.         
   */
  public MDRoot getRootFolder() throws Throwable {
    MetadataManager mdm = getMetadataManager();

    return mdm.getMDRoot();
  }
   
}