/**
 * @author <a href="mailto:goran_schwarz@hotmail.com">Goran Schwarz</a>
 */
package com.sap.dbmtk.demo;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import net.miginfocom.swing.MigLayout;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.log4j.Logger;

import com.sap.dbmtk.demo.SqlStatement.Type;
import com.sap.dbmtk.demo.ui.AbstractComponentDecorator;
import com.sap.dbmtk.demo.ui.ConnectionDialog;
import com.sap.dbmtk.demo.ui.GTabbedPane;
import com.sap.dbmtk.demo.ui.MultiLineLabel;
import com.sap.dbmtk.demo.ui.StatusBar;
import com.sap.dbmtk.demo.ui.StatusBar.ServerInfo;
import com.sap.dbmtk.demo.utils.AseConnectionUtils;
import com.sap.dbmtk.demo.utils.Configuration;
import com.sap.dbmtk.demo.utils.DbUtils;
import com.sap.dbmtk.demo.utils.Logging;
import com.sap.dbmtk.demo.utils.StringUtil;
import com.sap.dbmtk.demo.utils.SwingUtils;


/**
 * This class creates a Swing GUI that allows the user to enter a SQL query.
 * It then obtains a ResultSetTableModel for the query and uses it to display
 * the results of the query in a scrolling JTable component.
 **/
public class DemoApp
//	extends JFrame
//	extends JDialog
//implements ActionListener, SybMessageHandler, ConnectionProvider, CaretListener, CommandHistoryDialog.HistoryExecutor
	implements ActionListener, ConnectionProvider
{
	private static Logger _logger = Logger.getLogger(DemoApp.class);
	private static DemoApp _instance = null;

	private final static String NOT_CONNECTED_STR              = "Not Connected...";

	public final static String  APP_NAME                       = System.getProperty("APPL_NAME", "DemoClient"); //"ExodusDemoClient";

	public final static String  PROPKEY_APP_PREFIX             = "DemoClient.";

	public final static String  PROPKEY_showExtErrInfo         = PROPKEY_APP_PREFIX + "view.show.extended.error.info";
	public final static boolean DEFAULT_showExtErrInfo         = true;

	public final static String  PROPKEY_enableDbmsOutput       = PROPKEY_APP_PREFIX + "view.enable.dbms.output";
	public final static boolean DEFAULT_enableDbmsOutput       = true;

	public final static String  PROPKEY_connCheckTimeout       = PROPKEY_APP_PREFIX + "connection.check.timeout";
	public final static long    DEFAULT_connCheckTimeout       = 2000;

	//-------------------------------------------------
	// Actions
	public static final String ACTION_CONNECT                   = "CONNECT";
	public static final String ACTION_DISCONNECT                = "DISCONNECT";

	public static final String ACTION_OPEN_SQL_TRACE            = "OPEN_SQL_TRACE";
	public static final String ACTION_SAVE_PROPS                = "SAVE_PROPS";
	public static final String ACTION_DBMS_OUTPUT               = "DBMS_OUTPUT";
//	public static final String ACTION_OPEN_SQL_WINDOW           = "OPEN_SQL_WINDOW";
	public static final String ACTION_OPEN_PREFERENCES          = "OPEN_PREFERENCES";

	public static final String ACTION_EXIT                      = "EXIT";

	public static final String TAB_AUTHORS                      = DataPanelAuthors    .NAME; // "Authors";
	public static final String TAB_TITLES                       = DataPanelTitles     .NAME; // "Titles";
	public static final String TAB_PUBLISHERS                   = DataPanelPublishers .NAME; // "Publishers";
//	public static final String TAB_SALES                        = DataPanelSales      .NAME; // "Sales";
	public static final String TAB_STORES                       = DataPanelStores     .NAME; // "Stores";
	public static final String TAB_ORDERS                       = "Orders";
	public static final String TAB_STATS                        = DataPanelStatistics .NAME; // "Statistics";

	private Connection  _conn            = null;
	private int         _connType        = -1;
	private AseConnectionUtils.ConnectionStateInfo _aseConnectionStateInfo  = null;
	private DbUtils.JdbcConnectionStateInfo        _jdbcConnectionStateInfo = null;


	private JSplitPane        _splitPane                  = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);

	private GTabbedPane       _tabPane                    = null;
	private JPanel            _mainPane                   = new JPanel( new MigLayout("insets 0 0 0 0") );
//	private JPanel            _controlPane                = new JPanel( new MigLayout("insets 0 0 0 0") );
//	private JPanel            _possibleCtrlPane           = new JPanel( new BorderLayout() );
	private JPanel            _baseDemoPanel              = null;
//	private JPanel            _topPane                    = null;
//	private JPanel            _bottomPane                 = new JPanel( new MigLayout("insets 0 0 0 0") );

	private StatusBar         _statusBar                  = new StatusBar();

	private JLabel            _dbms_lbl                   = new JLabel(" DBMS: ");
	private MultiLineLabel    _dbms_txt                   = new MultiLineLabel(NOT_CONNECTED_STR);



	protected DataPanelAbstract    _authors         = null;
	protected DataPanelAbstract    _authorTitles    = null;
	protected SplitPanelAbstract   _authorsPanel    = null;

	protected DataPanelAbstract    _titles          = null;

	protected DataPanelAbstract    _publishers      = null;
	protected DataPanelAbstract    _publisherTitles = null;
	protected SplitPanelAbstract   _publishersPanel = null;

	protected DataPanelAbstract    _stores          = null;

	protected DataPanelAbstract    _orders          = null;
	protected DataPanelAbstract    _orderDetails    = null;
	protected SplitPanelAbstract   _ordersPanel     = null;

	protected DataPanelAbstract    _statistics      = null;


	private int         _srvVersion                       = 0;
//	private long        _connectedAtTime                  = 0;
	private String      _connectedDriverName              = null;
	private String      _connectedDriverVersion           = null;
	private String      _connectedToProductName           = null;
	private String      _connectedToProductVersion        = null;
	private String      _connectedToServerName            = null;
	private String      _connectedToSysListeners          = null;
	private String      _connectedSrvCharset              = null;
	private String      _connectedSrvSortorder            = null;
	private String      _connectedAsUser                  = null;
	private String      _connectedWithUrl                 = null;

	private String      _connectedClientCharsetId         = null;
	private String      _connectedClientCharsetName       = null;
	private String      _connectedClientCharsetDesc       = null;

	private boolean     _autoCommitEnabledAtConnect       = true; // AutoCommit=true is the default in JDBC

	private long _connCheckLastTime = 0; 
	private long _connCheckTimeout  = Configuration.getCombinedConfiguration().getLongProperty(PROPKEY_connCheckTimeout, DEFAULT_connCheckTimeout);

	
	// The base Window can be either a JFrame or a JDialog
	private Window      _window          = null;
	private JFrame      _jframe          = null;
	private JDialog     _jdialog         = null;
	private String      _titlePrefix     = null;
	private WindowType  _windowType      = null;

	private JButton     _connect_but     = SwingUtils.makeToolbarButton(Version.class, "connect_16.png",    ACTION_CONNECT,    this, "Connect to a DBMS",         "Connect");
	private JButton     _disconnect_but  = SwingUtils.makeToolbarButton(Version.class, "disconnect_16.png", ACTION_DISCONNECT, this, "Close the DBMS Connection", "Disconnect");

	// if we start from the CMD Line, add a few extra stuff
	//---------------------------------------
	private JMenuBar            _main_mb                = new JMenuBar();

	private JToolBar            _toolbar                = new JToolBar();

	// File
	private JMenu               _file_m                 = new JMenu("File");
	private JMenuItem           _connect_mi             = new JMenuItem("Connect...");
	private JMenuItem           _disconnect_mi          = new JMenuItem("Disconnect");
	private JMenuItem           _exit_mi                = new JMenuItem("Exit");

	// View
	private JMenu               _view_m                 = new JMenu("View");
	private JMenuItem           _sqlTrace_mi            = new JMenuItem("SQL Trace...");
//	private JCheckBoxMenuItem   _showExtErrInfo_mi      = new JCheckBoxMenuItem("Show Extended Error information", DEFAULT_showExtErrInfo);
//	private JCheckBoxMenuItem   _enableDbmsOutput_mi    = new JCheckBoxMenuItem("Enable DBMS Output subsystem",    DEFAULT_enableDbmsOutput);
	private JMenuItem           _preferences_mi         = new JMenuItem("Preferences...");

	// Tools
	private JMenu               _tools_m                = new JMenu("Tools");
	private JMenuItem           _toolDummy_mi           = new JMenuItem("Dummy entry");
//	private JMenuItem           _sqlw_mi                = new JMenuItem("SQL Window...");


	public static DemoApp getInstance()
	{
		return _instance;
	} 
	public static boolean hasInstance()
	{
		return _instance != null;
	} 

	/**
	 * Constructor for CommandLine parameters
	 * @param cmd
	 * @throws Exception
	 */
	public DemoApp(final CommandLine cmd)
	throws Exception
	{
		Version.setAppName(APP_NAME);

		// Create store dir if it did not exists.
		File appStoreDir = new File(Version.APP_STORE_DIR);
		if ( ! appStoreDir.exists() )
		{
			if (appStoreDir.mkdir())
				System.out.println("Creating directory '"+appStoreDir+"' to hold various files for "+Version.getAppName());
		}

		// -----------------------------------------------------------------
		// CHECK/SETUP information from the CommandLine switches
		// -----------------------------------------------------------------
		final String CONFIG_FILE_NAME      = System.getProperty("CONFIG_FILE_NAME",      "dbmtkDemo.properties");
//		final String USER_CONFIG_FILE_NAME = System.getProperty("USER_CONFIG_FILE_NAME", "dbmtkDemo.user.properties");
		final String TMP_CONFIG_FILE_NAME  = System.getProperty("TMP_CONFIG_FILE_NAME",  "dbmtkDemo.save.properties");
		final String APP_HOME             = System.getProperty("APP_HOME");

		String defaultPropsFile     = (APP_HOME              != null) ? APP_HOME              + File.separator + CONFIG_FILE_NAME      : CONFIG_FILE_NAME;
//		String defaultUserPropsFile = (Version.APP_STORE_DIR != null) ? Version.APP_STORE_DIR + File.separator + USER_CONFIG_FILE_NAME : USER_CONFIG_FILE_NAME;
		String defaultTmpPropsFile  = (Version.APP_STORE_DIR != null) ? Version.APP_STORE_DIR + File.separator + TMP_CONFIG_FILE_NAME  : TMP_CONFIG_FILE_NAME;

		// Compose MAIN CONFIG file
		String filename = Version.APP_STORE_DIR + File.separator + CONFIG_FILE_NAME;
		if ( (new File(filename)).exists() )
			defaultPropsFile = filename;

		String propFile        = cmd.getOptionValue("config",     defaultPropsFile);
//		String userPropFile    = cmd.getOptionValue("userConfig", defaultUserPropsFile);
		String tmpPropFile     = cmd.getOptionValue("tmpConfig",  defaultTmpPropsFile);

//		// Check if the configuration file exists
//		if ( ! (new File(propFile)).exists() )
//			throw new FileNotFoundException("The configuration file '"+propFile+"' doesn't exists.");

		// -----------------------------------------------------------------
		// CHECK JAVA JVM VERSION
		// -----------------------------------------------------------------
//		int javaVersionInt = JavaVersion.getVersion();
//		if (   javaVersionInt != JavaVersion.VERSION_NOTFOUND
//		    && javaVersionInt <  JavaVersion.VERSION_1_6
//		   )
//		{
//			System.out.println("");
//			System.out.println("===============================================================");
//			System.out.println(" "+Version.getAppName()+" needs a runtime JVM 1.6 or higher.");
//			System.out.println(" java.version = " + System.getProperty("java.version"));
//			System.out.println(" which is parsed into the number: " + JavaVersion.getVersion());
//			System.out.println("---------------------------------------------------------------");
//			System.out.println("");
//			throw new Exception(Version.getAppName()+" needs a runtime JVM 1.6 or higher.");
//		}

		// The SAVE Properties...
		Configuration appSaveProps = new Configuration(tmpPropFile);
		Configuration.setInstance(Configuration.USER_TEMP, appSaveProps);

		// Get the USER properties that could override CONF
//		Configuration appUserProps = new Configuration(userPropFile);
//		Configuration.setInstance(Configuration.USER_CONF, appUserProps);

		// Get the "OTHER" properties that has to do with LOGGING etc...
//		Configuration appProps = new Configuration(propFile);
//		Configuration.setInstance(Configuration.SYSTEM_CONF, appProps);

		// Set the Configuration search order when using the: Configuration.getCombinedConfiguration()
//		Configuration.setSearchOrder(
//			Configuration.TAIL_TEMP,    // First
//			Configuration.USER_TEMP,    // Second
//			Configuration.USER_CONF,    // Third
//			Configuration.SYSTEM_CONF // Forth
//			);
		Configuration.setSearchOrder(Configuration.USER_TEMP);

		Logging.init(null, propFile);

		_logger.info("Storage file for properties are '"+Configuration.getInstance(Configuration.USER_TEMP).getFilename()+"'.");

    	try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) {
			e.printStackTrace();
		}

		// Create a QueryWindow component that uses the factory object.
		final DemoApp demoApp = new DemoApp(WindowType.CMDLINE_JFRAME);

		// Install shutdown hook: used to...
		Runtime.getRuntime().addShutdownHook(new Thread()
		{
			@Override
			public void run()
			{
				_logger.debug("----Start Shutdown Hook");
				_logger.debug("----End Shutdown Hook");
			}
		});

		// Install our own EventQueue handler, to handle/log strange exceptions in the event dispatch thread
//		EventQueueProxy.install();

		// REMOVE THIS.... it's just to view the splash screen a little bit longer
		Thread.sleep(2500);

		// Now open the window
		demoApp.openTheWindow();
	}

	/**
	 * This constructor method creates a simple GUI and hooks up an event
	 * listener that updates the table when the user enters a new query.
	 **/
	public DemoApp(WindowType winType)
	{
		_instance = this;
		_windowType = winType;

		if (winType == WindowType.CMDLINE_JFRAME)
		{
			//_titlePrefix = Version.getAppName()+" Query Window";
			_titlePrefix = Version.getAppName();
			_jframe  = new JFrame(_titlePrefix);
			_jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			_window  = _jframe;
		}
		if (winType == WindowType.JFRAME)
		{
			_titlePrefix = Version.getAppName();
			_jframe  = new JFrame(_titlePrefix);
			_window  = _jframe;
		}
		if (winType == WindowType.JDIALOG)
		{
			_titlePrefix = Version.getAppName();
			_jdialog = new JDialog((Dialog)null, _titlePrefix);
			_window  = _jdialog;
		}
		if (winType == WindowType.JDIALOG_MODAL)
		{
			_titlePrefix = Version.getAppName();
			_jdialog = new JDialog((Dialog)null, _titlePrefix, true);
			_window  = _jdialog;
		}
		if (_window == null)
			throw new RuntimeException("_window is null, this should never happen.");

		_sqlTrace_mi        .setToolTipText("Open a 'trace' window where you can se what SQL Statements taht has been executed.");
//		_showExtErrInfo_mi  .setToolTipText("Show ASE 'print' messages and 'decoded' messages from any SQLExceptions");
//		_enableDbmsOutput_mi.setToolTipText("Enable or Disable Oracle 'DBMS_OUTPUT' subsystem, which is emulated in the SAP DBMTK Runtime Components as 'buffered_output'.");
		
		//--------------------------
		// MENU - composition
//		if (_jframe != null)
		if (winType == WindowType.CMDLINE_JFRAME)
		{
			_jframe.setJMenuBar(_main_mb);

			_main_mb.add(_file_m);
			_main_mb.add(_view_m);
			_main_mb.add(_tools_m);

			// FILE
			_file_m.add(_connect_mi);
			_file_m.add(_disconnect_mi);
			_file_m.addSeparator();
			_file_m.add(_exit_mi);

			_file_m .setMnemonic(KeyEvent.VK_F);

			// VIEW
			_view_m.add(_sqlTrace_mi);
//			_view_m.add(_showExtErrInfo_mi);
//			_view_m.add(_enableDbmsOutput_mi);
			_view_m.add(_preferences_mi);


			// TOOLS
			_tools_m.add(_toolDummy_mi);
//			_tools_m.add(_sqlw_mi);

			_toolDummy_mi    .setVisible(false);
//			_sqlw_mi         .setVisible(true);


			_file_m .setMnemonic(KeyEvent.VK_T);

			_connect_mi        .setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | KeyEvent.SHIFT_MASK));
			_disconnect_mi     .setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | KeyEvent.SHIFT_MASK));

			// TOOLBAR
			_toolbar.setLayout(new MigLayout("insets 0 0 0 3", "", "")); // insets Top Left Bottom Right

			// Add some title in the toolbar
			ImageIcon sap16x32 = SwingUtils.readImageIcon(DemoApp.class, "images/sap_16x32.png");
//			JLabel sapIcon = new JLabel("Publications Register ", sap16x32, JLabel.LEFT);
			JLabel sapIcon = new JLabel("Publications & Order Administration ", sap16x32, JLabel.LEFT);
			sapIcon.setFont(new java.awt.Font(Font.DIALOG, Font.BOLD, 16));

//			ImageIcon dbmtk_logo_16 = SwingUtils.readImageIcon(DemoApp.class, "images/dbmtk_logo_16.png");
			JLabel dbmtkIcon = new JLabel(createTopRightLogo());

			_toolbar.add(_connect_but);
			_toolbar.add(_disconnect_but);
			_toolbar.add(new JSeparator(SwingConstants.VERTICAL), "grow");

			_toolbar.add(sapIcon, "");
			_toolbar.add(new JLabel(), "growx, pushx");
			_toolbar.add(dbmtkIcon, "");

			// Visibility for TOOLBAR components at startup

			//--------------------------
			// MENU - Icons
			_connect_mi            .setIcon(SwingUtils.readImageIcon(Version.class, "images/connect_16.png"));
			_disconnect_mi         .setIcon(SwingUtils.readImageIcon(Version.class, "images/disconnect_16.png"));
			_exit_mi               .setIcon(SwingUtils.readImageIcon(Version.class, "images/close.gif"));

			//--------------------------
			// MENU - Actions
			_connect_mi         .setActionCommand(ACTION_CONNECT);
			_disconnect_mi      .setActionCommand(ACTION_DISCONNECT);
			_exit_mi            .setActionCommand(ACTION_EXIT);

			_sqlTrace_mi        .setActionCommand(ACTION_OPEN_SQL_TRACE);
//			_showExtErrInfo_mi  .setActionCommand(ACTION_SAVE_PROPS);
//			_enableDbmsOutput_mi.setActionCommand(ACTION_DBMS_OUTPUT);
//			_sqlw_mi            .setActionCommand(ACTION_OPEN_SQL_WINDOW);
			_preferences_mi     .setActionCommand(ACTION_OPEN_PREFERENCES);


			//--------------------------
			// And the action listener
			_connect_mi         .addActionListener(this);
			_disconnect_mi      .addActionListener(this);
			_exit_mi            .addActionListener(this);

			_sqlTrace_mi        .addActionListener(this);
//			_showExtErrInfo_mi  .addActionListener(this);
//			_enableDbmsOutput_mi.addActionListener(this);
//			_sqlw_mi            .addActionListener(this);
			_preferences_mi     .addActionListener(this);
		}

//		ImageIcon icon16 = SwingUtils.readImageIcon(DemoApp.class, "images/dbmtk_demo_window_16.png");
//		ImageIcon icon32 = SwingUtils.readImageIcon(DemoApp.class, "images/dbmtk_demo_window_32.png");
		ImageIcon icon16 = createIconWindow16();
		ImageIcon icon32 = createIconWindow32();

		ArrayList<Image> iconList = new ArrayList<Image>();
		if (icon16 != null) iconList.add(icon16.getImage());
		if (icon32 != null) iconList.add(icon32.getImage());
		_window.setIconImages(iconList);

		// Place the components within this window
		Container contentPane = _jframe != null ? _jframe.getContentPane() : _jdialog.getContentPane();
		contentPane.setLayout(new BorderLayout());

		_baseDemoPanel = createBaseDemoPane();
//		_bottomPane    = createBottomPane();

		setWatermarkAnchor(_baseDemoPanel);
		setWatermark();

		if (winType == WindowType.CMDLINE_JFRAME)
			contentPane.add(_toolbar, BorderLayout.NORTH);
		contentPane.add(_mainPane);

		_baseDemoPanel.setMinimumSize(new Dimension(300, 100));


		_mainPane.add(_baseDemoPanel,     "dock center");
		_mainPane.add(_statusBar,         "dock south");

		_statusBar.setVisibleAtLineCol(false);

		// load windows properties
		// note this is done in openTheWindow()
//		loadWinProps();

		loadProps();

		// Set components if visible, enabled etc...
		setComponentVisibility();


		// Arrange to quit the program when the user closes the window
		_window.addWindowListener(new WindowAdapter()
		{
			@Override
			public void windowClosing(WindowEvent e)
			{
				saveProps();
				saveWinProps();

				close();
			}

			@Override
			public void windowActivated(WindowEvent e)
			{
			}
			@Override
			public void windowDeactivated(WindowEvent e)
			{
			}
		});
	}

	private ImageIcon createTopRightLogo()
	{
		try
		{
			String appDemoHome  = System.getProperty("DBMTK_DEMO_HOME");
			String iconFilename = appDemoHome == null ? "./lib/dbmtk_logo_16.png" : appDemoHome+"/lib/dbmtk_logo_16.png";
			
			File f = new File(iconFilename);
			if ( ! f.exists() )
			{
				_logger.info("No top right corner logo will be displayed: Can't find the file '"+f+"'.");
				return null;
			}

			URL url = f.toURI().toURL();
			ImageIcon icon = new ImageIcon(Toolkit.getDefaultToolkit().getImage(url));
			return icon;
		}
		catch (MalformedURLException e)
		{
			_logger.info("No top right corner logo will be displayed: Caught: "+e);
			return null;
		}
	}
	private ImageIcon createIconWindow16()
	{
		ImageIcon defaultIcon = SwingUtils.readImageIcon(DemoApp.class, "images/dbmtk_demo_window_16.png");
		try
		{
			String appDemoHome  = System.getProperty("DBMTK_DEMO_HOME");
			String iconFilename = appDemoHome == null ? "./lib/dbmtk_demo_window_16.png" : appDemoHome+"/lib/dbmtk_demo_window_16.png";
			
			File f = new File(iconFilename);
			if ( ! f.exists() )
			{
				_logger.info("Using default window-16x16 icon. Can't find the file '"+f+"'.");
				return defaultIcon;
			}

			URL url = f.toURI().toURL();
			ImageIcon icon = new ImageIcon(Toolkit.getDefaultToolkit().getImage(url));
			return icon;
		}
		catch (MalformedURLException e)
		{
			_logger.info("Using default window-16x16 icon. Caught: "+e);
			return defaultIcon;
		}
	}
	private ImageIcon createIconWindow32()
	{
		ImageIcon defaultIcon = SwingUtils.readImageIcon(DemoApp.class, "images/dbmtk_demo_window_32.png");
		try
		{
			String appDemoHome  = System.getProperty("DBMTK_DEMO_HOME");
			String iconFilename = appDemoHome == null ? "./lib/dbmtk_demo_window_32.png" : appDemoHome+"/lib/dbmtk_demo_window_32.png";
			
			File f = new File(iconFilename);
			if ( ! f.exists() )
			{
				_logger.info("Using default window-32x32 icon. Can't find the file '"+f+"'.");
				return defaultIcon;
			}

			URL url = f.toURI().toURL();
			ImageIcon icon = new ImageIcon(Toolkit.getDefaultToolkit().getImage(url));
			return icon;
		}
		catch (MalformedURLException e)
		{
			_logger.info("Using default window-32x32 icon. Caught: "+e);
			return defaultIcon;
		}
	}

	private JPanel createBaseDemoPane()
	{
		JPanel panel = new JPanel();
		panel.setLayout(new MigLayout("insets 0 0 0 0", "", ""));   // insets Top Left Bottom Right

		_dbms_lbl.setFont(new java.awt.Font(Font.DIALOG, Font.BOLD, 14));
		_dbms_txt.setFont(new java.awt.Font(Font.DIALOG, Font.BOLD, 14));

//		panel.add(new SapSeparator(), "growx, pushx, wrap");

//		panel.add(createTopPane(),    "grow, push, wrap");
		panel.add(createTabPane(),    "grow, push, wrap");

//		panel.add(new SapSeparator(), "growx, pushx, wrap");
		panel.add(_dbms_lbl,          "split");
		panel.add(_dbms_txt,          "growx, pushx, wrap");

		return panel;
	}

	private GTabbedPane createTabPane()
	{
//		_tabPane = new JTabbedPane();
		_tabPane = new GTabbedPane();

		ImageIcon authors_ico    = SwingUtils.readImageIcon(DemoApp.class, "images/author_16.gif");
		ImageIcon titles_ico     = SwingUtils.readImageIcon(DemoApp.class, "images/book_16.png");
		ImageIcon publishers_ico = SwingUtils.readImageIcon(DemoApp.class, "images/publisher_16.png");
//		ImageIcon sales_ico      = SwingUtils.readImageIcon(DemoApp.class, "images/sale_16.png");
		ImageIcon stores_ico     = SwingUtils.readImageIcon(DemoApp.class, "images/store_16.png");
		ImageIcon orders_ico     = SwingUtils.readImageIcon(DemoApp.class, "images/order_16.png");
		ImageIcon stats_ico      = SwingUtils.readImageIcon(DemoApp.class, "images/stats_16.png");

		// Create Data Panels
		_authors         = new DataPanelAuthors        (this);
		_authorTitles    = new DataPanelAuthorTitles   (this);
		_authorsPanel    = new SplitPanelAbstract      (this, TAB_AUTHORS, _authors, _authorTitles);

		_titles          = new DataPanelTitles         (this);

		_publishers      = new DataPanelPublishers     (this);
		_publisherTitles = new DataPanelPublisherTitles(this);
		_publishersPanel = new SplitPanelAbstract      (this, TAB_PUBLISHERS, _publishers, _publisherTitles);

		_stores          = new DataPanelStores         (this);

		_orders          = new DataPanelOrders         (this);
		_orderDetails    = new DataPanelOrderDetails   (this);
		_ordersPanel     = new SplitPanelAbstract      (this, TAB_ORDERS, _orders, _orderDetails);

		_statistics      = new DataPanelStatistics     (this);

		// Also add special listener so that titles gets "notified" if authors or publishers changes selections
		// The titles tab will only react to those selections if it's UnDocked (but that logic goes in the DatPanelTitles)
		_authors   .addChildTableSelectionListener(_titles);
		_publishers.addChildTableSelectionListener(_titles);


		// Now add the items to the main-tab
		_tabPane.addTab(TAB_AUTHORS,    authors_ico,    _authorsPanel   );
		_tabPane.addTab(TAB_TITLES,     titles_ico,     _titles         );
		_tabPane.addTab(TAB_PUBLISHERS, publishers_ico, _publishersPanel);
		_tabPane.addTab(TAB_STORES,     stores_ico,     _stores         );
//		_tabPane.addTab(TAB_ORDERS,     orders_ico,     _orders         );
		_tabPane.addTab(TAB_ORDERS,     orders_ico,     _ordersPanel    );
		_tabPane.addTab(TAB_STATS,      stats_ico,      _statistics     );

		// 
		_tabPane.addChangeListener(new ChangeListener()
		{
			@Override
			public void stateChanged(ChangeEvent e)
			{
				String tabName = _tabPane.getSelectedTitle(false);

				if      (TAB_AUTHORS   .equals(tabName)) _authorsPanel   .onTabSelected();
				else if (TAB_TITLES    .equals(tabName)) _titles         .onTabSelected();
				else if (TAB_PUBLISHERS.equals(tabName)) _publishersPanel.onTabSelected();
				else if (TAB_STORES    .equals(tabName)) _stores         .onTabSelected();
				else if (TAB_ORDERS    .equals(tabName)) _ordersPanel    .onTabSelected();
				else if (TAB_STATS     .equals(tabName)) _statistics     .onTabSelected();
			}
		});

		return _tabPane;
	}

//	public boolean isOracle()
//	{
//		return DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_ORACLE);
//	}
	public String getConnectedProductName()
	{
		return _connectedToProductName;
	}

	public boolean isTabUnDocked(String tabTitle)
	{
		return _tabPane.isTabUnDocked(tabTitle);
	}

	public boolean isTabSelected(String tabTitle)
	{
		return tabTitle.equals(_tabPane.getSelectedTitle(false));
	}

	public Window getWindow()
	{
		return _window;
	}


	//---------------------------------------------------------------------
	// BEGIN implement: ConnectionProvider
	//---------------------------------------------------------------------
	/**
	 * Just check if the connection isn't null...
	 */
	@Override
	public boolean isConnected()
	{
		if (_conn == null)
			return false;

		return true;
	}

	/**
	 * issue some QSL Statement trying to find out if we are still connected...<br>
	 * ORACLE: select 1 from DUAL <br>
	 * DB2:    select 1 from SYSIBM.SYSDUMMY1 <br>
	 * OTHRES: select 1
	 */
	@Override
	public Connection getConnection()
	throws SQLException
	{
		return getConnection(false);
	}
	@Override
	public Connection getConnection(boolean forceConnectionCheck)
	throws SQLException
	{
		if (_conn == null)
			throw new SQLException("Not Connected!");

		try
		{
			// are we still connected?
			// But this doesn't *really* try out the connection
			_conn.isClosed();

			// issue dummy SQL to check if we are connected or not
			// if it has been done recently skip this
			long lastCheckWasDone = System.currentTimeMillis() - _connCheckLastTime;
			if (forceConnectionCheck || lastCheckWasDone >_connCheckTimeout)
			{
				doDummySelect();
				_connCheckLastTime = System.currentTimeMillis();
			}
		}
		catch (SQLException e)
		{
//			onLostConnection();
			throw e;
		}

		return _conn;
	}

	@Override
	public boolean isAutoCommitEnabledAtConnect()
	{
		return _autoCommitEnabledAtConnect;
	}

	private List<DbMessage> _warningMessages = new ArrayList<DbMessage>(); 
	@Override
	public List<DbMessage> getWarningMessages(boolean reset)
	{
		List<DbMessage> list = _warningMessages;
		if (reset)
			_warningMessages = new ArrayList<DbMessage>();

		return list;
	}
	@Override
	public void addWarningMessage(DbMessage message)
	{
		_warningMessages.add(message);
	}

//	@Override
//	public Connection getNewConnection(String appname)
//	{
//		throw new RuntimeException("Not yet implemeted");
//	}

	//---------------------------------------------------------------------
	// END implement: ConnectionProvider
	//---------------------------------------------------------------------

//	/**
//	 * Local method to get AutoCommit, in jConnect the value seems to be cached... <br>
//	 * so if you change it at the server with 'set chained on|off' the return value might be changed.
//	 * @return true=inAutoCommit(un-chained-mode), false=notInAutoCommit(chained-mode)
//	 * @throws SQLException
//	 */
//	public boolean getAutoCommit()
//	throws SQLException
//	{
//		Connection conn = getConnection();
//
//		boolean isAutoCommit = true; // well this is the default...
//
//		if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_SYBASE_ASE, DbUtils.DB_PROD_NAME_SYBASE_ASA, DbUtils.DB_PROD_NAME_SYBASE_IQ))
//		{
//			int atatTranChained = -1;
//
//			Statement stmnt = conn.createStatement();
//			ResultSet rs    = stmnt.executeQuery("select @@tranchained");
//			while (rs.next())
//				atatTranChained = rs.getInt(1);
//
//			if (atatTranChained != -1)
//				isAutoCommit = (atatTranChained == 0 ? true : false);
//		}
//		else
//		{
//			isAutoCommit = conn.getAutoCommit();
//		}
//
//		return isAutoCommit;
//	}



//	private JPanel createBottomPane()
//	{
//		JPanel panel = new JPanel();
//		panel.setLayout(new MigLayout("wrap 1", "", ""));   // insets Top Left Bottom Right
//
//		panel.add(new JButton("BottomPanel"), "growx, pushx");
//
//		return panel;
//	}


	private void loadProps()
	{
//		Configuration conf = Configuration.getCombinedConfiguration();

//		_showExtErrInfo_mi         .setSelected( conf.getBooleanProperty(PROPKEY_showExtErrInfo,                    DEFAULT_showExtErrInfo) );
//		_enableDbmsOutput_mi       .setSelected( conf.getBooleanProperty(PROPKEY_enableDbmsOutput,                  DEFAULT_enableDbmsOutput) );
	}

	private void saveProps()
	{
		Configuration conf = Configuration.getInstance(Configuration.USER_TEMP);
		if (conf == null)
			return;

		if (_windowType == null || ( _windowType != null && _windowType != WindowType.CMDLINE_JFRAME) )
			return;

//		conf.setProperty(PROPKEY_showExtErrInfo,                    _showExtErrInfo_mi        .isSelected());
//		conf.setProperty(PROPKEY_enableDbmsOutput,                  _enableDbmsOutput_mi      .isSelected());

		conf.save();
	}

	/**
	 * Saves some properties about the window
	 * <p>
	 * NOTE: normally you would load window size via loadWinProps(), but this is done openTheWindow()...
	 */
	public void saveWinProps()
	{
		Configuration conf = Configuration.getInstance(Configuration.USER_TEMP);
		if (conf == null)
			return;

		if (_window == null)
			return;

		conf.setProperty(PROPKEY_APP_PREFIX+"size.width",         _window.getSize().width);
		conf.setProperty(PROPKEY_APP_PREFIX+"size.height",        _window.getSize().height);
		conf.setProperty(PROPKEY_APP_PREFIX+"splitPane.location", _splitPane.getDividerLocation());

		if (_window.isVisible())
		{
			conf.setProperty(PROPKEY_APP_PREFIX+"size.pos.x",  _window.getLocationOnScreen().x);
			conf.setProperty(PROPKEY_APP_PREFIX+"size.pos.y",  _window.getLocationOnScreen().y);
		}

		conf.save();
	}

	/**
	 *
	 * @param width
	 * @param height
	 */
	public void setSize(int width, int height)
	{
		_window.setSize(width, height);
	}
	/**
	 *
	 * @param comp
	 */
	public void setLocationRelativeTo(Component comp)
	{
		_window.setLocationRelativeTo(comp);
	}
	/**
	 *
	 * @param b
	 */
	public void setVisible(boolean b)
	{
		_window.setVisible(b);
	}


	/*---------------------------------------------------
	** BEGIN: implementing ActionListener
	**--------------------------------------------------*/
	@Override
	public void actionPerformed(ActionEvent e)
	{
//		Object source    = e.getSource();
		String actionCmd = e.getActionCommand();

		_logger.debug("ACTION '"+actionCmd+"'.");

		if (ACTION_CONNECT.equals(actionCmd))
			action_connect(e);

		if (ACTION_DISCONNECT.equals(actionCmd))
			action_disconnect(e);


		if (ACTION_EXIT.equals(actionCmd))
			action_exit(e);

		if (ACTION_OPEN_SQL_TRACE.equals(actionCmd))
			action_sqlTrace(e);

		if (ACTION_SAVE_PROPS.equals(actionCmd))
			saveProps();

		if (ACTION_DBMS_OUTPUT.equals(actionCmd))
			action_dbmsOutput();

//		if (ACTION_OPEN_SQL_WINDOW.equals(actionCmd))
//			action_sqlw(e);

		if (ACTION_OPEN_PREFERENCES.equals(actionCmd))
			action_openPreferences(e);

		setComponentVisibility();
		setWatermark();
	}

	/*---------------------------------------------------
	** END: implementing ActionListener
	**--------------------------------------------------*/


	public void refreshStatusBar()
	{
		if (_conn == null)
		{
			onLostConnection();
//			setWatermark();
			return;
		}

		try
		{
			// are we still connected?
			_conn.isClosed();

			// issue 'select 1' to check if the connection is valid
			doDummySelect();

			// if ASE, refresh the database list and currect working database
//			if (_connectedToProductName != null && _connectedToProductName.equals(DbUtils.DB_PROD_NAME_SYBASE_ASE))
			if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_SYBASE_ASE, DbUtils.DB_PROD_NAME_MSSQL))
			{
//				// getCurrentDb() is also done in setDbNames()
//				// it only refreshes the DB Combobox if number of databases has changed.
//				setDbNames();

				// Also get "various statuses" like if we are in a transaction or not
				boolean getTranState = DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_SYBASE_ASE);
				_aseConnectionStateInfo = AseConnectionUtils.getAseConnectionStateInfo(_conn, getTranState);
				_statusBar.setAseConnectionStateInfo(_aseConnectionStateInfo);
			}
			else if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_SYBASE_RS))
			{
				// Do nothing
			}
			else
			{
				_jdbcConnectionStateInfo = DbUtils.getJdbcConnectionStateInfo(_conn);
				_statusBar.setJdbcConnectionStateInfo(_jdbcConnectionStateInfo);
			}
		}
		catch (SQLException e)
		{
			_conn = null;
		}

		setWatermark();
	}

	/**
	 * Set the windows title
	 * @param srvStr servername we are connected to, null = not connected.
	 */
	private void setSrvInTitle(String srvStr)
	{
		String title = _titlePrefix;
		if (srvStr != null)
			title += " - " + srvStr;

		if (_jframe  != null) _jframe .setTitle(title);
		if (_jdialog != null) _jdialog.setTitle(title);
	}

	private void action_connect(ActionEvent e)
	{
		// Create a new dialog Window
//		boolean checkAseCfg    = false;
//		boolean showAseTab     = true;
//		boolean showAseOptions = false;
//		boolean showHostmonTab = false;
//		boolean showPcsTab     = false;
//		boolean showOfflineTab = false;
//		boolean showJdbcTab    = true;

		_srvVersion                 = 0;
//		_connectedAtTime            = 0;
		_connectedDriverName        = null;
		_connectedDriverVersion     = null;
		_connectedToProductName     = null;
		_connectedToProductVersion  = null;
		_connectedToServerName      = null;
		_connectedSrvCharset        = null;
		_connectedSrvSortorder      = null;
		_connectedAsUser            = null;
		_connectedWithUrl           = null;

		// Create the connection dialog
//		ConnectionDialog connDialog = new ConnectionDialog(_jframe, checkAseCfg, showAseTab, showAseOptions, showHostmonTab, showPcsTab, showOfflineTab, showJdbcTab);
		ConnectionDialog connDialog = new ConnectionDialog(_jframe);

		// Show the dialog and wait for response
		connDialog.setVisible(true);
		connDialog.dispose();

		// Get what was connected to...
		int connType = connDialog.getConnectionType();

		if ( connType == ConnectionDialog.CANCEL)
			return;

		// Get product info
		try
		{
			_srvVersion                 = 0;
//			_connectedAtTime            = System.currentTimeMillis();
			_connectedDriverName        = connDialog.getDriverName();
			_connectedDriverVersion     = connDialog.getDriverVersion();
			_connectedToProductName     = connDialog.getDatabaseProductName();
			_connectedToProductVersion  = connDialog.getDatabaseProductVersion();
			_connectedToServerName      = connDialog.getDatabaseServerName();
			_connectedSrvCharset        = null;
			_connectedSrvSortorder      = null;
			_connectedAsUser            = connDialog.getUsername();
			_connectedWithUrl           = connDialog.getUrl();

			// NOTE: in ASE 16 it seems the getDatabaseProductVersion() only returns a short version string... (probably select @@sbssav)
			//       so if it's ASE: lets get the @@version string to be backward compatible
			if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_SYBASE_ASE))
			{
				_connectedToProductVersion  = AseConnectionUtils.getAseVersionStr(connDialog.getConnection());
			}

			// NOTE: HANA
			//       so if it's ASE: lets get the @@version string to be backward compatible
			if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_HANA))
			{
				_connectedToProductVersion  = "SAP HANA, Version: "+_connectedToProductVersion;
			}

//			String displayStr = "<HTML>" + _connectedToProductVersion.replace("\n", "<BR>") + "</HTML>";
			String displayStr = _connectedToProductVersion.replace("\n", " ");
			_dbms_txt.setText(displayStr);

			_logger.info("Connected to DatabaseProductName='"+_connectedToProductName+"', DatabaseProductVersion='"+_connectedToProductVersion+"', DatabaseServerName='"+_connectedToServerName+"' with Username='"+_connectedAsUser+"', toURL='"+_connectedWithUrl+"', using Driver='"+_connectedDriverName+"', DriverVersion='"+_connectedDriverVersion+"'.");
		}
		catch (Throwable ex)
		{
			if (_logger.isDebugEnabled())
				_logger.warn("Problems getting DatabaseProductName, DatabaseProductVersion, DatabaseServerName or Username. Caught: "+ex, ex);
			else
				_logger.warn("Problems getting DatabaseProductName, DatabaseProductVersion, DatabaseServerName or Username. Caught: "+ex);
		}

//		if ( connType == ConnectionDialog.TDS_CONN)
//		{
//			_conn = connDialog.getAseConn();
//
//			if (AseConnectionUtils.isConnectionOk(_conn, true, _jframe))
//			{
//				_connType = ConnectionDialog.TDS_CONN;
//
//				if (connDialog.isDatabaseProduct(DbUtils.DB_PROD_NAME_SYBASE_ASE))
//				{
////					setDbNames();
//
//					_srvVersion              = AseConnectionUtils.getAseVersionNumber(_conn);
//
//					// Only SA_ROLE can get listeners
//					_connectedToSysListeners = "Sorry you need 'sa_role' to query master..syslisteners";
//					if (AseConnectionUtils.hasRole(_conn, AseConnectionUtils.SA_ROLE))
//						_connectedToSysListeners = AseConnectionUtils.getListeners(_conn, false, false, _window);
//
//					// Sortorder & charset
//					_connectedSrvCharset        = AseConnectionUtils.getAseCharset(_conn);
//					_connectedSrvSortorder      = AseConnectionUtils.getAseSortorder(_conn);
//					_connectedClientCharsetId   = AseConnectionUtils.getClientCharsetId(_conn);
//					_connectedClientCharsetName = AseConnectionUtils.getClientCharsetName(_conn);
//					_connectedClientCharsetDesc = AseConnectionUtils.getClientCharsetDesc(_conn);
//
//					// Also get "various statuses" like if we are in a transaction or not
//					_aseConnectionStateInfo = AseConnectionUtils.getAseConnectionStateInfo(_conn, true);
//					_statusBar.setAseConnectionStateInfo(_aseConnectionStateInfo);
//					setWatermark();
//				}
//				else if (connDialog.isDatabaseProduct(DbUtils.DB_PROD_NAME_SYBASE_ASA))
//				{
////					_aseVersion = AseConnectionUtils.getAsaVersionNumber(_conn); // FIXME: ASA has another "system"
//
//					// Sortorder & charset
//					_connectedSrvCharset   = AseConnectionUtils.getAsaCharset(_conn);
//					_connectedSrvSortorder = AseConnectionUtils.getAsaSortorder(_conn);
//
//					// JDBC Specific statuses
//					_jdbcConnectionStateInfo = DbUtils.getJdbcConnectionStateInfo(_conn);
//					_statusBar.setJdbcConnectionStateInfo(_jdbcConnectionStateInfo);
//
//					_logger.info("Connected to SQL Anywhere version '"+_srvVersion+"'.");
//				}
//				else if (connDialog.isDatabaseProduct(DbUtils.DB_PROD_NAME_SYBASE_IQ))
//				{
////					_aseVersion = AseConnectionUtils.getIqVersionNumber(_conn); // FIXME: IQ has another "system"
//
//					// Sortorder & charset
//					_connectedSrvCharset   = AseConnectionUtils.getAsaCharset(_conn);
//					_connectedSrvSortorder = AseConnectionUtils.getAsaSortorder(_conn);
//
//					// JDBC Specific statuses
//					_jdbcConnectionStateInfo = DbUtils.getJdbcConnectionStateInfo(_conn);
//					_statusBar.setJdbcConnectionStateInfo(_jdbcConnectionStateInfo);
//
//					_logger.info("Connected to Sybase IQ version '"+_srvVersion+"'.");
//				}
//				else
//				{
//					_logger.info("Connected to 'other' Sybase TDS server with product name'"+_connectedToProductName+"'.");
//				}
//
//			} // end: connectionIsOk
//			else
//			{
//			}
//		}
//		else if ( connType == ConnectionDialog.JDBC_CONN)
//		{
//			_conn = connDialog.getJdbcConn();
//			_connType = ConnectionDialog.JDBC_CONN;
//
//			_srvVersion = -1;
//
//			//---------------------------------------------------
//			// Get specific stuff for various products
//
//			// HANA
//			if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_HANA))
//			{
//				// Sortorder & charset
//				_connectedSrvCharset   = "UTF8";
//				_connectedSrvSortorder = "BINARY";
//			}
//			// ORACLE
//			else if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_ORACLE))
//			{
//				// Sortorder & charset
//				_connectedSrvCharset   = DbUtils.getOracleCharset(_conn);
//				_connectedSrvSortorder = DbUtils.getOracleSortorder(_conn);
//			}
//			// MS-SQL
//			else if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_MSSQL))
//			{
//				// Sortorder & charset
//				//_connectedSrvCharset   = DbUtils.getMsSqlCharset(_conn);
//				//_connectedSrvSortorder = DbUtils.getMsSqlSortorder(_conn);
//			}
//			// DB2
//			else if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_DB2_UX))
//			{
//				// Sortorder & charset
//				_connectedSrvCharset   = DbUtils.getDb2Charset(_conn);
//				_connectedSrvSortorder = DbUtils.getDb2Sortorder(_conn);
//			}
//			else
//			{
//			}
//
//
//
//			//---------------------------------------------------
//			// Connection STATE information
//			//---------------------------------------------------
//			if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_MSSQL))
//			{
//				// Connection info status: USE ASE stuff...
////				setDbNames();
//
//				// Also get "various statuses" like if we are in a transaction or not
//				_aseConnectionStateInfo = AseConnectionUtils.getAseConnectionStateInfo(_conn, false);
//				_statusBar.setAseConnectionStateInfo(_aseConnectionStateInfo);
//
//			}
//			else
//			{
//				//---------------------------------------------------
//				// JDBC Specific status - refreshed after each execution
//				_jdbcConnectionStateInfo = DbUtils.getJdbcConnectionStateInfo(_conn);
//				_statusBar.setJdbcConnectionStateInfo(_jdbcConnectionStateInfo);
//			}
//		}

		_conn = connDialog.getConnection();
		_srvVersion = -1;

		// ASE
		if (connDialog.isDatabaseProduct(DbUtils.DB_PROD_NAME_SYBASE_ASE))
		{
			_connType = ConnectionDialog.TDS_CONN;
//			setDbNames();

			_srvVersion              = AseConnectionUtils.getAseVersionNumber(_conn);

			// Only SA_ROLE can get listeners
			_connectedToSysListeners = "Sorry you need 'sa_role' to query master..syslisteners";
			if (AseConnectionUtils.hasRole(_conn, AseConnectionUtils.SA_ROLE))
				_connectedToSysListeners = AseConnectionUtils.getListeners(_conn, false, false, _window);

			// Sortorder & charset
			_connectedSrvCharset        = AseConnectionUtils.getAseCharset(_conn);
			_connectedSrvSortorder      = AseConnectionUtils.getAseSortorder(_conn);
			_connectedClientCharsetId   = AseConnectionUtils.getClientCharsetId(_conn);
			_connectedClientCharsetName = AseConnectionUtils.getClientCharsetName(_conn);
			_connectedClientCharsetDesc = AseConnectionUtils.getClientCharsetDesc(_conn);

			// Also get "various statuses" like if we are in a transaction or not
			_aseConnectionStateInfo = AseConnectionUtils.getAseConnectionStateInfo(_conn, true);
			_statusBar.setAseConnectionStateInfo(_aseConnectionStateInfo);
			setWatermark();
		}
		// SQL Anywhere / Adapdive Server Anywhere
		else if (connDialog.isDatabaseProduct(DbUtils.DB_PROD_NAME_SYBASE_ASA))
		{
			_connType = ConnectionDialog.TDS_CONN;
//			_aseVersion = AseConnectionUtils.getAsaVersionNumber(_conn); // FIXME: ASA has another "system"

			// Sortorder & charset
			_connectedSrvCharset   = AseConnectionUtils.getAsaCharset(_conn);
			_connectedSrvSortorder = AseConnectionUtils.getAsaSortorder(_conn);

			// JDBC Specific statuses
			_jdbcConnectionStateInfo = DbUtils.getJdbcConnectionStateInfo(_conn);
			_statusBar.setJdbcConnectionStateInfo(_jdbcConnectionStateInfo);

			_logger.info("Connected to SQL Anywhere version '"+_srvVersion+"'.");
		}
		// IQ
		else if (connDialog.isDatabaseProduct(DbUtils.DB_PROD_NAME_SYBASE_IQ))
		{
			_connType = ConnectionDialog.TDS_CONN;
//			_aseVersion = AseConnectionUtils.getIqVersionNumber(_conn); // FIXME: IQ has another "system"

			// Sortorder & charset
			_connectedSrvCharset   = AseConnectionUtils.getAsaCharset(_conn);
			_connectedSrvSortorder = AseConnectionUtils.getAsaSortorder(_conn);

			// JDBC Specific statuses
			_jdbcConnectionStateInfo = DbUtils.getJdbcConnectionStateInfo(_conn);
			_statusBar.setJdbcConnectionStateInfo(_jdbcConnectionStateInfo);

			_logger.info("Connected to Sybase IQ version '"+_srvVersion+"'.");
		}
		// HANA
		else if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_HANA))
		{
			_connType = ConnectionDialog.JDBC_CONN;

			// Sortorder & charset
			_connectedSrvCharset   = "UTF8";
			_connectedSrvSortorder = "BINARY";
		}
		// ORACLE
		else if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_ORACLE))
		{
			_connType = ConnectionDialog.JDBC_CONN;

			// Sortorder & charset
			_connectedSrvCharset   = DbUtils.getOracleCharset(_conn);
			_connectedSrvSortorder = DbUtils.getOracleSortorder(_conn);
		}
		// MS-SQL
		else if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_MSSQL))
		{
			_connType = ConnectionDialog.JDBC_CONN;

			// Sortorder & charset
			//_connectedSrvCharset   = DbUtils.getMsSqlCharset(_conn);
			//_connectedSrvSortorder = DbUtils.getMsSqlSortorder(_conn);
		}
		// DB2
		else if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_DB2_UX))
		{
			_connType = ConnectionDialog.JDBC_CONN;

			// Sortorder & charset
			_connectedSrvCharset   = DbUtils.getDb2Charset(_conn);
			_connectedSrvSortorder = DbUtils.getDb2Sortorder(_conn);
		}
		else
		{
		}



		//---------------------------------------------------
		// Connection STATE information
		//---------------------------------------------------
		if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_MSSQL))
		{
			// Connection info status: USE ASE stuff...
//			setDbNames();

			// Also get "various statuses" like if we are in a transaction or not
			_aseConnectionStateInfo = AseConnectionUtils.getAseConnectionStateInfo(_conn, false);
			_statusBar.setAseConnectionStateInfo(_aseConnectionStateInfo);
		}
		else
		{
			//---------------------------------------------------
			// JDBC Specific status - refreshed after each execution
			_jdbcConnectionStateInfo = DbUtils.getJdbcConnectionStateInfo(_conn);
			_statusBar.setJdbcConnectionStateInfo(_jdbcConnectionStateInfo);
		}



		//---------------------------------------------------
		// Get initial AutoCommit
		//---------------------------------------------------
		try
		{
//			_autoCommitEnabledAtConnect = getConnection().getAutoCommit();
//			_autoCommitEnabledAtConnect = getAutoCommit();
			_autoCommitEnabledAtConnect = DbUtils.getAutoCommit(_conn, _connectedToProductName);
			_logger.info("AutoCommit="+_autoCommitEnabledAtConnect+". This is the initial state of AutoCommit fetched from the server.");
		}
		catch (SQLException ex)
		{
			_logger.warn("Problems getting AutoCommit mode. I will asume that AutoCommit=true, which is the default in JDBC. Caught: "+ex);
		}

		action_dbmsOutput();

		onConnect();

		// What Components should be enabled/visible
		setComponentVisibility();

		// Finally update the watermark
		setWatermark();
	}

	private void action_dbmsOutput()
	{
		if (isConnected())
		{
			try 
			{ 
				boolean onOff = Configuration.getCombinedConfiguration().getBooleanProperty(PROPKEY_enableDbmsOutput, DEFAULT_enableDbmsOutput);
	//			boolean onOff = SqlStatement.dbmsOutput(getConnection(), _enableDbmsOutput_mi.isSelected()); 
				
				SqlStatement.dbmsOutput(getConnection(), onOff); 
			}
			catch (SQLException e) 
			{
				_logger.error("Enable/disabe DBMS Output: Caught: "+e);
			}
		}

		saveProps();
	}

	private void setComponentVisibility()
	{
		// Set all to invisible, later set the ones that should be visible to true

		// view and tools menu might be empty...
		// if so hide the main menu entry as well
		SwingUtils.hideMenuIfNoneIsVisible(_view_m);
		SwingUtils.hideMenuIfNoneIsVisible(_tools_m);

		// sets Save, SaveAs to enabled or not
//		caretUpdate(null);

		if ( ! AseConnectionUtils.isConnectionOk(_conn, false, null) )
		{
			_connect_mi                .setEnabled(true);
			_connect_but               .setEnabled(true);
			_disconnect_mi             .setEnabled(false);
			_disconnect_but            .setEnabled(false);

//			_sqlw_mi                   .setEnabled(false);

			setSrvInTitle(NOT_CONNECTED_STR);
			_statusBar.setNotConnected();

			return;
		}
		else
		{
			_connect_mi     .setEnabled(false);
			_connect_but    .setEnabled(false);
			_disconnect_mi  .setEnabled(true);
			_disconnect_but .setEnabled(true);

//			_sqlw_mi        .setEnabled(true);
		}

		if ( _connType == ConnectionDialog.TDS_CONN)
		{
			// Set server name in windows - title
//			String aseSrv      = AseConnectionFactory.getServer();
//			String aseHostPort = AseConnectionFactory.getHostPortStr();
//			String srvStr      = aseSrv != null ? aseSrv : aseHostPort;
			String srvStr      = _connectedToServerName;

			setSrvInTitle(srvStr);
			ServerInfo srvInfo = new ServerInfo(srvStr, _connectedToProductName, _connectedToProductVersion, _connectedToServerName, _connectedAsUser, _connectedWithUrl, _connectedToSysListeners, _connectedSrvCharset, _connectedSrvSortorder, _connectedClientCharsetId, _connectedClientCharsetName, _connectedClientCharsetDesc);
			_statusBar.setServerInfo(srvInfo);

			if (_connectedToProductName != null && _connectedToProductName.equals(DbUtils.DB_PROD_NAME_SYBASE_ASE))
			{
			}
			else // Probably IQ, SQL Anywhere or some other TDS implementation like OpenServer or jTDS
			{
			}
		}

		if ( _connType == ConnectionDialog.JDBC_CONN)
		{
			setSrvInTitle(_connectedWithUrl);
			ServerInfo srvInfo = new ServerInfo(_connectedWithUrl, _connectedToProductName, _connectedToProductVersion, _connectedToServerName, _connectedAsUser, _connectedWithUrl, _connectedToSysListeners, _connectedSrvCharset, _connectedSrvSortorder, _connectedClientCharsetId, _connectedClientCharsetName, _connectedClientCharsetDesc);
			_statusBar.setServerInfo(srvInfo);
		}

		// view and tools menu might be empty...
		// if so hide the main menu entry as well
		SwingUtils.hideMenuIfNoneIsVisible(_view_m);
		SwingUtils.hideMenuIfNoneIsVisible(_tools_m);
	}

	private void action_disconnect(ActionEvent e)
	{
		saveWinProps();

		_srvVersion                 = 0;
//		_connectedAtTime            = 0;
		_connectedDriverName        = null;
		_connectedDriverVersion     = null;
		_connectedToProductName     = null;
		_connectedToProductVersion  = null;
		_connectedToServerName      = null;
		_connectedAsUser            = null;
		_connectedWithUrl           = null;
		_connectedToSysListeners    = null;
		_connectedSrvCharset        = null;
		_connectedSrvSortorder      = null;
		_connectedClientCharsetId   = null;
		_connectedClientCharsetName = null;
		_connectedClientCharsetDesc = null;

		_dbms_txt.setText(NOT_CONNECTED_STR);

		onDisconnect();

		if (_conn != null)
		{
			try
			{
				setSrvInTitle(null);
				_statusBar.setNotConnected();

				// close the connection "at the end" of the method, if it causes an exception
				Connection tmpConn = _conn;
				_conn = null;
				_connType = -1;

				tmpConn.close();
			}
			catch (SQLException ex)
			{
				_logger.error("Problems closing database connection.", ex);
			}
		}
	}


	private void action_exit(ActionEvent e)
	{
		_jframe.dispatchEvent(new WindowEvent(_jframe, WindowEvent.WINDOW_CLOSING));
	}


	private void action_sqlTrace(ActionEvent e)
	{
		SqlTraceWindow.getInstance().open();
	}


	private void action_openPreferences(ActionEvent e)
	{
		PreferencesDialog pref = new PreferencesDialog(getWindow());
		pref.setVisible(true);
		
		if (pref.wasOkPressed())
		{
			action_dbmsOutput();
		}
	}
	
//	private void action_sqlw(ActionEvent e)
//	{
//		try
//		{
//			// Check that we are connected
//			if ( ! AseConnectionUtils.isConnectionOk(_conn, true, _jframe) )
//			{
//				SwingUtils.showInfoMessage(MainFrame.getInstance(), "Not connected", "Not yet connected to a server.");
//				return;
//			}
//
//			QueryWindow qf = new QueryWindow(_conn, true, WindowType.JFRAME);
//			qf.openTheWindow();
//		}
//		catch (Exception ex)
//		{
//			SwingUtils.showErrorMessage(_jframe, "Error",
//				"Problems open Connection for SQL Query Window\n" + ex, ex);
//		}
//
//	}


//	public void openTheWindow()
//	{
//		Configuration conf = Configuration.getCombinedConfiguration();
//		int width   = conf.getIntProperty(PROPKEY_APP_PREFIX+"size.width",  600);
//		int height  = conf.getIntProperty(PROPKEY_APP_PREFIX+"size.height", 400);
//
//		openTheWindow(width, height);
//	}
	public void openTheWindow()
	{
		Configuration conf = Configuration.getCombinedConfiguration();

		if (_window == null)
			return;

		String screenResStr = SwingUtils.getScreenResulutionAsString();

		int width   = 1170;
		int height  = 800;
		int winPosX = -1;
		int winPosY = -1;
		int divLoc  = -1;

		width   = conf.getIntProperty(PROPKEY_APP_PREFIX+"size.width",         width);
		height  = conf.getIntProperty(PROPKEY_APP_PREFIX+"size.height",        height);
		winPosX = conf.getIntProperty(PROPKEY_APP_PREFIX+"size.pos.x",         winPosX);
		winPosY = conf.getIntProperty(PROPKEY_APP_PREFIX+"size.pos.y",         winPosY);
		divLoc  = conf.getIntProperty(PROPKEY_APP_PREFIX+"splitPane.location", divLoc);

		width   = conf.getIntProperty(PROPKEY_APP_PREFIX+screenResStr+".size.width",         width);
		height  = conf.getIntProperty(PROPKEY_APP_PREFIX+screenResStr+".size.height",        height);
		winPosX = conf.getIntProperty(PROPKEY_APP_PREFIX+screenResStr+".size.pos.x",         winPosX);
		winPosY = conf.getIntProperty(PROPKEY_APP_PREFIX+screenResStr+".size.pos.y",         winPosY);
		divLoc  = conf.getIntProperty(PROPKEY_APP_PREFIX+screenResStr+".splitPane.location", divLoc);

		// If this window is a "cloned" window...
		// Or if other SQL Windows processes is started FIXME: implement this
		// Then move the window slightly
		//FIXME: Jps.java -- to get othet running applications...
		//       This will also cover when you start several windows but from the command line (or not cloning)


//		winPosX=0;
//		winPosY=0;
		openTheWindow(width, height, winPosX, winPosY, divLoc);
	}
	public void openTheWindow(int width, int height, int winPosX, int winPosY, int dividerLocation)
	{
//System.out.println("openTheWindow(width="+width+", height="+height+", winPosX="+winPosX+", winPosY="+winPosY+", dividerLocation="+dividerLocation+")");

		// Set size
		if (width >= 0 && height >= 0)
		{
			_window.setSize(width, height);
		}

		//Center the window
		if (winPosX == -1  && winPosY == -1)
		{
			_logger.debug("Open window in center of screen.");

//			Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
			Rectangle screenSize = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
			Dimension frameSize = _window.getSize();

			// We can't be larger than the screen
			if (frameSize.height > screenSize.height) frameSize.height = screenSize.height;
			if (frameSize.width  > screenSize.width)  frameSize.width  = screenSize.width;

			_window.setLocation((screenSize.width - frameSize.width) / 2,
			        (screenSize.height - frameSize.height) / 2);
		}
		// Set to last known position
		else
		{
			if ( ! SwingUtils.isOutOfScreen(winPosX, winPosY, width, height) )
			{
				_logger.debug("Open main window in last known position.");
				_window.setLocation(winPosX, winPosY);
			}
		}

		// Set the split pane location
		if (dividerLocation >= 0)
		{
			_splitPane.setDividerLocation(dividerLocation);
		}

		// Create a Runnable to set the main visible, and get Swing to invoke.
		SwingUtilities.invokeLater(new Runnable()
		{
			@Override
			public void run()
			{
				DemoApp.this.setVisible(true);
				_logger.debug("openTheWindowAsThread() AFTER... tread is terminating...");
			}
		});
	}


	/** close the db connection */
	private void close()
	{
		if (_conn != null)
		{
			try { _conn.close(); }
			catch (SQLException sqle) {/*ignore*/}
		}
		_conn = null;
	}

	/** Automatically close the connection when we're garbage collected */
	@Override
	protected void finalize()
	{
//		if (_closeConnOnExit)
			close();
	}

//	/**
//	 * Change database context in the ASE
//	 * @param dbname name of the database to change to
//	 * @return true on success
//	 */
//	private boolean useDb(String dbname)
//	{
//		if (dbname == null || (dbname!=null && dbname.trim().equals("")))
//			return false;
//
//		try
//		{
//			_conn.createStatement().execute("use "+dbname);
////			_currentDbName = dbname;
//			return true;
//		}
//		catch(SQLException e)
//		{
//			// Then display the error in a dialog box
//			JOptionPane.showMessageDialog(
////					QueryWindow.this,
//					_window,
//					"Error Number: "+e.getErrorCode()+"\n" + e.getMessage(),
//					"Error", JOptionPane.ERROR_MESSAGE);
//			getCurrentDb();
//			//e.printStackTrace();
//			return false;
//		}
//	}
//
//	/**
//	 * What is current working database
//	 * @return database name, null on failure
//	 */
//	private String getCurrentDb()
//	{
//		try
//		{
//			Statement stmnt   = _conn.createStatement();
//			ResultSet rs      = stmnt.executeQuery("select db_name()");
//			String cwdb = "";
//			while (rs.next())
//			{
//				cwdb = rs.getString(1);
//			}
////			_currentDbName = cwdb;
//
////			String currentSelectedDb = (String) _dbnames_cbx.getSelectedItem();
////			if ( ! cwdb.equals(currentSelectedDb) )
////			{
////				// Note this triggers: code completion for refresh
////				_dbnames_cbx.setSelectedItem(cwdb);
////			}
//
//			return cwdb;
//		}
//		catch(SQLException e)
//		{
//			JOptionPane.showMessageDialog(
////					QueryWindow.this,
//					_window,
//					"Problems getting current Working Database:\n" +
//					"Error Number: "+e.getErrorCode()+"\n" + e.getMessage(),
//					"Error", JOptionPane.ERROR_MESSAGE);
//			return null;
//		}
//	}
//
//	/**
//	 * Get 'all' databases from ASE, and set the ComboBox to Current Working database
//	 */
//	private boolean setDbNames()
//	{
//		try
//		{
//			Statement stmnt   = _conn.createStatement();
//			ResultSet rs      = stmnt.executeQuery("select name, db_name() from master..sysdatabases readpast order by name");
//			DefaultComboBoxModel cbm = new DefaultComboBoxModel();
//			String cwdb = "";
//			while (rs.next())
//			{
//				cbm.addElement(rs.getString(1));
//				cwdb = rs.getString(2);
//			}
////			_currentDbName = cwdb;
//
////			// Check if number of databases has changed
////			int currentDbCount = _dbnames_cbx.getItemCount();
////			if (cbm.getSize() != currentDbCount)
////			{
////				_dbnames_cbx.setModel(cbm);
////			}
//
//			// Check if Current Working database has changed
////			String currentSelectedDb = (String) _dbnames_cbx.getSelectedItem();
////			if ( ! cwdb.equals(currentSelectedDb) )
////			{
////				// Note this triggers: code completion for refresh
////				_dbnames_cbx.setSelectedItem(cwdb);
////			}
//			return true;
//		}
//		catch(SQLException e)
//		{
//			DefaultComboBoxModel cbm = new DefaultComboBoxModel();
//			cbm.addElement("Problems getting dbnames");
////			_dbnames_cbx.setModel(cbm);
//			return false;
//		}
//	}

	private void doDummySelect()
	throws SQLException
	{
		if (_conn == null)
			return;

		String sql = "select 1";
		if      (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_ORACLE)) sql = "select 1 from DUAL";
		else if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_DB2_UX)) sql = "select 1 from SYSIBM.SYSDUMMY1";
		else if (DbUtils.isProductName(_connectedToProductName, DbUtils.DB_PROD_NAME_HANA))   sql = "select 1 from DUMMY";

		try
		{
    		Statement stmnt   = _conn.createStatement();
    		ResultSet rs      = stmnt.executeQuery(sql);
    		while (rs.next())
    		{
    		}
    		rs.close();
    		stmnt.close();
		}
		catch(SQLException ex)
		{
			// Write something in the error log and throw the exception to any caller
			_logger.error("Problem checking if connection is alive, SQL Statement executed '"+sql+"'. Caught: "+ex);
			throw ex;
		}
	}



	private void getServerSideConfiguration()
	{
		try
		{
			SqlStatement stmnt = new SqlStatement(Type.CALLABLE, "{call get_demoapp_property(?, ?, ?)}");

			stmnt.addParam( SqlStatementParam.createInParam ("propname",  Types.VARCHAR, "use_package_variables"));
			stmnt.addParam( SqlStatementParam.createOutParam("int_value", Types.INTEGER));
			stmnt.addParam( SqlStatementParam.createOutParam("str_value", Types.VARCHAR));

			stmnt.execute(this, null);

			String  strValue = (String)  stmnt.getParameterValue("str_value");
			Integer intValue = (Integer) stmnt.getParameterValue("int_value");
			
			_logger.debug("getServerSideConfiguration(use_package_variables): strValue='"+strValue+"', intValue="+intValue);
			
			boolean usePkgVariables = intValue == null ? true: intValue > 0;
			_logger.info("getServerSideConfiguration('use_package_variables') = "+usePkgVariables);
			SqlStatement.setUsePkgVariables( usePkgVariables );
		}
		catch(SQLException ex)
		{
			_logger.warn("Problems getting get_demoapp_property('use_package_variables') Setting use_package_variables to FALSE. Caught: "+ex);
			SqlStatement.setUsePkgVariables(false);
		}
	}

	private void onConnect()
	{
		getServerSideConfiguration();

		_publishersPanel.onConnect();
		_authorsPanel   .onConnect();
		_titles         .onConnect();
		_stores         .onConnect();
		_ordersPanel    .onConnect();
		_statistics     .onConnect();
		
//		_tabPane.setSelectedTitle(TAB_AUTHORS); // this didn't trigger the change listener
//		_authorsPanel   .onTabSelected();
		String selectedTab = _tabPane.getSelectedTitle(false);
		if      (TAB_AUTHORS   .equals(selectedTab)) _authorsPanel   .onTabSelected();
		else if (TAB_TITLES    .equals(selectedTab)) _titles         .onTabSelected();
		else if (TAB_PUBLISHERS.equals(selectedTab)) _publishersPanel.onTabSelected();
		else if (TAB_STORES    .equals(selectedTab)) _stores         .onTabSelected();
		else if (TAB_ORDERS    .equals(selectedTab)) _ordersPanel    .onTabSelected();
		else if (TAB_STATS     .equals(selectedTab)) _statistics     .onTabSelected();
	}

	private void onDisconnect()
	{
		_publishersPanel.onDisconnect();
		_authorsPanel   .onDisconnect();
		_titles         .onDisconnect();
		_stores         .onDisconnect();
		_ordersPanel    .onDisconnect();
		_statistics     .onDisconnect();
	}

	private void onLostConnection()
	{
		action_disconnect(null);
		setComponentVisibility();
		setWatermark();
	}

	/*----------------------------------------------------
	 ** BEGIN: Watermark stuff
	 **---------------------------------------------------
	 */
	private Watermark _watermark = null;

	public void setWatermark()
	{
		if ( _conn == null )
		{
			setWatermarkText(NOT_CONNECTED_STR);
		}
		else if ( _aseConnectionStateInfo != null && ( _aseConnectionStateInfo._tranCount > 0 || _aseConnectionStateInfo.isNonNormalTranState()) )
		{
	    	boolean showExtendedErrorInfo = Configuration.getCombinedConfiguration().getBooleanProperty(DemoApp.PROPKEY_showExtErrInfo, DemoApp.DEFAULT_showExtErrInfo);

	    	String str = null;
			if (showExtendedErrorInfo)
			{
    			if (_aseConnectionStateInfo._tranChained == 1)
    			{
    				if (_aseConnectionStateInfo._lockCount > 0)
    					str = "You are in CHAINED MODE (AutoCommit=false)\n"
    						+ "And you are holding "+_aseConnectionStateInfo._lockCount+" locks in the server\n"
    						+ "Don't forget to commit or rollback!";
    			}
    			else
    			{
        			if (_aseConnectionStateInfo.isTranStateUsed())
        				str = _aseConnectionStateInfo.getTranStateDescription() + "\n@@trancount = " + _aseConnectionStateInfo._tranCount + ", @@tranchained = " + _aseConnectionStateInfo._tranChained;
        			else
        				str = "@@trancount = " + _aseConnectionStateInfo._tranCount + ", @@tranchained = " + _aseConnectionStateInfo._tranChained;
    			}
			}

			setWatermarkText(str);
		}
//		else if ( _aseConnectionStateInfo != null && ( _aseConnectionStateInfo._tranCount > 0 || _aseConnectionStateInfo.isNonNormalTranState()) )
//		{
//			String str;
//			if (_aseConnectionStateInfo.isTranStateUsed())
//				str = _aseConnectionStateInfo.getTranStateDescription() + "\n@@trancount = " + _aseConnectionStateInfo._tranCount;
//			else
//				str = "@@trancount = " + _aseConnectionStateInfo._tranCount;
//
//			setWatermarkText(str);
//		}
		else
		{
			setWatermarkText(null);
		}
	}

	public void setWatermarkText(String str)
	{
		if (_watermark != null)
			_watermark.setWatermarkText(str);
	}

	public void setWatermarkAnchor(JComponent comp)
	{
		_watermark = new Watermark(comp, "");
	}

	private class Watermark extends AbstractComponentDecorator
	{
		public Watermark(JComponent target, String text)
		{
			super(target);
			if ( text == null )
				text = "";
			_textSave = text;
			_textBr   = text.split("\n");
		}

		private String[]	_textBr			= null; // Break Lines by '\n'
		private String      _textSave       = null; // Save last text so we don't need to do repaint if no changes.
		private Graphics2D	g				= null;
		private Rectangle	r				= null;

		@Override
		public void paint(Graphics graphics)
		{
			if ( _textBr == null || _textBr != null && _textBr.length < 0 )
				return;

			r = getDecorationBounds();
			g = (Graphics2D) graphics;
			g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			Font f = g.getFont();
//			g.setFont(f.deriveFont(Font.BOLD, f.getSize() * 2.0f));
			g.setFont(f.deriveFont(Font.BOLD, f.getSize() * 1.5f));
			g.setColor(new Color(128, 128, 128, 128));

			FontMetrics fm = g.getFontMetrics();
			int maxStrWidth = 0;
			int maxStrHeight = fm.getHeight();

			// get max with for all of the lines
			for (int i = 0; i < _textBr.length; i++)
			{
				int CurLineStrWidth = fm.stringWidth(_textBr[i]);
				maxStrWidth = Math.max(maxStrWidth, CurLineStrWidth);
			}
			int xPos = (r.width - maxStrWidth) / 2;
			int yPos = (int) (r.height - ((r.height - fm.getHeight()) / 2) * 1.3);

			// Print all the lines
			for (int i = 0; i < _textBr.length; i++)
			{
				g.drawString(_textBr[i], xPos, (yPos + (maxStrHeight * i)));
			}
		}

		public void setWatermarkText(String text)
		{
			if ( text == null )
				text = "";

			// If text has NOT changed, no need to continue
			if (text.equals(_textSave))
				return;

			_textSave = text;

			_textBr = text.split("\n");
			_logger.debug("setWatermarkText: to '" + text + "'.");

			repaint();
		}
	}
	/*---------------------------------------------------
	 ** END: Watermark stuff
	 **---------------------------------------------------
	 */




	/**
	 * Print command line options.
	 * @param options
	 */
	private static void printHelp(Options options, String errorStr)
	{
//		PrintWriter pw = new PrintWriter(System.out);
//
//		if (errorStr != null)
//		{
//			pw.println();
//			pw.println(errorStr);
//			pw.println();
//		}
//
//		pw.println("usage: sqlw [-U <user>] [-P <passwd>] [-S <server>] [-D <dbname>]");
//		pw.println("            [-u <jdbcUrl>] [-d <jdbcDriver>]");
//		pw.println("            [-q <sqlStatement>] [-h] [-v] [-x] <debugOptions> ");
//		pw.println("  ");
//		pw.println("options:");
//		pw.println("  -h,--help                 Usage information.");
//		pw.println("  -v,--version              Display "+Version.getAppName()+" and JVM Version.");
//		pw.println("  -x,--debug <dbg1,dbg2>    Debug options: a comma separated string");
//		pw.println("                            To get available option, do -x list");
//		pw.println("  ");
//		pw.println("  -U,--user <user>          Username when connecting to server.");
//		pw.println("  -P,--passwd <passwd>      Password when connecting to server. null=noPasswd");
//		pw.println("  -S,--server <server>      Server to connect to.");
//		pw.println("  -D,--dbname <dbname>      Database to use when connecting");
//		pw.println("  -u,--jdbcUrl <url>        JDBC URL. if not a sybase/TDS server");
//		pw.println("  -d,--jdbcDriver <driver>  JDBC Driver. if not a sybase/TDS server");
//		pw.println("                            If the JDBC drivers is registered with the ");
//		pw.println("                            DriverManager, this is NOT needed");
//		pw.println("  -p,--connProfile <name>   Connect using an existing Connection Profile");
//		pw.println("  -q,--query <sqlStatement> SQL Statement to execute");
//		pw.println("  -i,--inputFile <filename> Input File to open in editor");
//		pw.println("");
//		pw.flush();
	}

	/**
	 * Build the options com.asetune.parser. Has to be synchronized because of the way
	 * Options are constructed.
	 *
	 * @return an options
	 */
	private static synchronized Options buildCommandLineOptions()
	{
		Options options = new Options();

//		// create the Options
//		options.addOption( "h", "help",        false, "Usage information." );
//		options.addOption( "v", "version",     false, "Display "+Version.getAppName()+" and JVM Version." );
//		options.addOption( "x", "debug",       true,  "Debug options: a comma separated string dbg1,dbg2,dbg3" );
//
//		options.addOption( "U", "user",        true, "Username when connecting to server." );
//		options.addOption( "P", "passwd",      true, "Password when connecting to server. (null=noPasswd)" );
//		options.addOption( "S", "server",      true, "Server to connect to." );
//		options.addOption( "D", "dbname",      true, "Database use when connecting" );
//		options.addOption( "u", "jdbcUrl",     true, "JDBC URL. if not a sybase/TDS server" );
//		options.addOption( "d", "jdbcDriver",  true, "JDBC Driver. if not a sybase/TDS server. If the JDBC drivers is registered with the DriverManager, this is NOT needed." );
//		options.addOption( "p", "connProfile", true, "Connect using an existing Connection Profile");
//		options.addOption( "q", "sqlStatement",true, "SQL statement to execute" );
//		options.addOption( "i", "inputFile",   true, "Input File to open in editor" );

		return options;
	}


	//---------------------------------------------------
	// Command Line Parsing
	//---------------------------------------------------
	private static CommandLine parseCommandLine(String[] args, Options options)
	throws ParseException
	{
		// create the command line
		CommandLineParser parser = new PosixParser();

		// parse the command line arguments
		CommandLine cmd = parser.parse( options, args );

		// Validate any mandatory options or dependencies of switches


		if (_logger.isDebugEnabled())
		{
			for (@SuppressWarnings("unchecked") Iterator<Option> it=cmd.iterator(); it.hasNext();)
			{
				Option opt = it.next();
				_logger.debug("parseCommandLine: swith='"+opt.getOpt()+"', value='"+opt.getValue()+"'.");
			}
		}

		return cmd;
	}

//	private static void jConnectEnableLogging()
//	{
////		java.util.logging.Logger LOG = java.util.logging.Logger.getLogger("com.sybase.jdbc4.jdbc");
//		java.util.logging.Logger LOG = java.util.logging.Logger.getLogger("com.sybase.jdbc4.jdbc.SybConnection");
//
//		// To log class-specific log message, provide complete class name, for example:
//		//Logger.getLogger("com.sybase.jdbc4.jdbc.SybConnection");
//		//Get handle as per user's requirement
//		Handler handler = new ConsoleHandler();
//
//		//Set logging level
////		handler.setLevel(java.util.logging.Level.ALL);
//		handler.setLevel(java.util.logging.Level.FINEST);
//
//		//Added user specific handler to logger object
//		LOG.addHandler(handler);
//
//		//Set logging level
////		LOG.setLevel(java.util.logging.Level.ALL);
//		LOG.setLevel(java.util.logging.Level.FINEST);
//	}


	//---------------------------------------------------
	// MAIN
	//---------------------------------------------------
	public static void main(String[] args)
	{
//		jConnectEnableLogging();

		Options options = buildCommandLineOptions();
		try
		{
			CommandLine cmd = parseCommandLine(args, options);

			//-------------------------------
			// HELP
			//-------------------------------
			if ( cmd.hasOption("help") )
			{
				printHelp(options, "The option '--help' was passed.");
			}
			//-------------------------------
			// VERSION
			//-------------------------------
			else if ( cmd.hasOption("version") )
			{
				System.out.println();
				System.out.println(Version.getAppName()+" Version: " + Version.getVersionStr() + " JVM: " + System.getProperty("java.version"));
				System.out.println();
			}
			//-------------------------------
			// Check for correct number of cmd line parameters
			//-------------------------------
			else if ( cmd.getArgs() != null && cmd.getArgs().length > 0 )
			{
				String error = "Unknown options: " + StringUtil.toCommaStr(cmd.getArgs());
				printHelp(options, error);
			}
			//-------------------------------
			// Start App, GUI/NOGUI will be determined later on.
			//-------------------------------
			else
			{
				new DemoApp(cmd);
			}
		}
		catch (ParseException pe)
		{
			String error = "Error: " + pe.getMessage();
			printHelp(options, error);
		}
		catch (NormalExitException e)
		{
			// This was probably throws when checking command line parameters
			// do normal exit
		}
		catch (Exception e)
		{
			System.out.println();
			System.out.println("Error: " + e.getMessage());
			System.out.println();
			System.out.println("Printing a stacktrace, where the error occurred.");
			System.out.println("--------------------------------------------------------------------");
			e.printStackTrace();
			System.out.println("--------------------------------------------------------------------");
		}
	}
}


