//*****************************************************************************
/*
** FILE:   da_DatabaseConnectDialog.java
**
** Copyright 1998 Steve Withall.
**
** HISTORY:
**    22May98  stevew  Created.
*/
package da;

import xm.xm_DocumentModel;

import xg.xg_Document;

import xm.xm_SimpleNodeFormatter;

import eh.eh_Debug;

import com.sun.java.swing.text.BadLocationException;

import com.sun.java.swing.Box;
import com.sun.java.swing.ComboBoxModel;
import com.sun.java.swing.JButton;
import com.sun.java.swing.JComboBox;
import com.sun.java.swing.JDialog;
import com.sun.java.swing.JLabel;
import com.sun.java.swing.JOptionPane;
import com.sun.java.swing.JTextField;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;

import java.io.IOException;
import java.io.StringWriter;

import java.util.Enumeration;

import java.lang.StringBuffer;

//*****************************************************************************
/** A dialog for entering details about a database to which to connect.
 */
public class da_DatabaseConnectDialog extends JDialog
{
    /** If a connection is successfully established, this is it. */
    Connection        TheConnection    = null;

    /** The document which will be transformed to represent the structure of
     *  the database we're looking at. */
    xm_DocumentModel  TheDocumentModel = null;

    Frame             ParentFrame      = null;

    // Attributes relating to the combo box listing the loaded database drivers.
    JLabel      DriverLabel       = new JLabel("Database driver");
	JComboBox   DriverComboBox    = new JComboBox();

    // Attributes relating to the URL of the database to which to connect.
    JLabel      DatabaseURLLabel     = new JLabel("Database URL");
	JTextField  DatabaseURLTextField = new JTextField(20);
    JLabel      DatabaseURLLabel2    = new JLabel("(Eg. jdbc:odbc:<Name>)");

    // Attributes relating to the database login user ID.
    JLabel      UserIdLabel       = new JLabel("Database user ID");
    JTextField  UserIdTextField   = new JTextField(12);

    // Attributes relating to the database password.
    JLabel      PasswordLabel     = new JLabel("Password");
    JTextField  PasswordTextField = new JTextField(12);

    // Buttons.
    JButton     ConnectButton = new JButton("Connect");
    JButton     CancelButton  = new JButton("Cancel");

    //*****************************************************************************
    /** Constructor.
     */
    public da_DatabaseConnectDialog(Frame             InputParentFrame,
                                    xm_DocumentModel  InputDocumentModel)
    {
	    super(InputParentFrame, "Database connection", true);
	    ParentFrame      = InputParentFrame;
        TheDocumentModel = InputDocumentModel;
	    initScreen();
	}

    //*****************************************************************************
    /** Constructor.
     */
    public da_DatabaseConnectDialog(Frame  InputParentFrame)
    {
	    super(InputParentFrame, "Database connection", true);
	    ParentFrame = InputParentFrame;
	    initScreen();
	}

    //*****************************************************************************
    /** Initialise the screen.
     */
    protected void initScreen()
    {
	    // Load icon image.
//	    Image  IconImage = Toolkit.getDefaultToolkit().getImage("df/images/da_DatabaseIcon.gif");
//	    InputParentFrame.setIconImage(IconImage);

        GridBagLayout      gbl = new GridBagLayout();
        GridBagConstraints gbc = new GridBagConstraints();
        getContentPane().setLayout(gbl);

        // Driver name.
        gbc.anchor    = GridBagConstraints.WEST;
        gbc.gridwidth = 1;
        gbc.insets    = new Insets(0, 4, 8, 4);
        gbl.setConstraints(DriverLabel, gbc);
        getContentPane().add(DriverLabel);

        loadDriverList();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbl.setConstraints(DriverComboBox, gbc);
        getContentPane().add(DriverComboBox);

        // Database URL.
        gbc.gridwidth = 1;
        gbl.setConstraints(DatabaseURLLabel, gbc);
        getContentPane().add(DatabaseURLLabel);

        gbl.setConstraints(DatabaseURLTextField, gbc);
        getContentPane().add(DatabaseURLTextField);

        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbl.setConstraints(DatabaseURLLabel2, gbc);
        getContentPane().add(DatabaseURLLabel2);

        // User ID.
        gbc.gridwidth = 1;
        gbl.setConstraints(UserIdLabel, gbc);
        getContentPane().add(UserIdLabel);

        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbl.setConstraints(UserIdTextField, gbc);
        getContentPane().add(UserIdTextField);

        // Password.
        gbc.gridwidth = 1;
        gbl.setConstraints(PasswordLabel, gbc);
        getContentPane().add(PasswordLabel);

        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbl.setConstraints(PasswordTextField, gbc);
        getContentPane().add(PasswordTextField);

	    // Panel for buttons.
        Box  ButtonBox = Box.createHorizontalBox();
        ButtonBox.add(ConnectButton);
        ButtonBox.add(CancelButton);

        gbc.anchor    = GridBagConstraints.EAST;
//        gbc.anchor    = GridBagConstraints.SOUTH;
        gbc.insets    = new Insets(5, 0, 0, 0);
        gbc.fill      = GridBagConstraints.HORIZONTAL;
//        gbc.gridwidth = 1;  // The number of horizontal cells  //TEMP
        gbl.setConstraints(ButtonBox, gbc);
        getContentPane().add(ButtonBox);

    	ConnectButton.addActionListener(new ConnectButtonListener() );
    	CancelButton.addActionListener(new CancelButtonListener() );

        Point  ParentLocation = ParentFrame.getLocation();
        setBounds(ParentLocation.x + 40, ParentLocation.y + 110, 600, 180);
        show();
    }

    //*****************************************************************************
    /** Load the combo box of the loaded drivers.
     */
    private void loadDriverList()
    {
        Enumeration  DriverEnumeration   = DriverManager.getDrivers();
        Object       CurrentDriverObject = null;
        while (DriverEnumeration.hasMoreElements() )
        {
            CurrentDriverObject = DriverEnumeration.nextElement();
            DriverComboBox.addItem(CurrentDriverObject.toString());
        }

        if (DriverComboBox.getItemCount() == 0)
            DriverComboBox.addItem("No JDBC drivers loaded");
    }

    //*****************************************************************************
    /** Analyse the database, and reflect the details in the document model.
     */
    public void analyseDatabase()
    {
	    eh_Debug.add(6, "da_DatabaseConnectDialog.analyseDatabase:");
        TheDocumentModel.clear();  //TEMP Very heavyhanded!

        // Create a new database schema element.
        da_DatabaseSchemaElement  NewDatabaseSchemaElement = new da_DatabaseSchemaElement();
        //TBD Add 'Class' attribute to hold the name of the JDBC driver class.
//        NewDatabaseSchemaElement.addAttribute(da_DatabaseSchemaElement.ClassAttName,
//                                              ?);

        // Add database schema as root element in document.
        xg_Document  DatabaseDocument = TheDocumentModel.getCurrentDocument();
        DatabaseDocument.addChild(NewDatabaseSchemaElement);

        try
        {
            DatabaseMetaData  TheMetaData = TheConnection.getMetaData();

            // Ask the database schema element to set itself up to reflect the
            // structure of the database.
            NewDatabaseSchemaElement.analyseDatabase(TheMetaData);

            // Give the document decent whitespace, so we can read it easily.
            xm_SimpleNodeFormatter  NodeFormatter = new xm_SimpleNodeFormatter();
            NodeFormatter.format(DatabaseDocument);

            // Display the source of the newly-generated document.
            StringWriter  SourceWriter = new StringWriter();
            DatabaseDocument.save(SourceWriter);
            TheDocumentModel.insertString(0, SourceWriter.toString(), null);
        }
        catch (SQLException InputException)
        {
	        eh_Debug.add(2, "Error retrieving database meta data: " + InputException);
        }
        catch (IOException InputException)
        {
	        eh_Debug.add(2, "Error saving database meta data to source: " + InputException);
        }
        catch (BadLocationException InputException)
        {
	        eh_Debug.add(2, "Error moving database meta data source to screen: " + InputException);
        }
    }

    //*****************************************************************************
    /** Pass in the document model into which we are to place the analysed structure
     *  of the database.
     *
     *  @param  InputDocumentModel  The document model to represent the database's
     *                               structure
     */
    public void setDocumentModel(xm_DocumentModel  InputDocumentModel)
    {
        TheDocumentModel = InputDocumentModel;
    }

    //*****************************************************************************
    /** Retrieve the document model into which we placed the analysed structure
     *  of the database.
     *
     *  @return  The document model representing the database's structure
     */
    public xm_DocumentModel getDocumentModel()
    {
        return TheDocumentModel;
    }

    //*****************************************************************************
    /** Retrieve the connection which was established (or null if one hasn't been
     *  established).
     *
     *  @return  The database connection which has been established
     */
    public Connection getConnection()
    {
        return TheConnection;
    }

    //*****************************************************************************
    // Button listener inner classes.
    //*****************************************************************************
    /** Handle pressing of the "Update" button. Establish a connection according to
     *  the values entered.
     */
    class ConnectButtonListener implements ActionListener
    {
        public void actionPerformed(ActionEvent  InputEvent)
        {
            try
            {
//                String  DriverName = (String)DriverComboBox.getSelectedItem();

                String  DatabaseURLString = DatabaseURLTextField.getText();
                String  UserIdString      = UserIdTextField.getText();
                String  PasswordString    = PasswordTextField.getText();

	            eh_Debug.add(4, "Establish connection to '" + DatabaseURLString
	                                + "' for user '" +  UserIdString
	                                + "', password '" + PasswordString + "'");
                TheConnection = DriverManager.getConnection(DatabaseURLString,
                                                            UserIdString,
                                                            PasswordString);
	            eh_Debug.add(4, "Connection to '" + DatabaseURLString
	                                 + "' established successfully");

                // Analyse this database, and reflect the details in the document
                // model.
                if (TheDocumentModel != null)
                    analyseDatabase();

                dispose();
            }
            catch (SQLException InputException)
            {
		        Object[]  MessageArray = new Object[2];
		        MessageArray[0] = "Error establishing database connection:";
		        MessageArray[1] = InputException.toString();

		        String[]  OptionButtonLabel = { "OK" };
		        JOptionPane.showOptionDialog(ParentFrame,
		                                     MessageArray,
		                                     "Connection error",
		                                     JOptionPane.DEFAULT_OPTION,
		                                     JOptionPane.ERROR_MESSAGE,
		                                     null,
		                                     OptionButtonLabel,
		                                     OptionButtonLabel[0]);
	            eh_Debug.add(2, MessageArray[0] + " " + InputException);
            }
        }
    }

    //*****************************************************************************
    /** Handle pressing of the "Cancel" button. Close this dialog, and do nothing
     *  else.
     */
    class CancelButtonListener implements ActionListener
    {
        public void actionPerformed(ActionEvent  InputEvent)
        {
            dispose();
        }
    }
}
//*****************************************************************************
