 /*
 * Copyright (C) 17-sept.-2003  Jean-Yves Beaujean 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,  59
 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * 
 */
package jxtray.swing;

import javax.swing.*;

import java.awt.*;
import java.awt.event.*;

import java.sql.*;

import java.util.Vector;

import jxtray.CustomFileFilter;
import jxtray.util.FileUtilities;
import jxtray.Messages;
import jxtray.Jxtray;
import jxtray.SQLHistoryEntry;
import jxtray.io.WriterContext;

import jxtray.table.QueryTable;


import java.util.StringTokenizer;

import jxtray.connection.JxtConnection;


public class JxtSQLPanel extends JPanel implements ItemListener, ActionListener, KeyListener, Runnable
{
	
	private JPanel pNorth;
	private JSplitPane splitPane;
	
	private JxtEditorPane editorPane = new JxtEditorPane(new Font(Jxtray.getProperty("sqleditor.fontname"),0,Integer.parseInt(Jxtray.getProperty("sqleditor.fontsize"))));
	private JxtButton bExecute = new JxtButton(new ImageIcon(getClass().getResource("/images/exec.png")),Jxtray.getLang("action.execute"),this,Jxtray.getLang("action.execute"));
	private JxtButton bSaveQuery = new JxtButton(new ImageIcon(getClass().getResource("/images/save_as.png")),Jxtray.getLang("action.savequery"),this,Jxtray.getLang("action.savequery"));
	private JxtButton bSaveOutput = new JxtButton(new ImageIcon(getClass().getResource("/images/save.png")),Jxtray.getLang("action.saveoutput"),this,Jxtray.getLang("action.saveoutput"));
	private JxtButton bEmptyTable = new JxtButton(new ImageIcon(getClass().getResource("/images/clear.png")),Jxtray.getLang("action.emptytable"),this,Jxtray.getLang("action.emptytable"));
	
	
	private JxtComboBox comboCatalog = new JxtComboBox();
	private JxtComboBox comboSchema = new JxtComboBox();
	private JxtComboBox comboTable = new JxtComboBox();
	
	private JxtJLabel lQueryTime = new JxtJLabel("");
	
	private JxtConnection connection;
	private Thread thread;
	private QueryTable queryTable=null;
	
	public JxtSQLPanel(JxtConnection con, String catalog[], String schema[])
	{
		super(new BorderLayout(),true );
		
		connection = con;
		
		pNorth = new JPanel();
		splitPane = new JSplitPane();
		splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
		editorPane.addKeyListener(this);
		

		splitPane.setLeftComponent(new JScrollPane(editorPane));
		splitPane.setRightComponent(new JScrollPane());
		splitPane.setDividerLocation(200);
		
		bSaveOutput.setEnabled(false);
			
		
		if ( catalog.length > 0 )
			comboCatalog = new JxtComboBox(catalog);
		else
		{
			comboCatalog = new JxtComboBox();
			comboCatalog.setVisible(false);
		}
			
		if ( schema.length > 0 )
			comboSchema = new JxtComboBox(schema);
		else
		{
			comboSchema = new JxtComboBox();
			comboSchema.setVisible(false);
		}	
		
		comboTable.setEditable(true);
		pNorth.add(comboCatalog);
		pNorth.add(comboSchema);
		pNorth.add(comboTable);
		pNorth.add(bExecute);
		pNorth.add(bSaveQuery);
		pNorth.add(bSaveOutput);
		pNorth.add(lQueryTime);
		pNorth.add(bEmptyTable);
		
		
		this.setName("SQL");
		
		comboTable.addItemListener(this);
		try
		{
				init();
		}
		catch( Exception e )
		{
			Messages.error("JxtSQLPanel.init() : "+ e );
		}
		comboCatalog.addItemListener(this);
		comboSchema.addItemListener(this);
		
		this.add(pNorth,BorderLayout.NORTH);
		this.add(splitPane,BorderLayout.CENTER);
			
	}
	
	public void init() throws Exception
	{
		Vector v = connection.getTables((String)comboCatalog.getSelectedItem(),(String) comboSchema.getSelectedItem());
		for ( int i=0; i<v.size();i++)
			comboTable.addItem(v.elementAt(i));
	}
	
	public void itemStateChanged( ItemEvent e )
	{
			this.setCursor(new Cursor(Cursor.WAIT_CURSOR));
			if ( e.getSource().equals(comboCatalog) || e.getSource().equals(comboSchema) )
			{
				try
				{
					comboTable.removeAllItems();
					Vector v = connection.getTables((String)comboCatalog.getSelectedItem(),(String) comboSchema.getSelectedItem());
					for ( int i=0; i<v.size();i++)
						comboTable.addItem(v.elementAt(i));
				}
				catch ( Exception ex )
				{
					Messages.error("JxtStructurePanel.itemStateChanged() : " + ex);
				}
			}
			
			else if ( e.getSource().equals(comboTable) )
			{
				try 
				{	
					if ( connection.getMetaData().supportsCatalogsInDataManipulation() )
						editorPane.setText("select * from "+comboCatalog.getSelectedItem()+"."+ comboTable.getSelectedItem());
					else if ( connection.getMetaData().supportsSchemasInDataManipulation() )
						editorPane.setText("select * from "+comboSchema.getSelectedItem()+"."+ comboTable.getSelectedItem());
					else
						editorPane.setText("select * from "+ comboTable.getSelectedItem());		
				}
				catch ( Exception ex )	
				{ 
					Messages.error("JxtSQLPanel.itemStateChanged() :"+ e);	
				}
			}
			this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
	}
	
	public void actionPerformed( ActionEvent e )
	{
			if ( e.getActionCommand().equals(Jxtray.getLang("action.execute")) )
			{
				thread = new Thread(this);
				thread.start();
				
			}
			else if ( e.getActionCommand().equals(Jxtray.getLang("action.savequery")) )
			{
				
				
				String name = Messages.chooseFile(new CustomFileFilter(Jxtray.getLang("file.sql"),FileUtilities.SQL));
				try
				{
					if ( name != null )
					{
						this.setCursor(new Cursor(Cursor.WAIT_CURSOR));
						WriterContext writeContext = new WriterContext(name);
						writeContext.open();
						writeContext.write(editorPane.getText());
						writeContext.close();
						Messages.info(Jxtray.getLang("output.saved"));
						this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
					}
				}
				catch ( Exception ex )
				{
					Messages.error("JxtSQLPanel.actionPerformed() : save : " +ex );
					this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
				}
				
			}
			else if ( e.getActionCommand().equals(Jxtray.getLang("action.saveoutput")) )
			{
				
				CustomFileFilter saveFilter[] = {new CustomFileFilter(Jxtray.getLang("file.xul"),FileUtilities.XUL),new CustomFileFilter(Jxtray.getLang("file.csv"),FileUtilities.CSV)};
				String name = Messages.chooseFile(saveFilter);
				
				try
				{
					
					if ( name != null )
					{
						this.setCursor(new Cursor(Cursor.WAIT_CURSOR));
						WriterContext writeContext = new WriterContext(name.toString());
						writeContext.open();		
						int tcol = queryTable.getColumnCount();
						int trow =  queryTable.getRowCount();
						
						String ext = name.substring(name.lastIndexOf(".")+1,name.length()).toLowerCase();
						if ( ext.equals("csv"))
						{
								
							for ( int i=0;i <trow; i++)
							{
								// write header ( col names )
								if ( i == 0)
								{
									for ( int j=0;j<tcol;j++)
									{
										writeContext.write(queryTable.getColumnName(j)+Jxtray.getProperty("csv.separator"));
									}
									writeContext.write("\n");
								}
								for ( int j=0;j<tcol;j++)
								{
									writeContext.write(queryTable.getValueAt(i,j)+Jxtray.getProperty("csv.separator"));
								}
								writeContext.write("\n");
							}
						}
						else if ( ext.equals("xul"))
						{
							writeContext.write("<?xml version='1.0'  encoding='ISO-8859-1'?>\n");
							writeContext.write("<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'>\n");
							writeContext.write("<tree id='jxtray-query-result' flex='1'>\n");
							for ( int i=0;i <trow; i++)
							{
								// write header ( col names )
								if ( i == 0)
								{
									writeContext.write("\t<treecols>\n");
									for ( int j=0;j<tcol;j++)
									{
								            writeContext.write("\t\t<treecol id=\"col-"+queryTable.getColumnName(j)+"\" label=\""+queryTable.getColumnName(j)+"\" flex=\"1\" />\n");
									}
									
									writeContext.write("\t</treecols>\n\t<treechildren flex='1'>\n");
									
								}
	
								 writeContext.write("\t\t<treeitem>\t\t<treerow>\n");
								 for ( int j=0;j<tcol;j++)
								{
									writeContext.write("\t\t\t<treecell label=\""+queryTable.getValueAt(i,j)+"\"/>\n");
								}
								 writeContext.write("\t\t</treerow>\n\t\t</treeitem>\n");
								
							}
							
							writeContext.write("\t</treechildren>\n\t</tree>\n");
							
							writeContext.write("</window>\n");
									   

	
									  
									
						}
						writeContext.close();
						Messages.info(Jxtray.getLang("output.saved"));
						this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
						
					}
				}
				catch ( Exception ex )
				{
					Messages.error("JxtSQLPanel.actionPerformed() : save result : " +ex );
					this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
				}
			}
			else if ( e.getActionCommand().equals(Jxtray.getLang("action.emptytable")) )
			{
				if ( Messages.question(Jxtray.getLang("action.emptytable") +" ?") == JOptionPane.YES_OPTION)
				{
						StringBuffer result = new StringBuffer();
						try
						{
								bSaveOutput.setEnabled(false);
								Statement stmt = connection.getConnection().createStatement();
								String query = "delete from " ;
								try 
								{	
									if ( connection.getMetaData().supportsCatalogsInDataManipulation() )
											query += comboCatalog.getSelectedItem()+"."+ comboTable.getSelectedItem();
									else if ( connection.getMetaData().supportsSchemasInDataManipulation() )
											query += comboSchema.getSelectedItem()+"."+ comboTable.getSelectedItem();
									else
											query += comboTable.getSelectedItem();		
							}
							catch ( Exception ex )	
							{ 
									Messages.error("JxtSQLPanel.emptyTable :"+ e);	
							}
							double t1 = System.currentTimeMillis();
							stmt.executeUpdate(query);
							double diff = System.currentTimeMillis()-t1;
							lQueryTime.setText(queryTable.getRowCount()+" row(s) - time :"+ (diff/1000)+ "sec.");
							stmt.close();
							
						}
						catch ( Exception ex )
						{
								Messages.error("JxtSQLPanel.emptyTable :"+ ex);	
							  lQueryTime.setForeground(Color.red);
								lQueryTime.setText("ERROR");
								
						}
				}
				
			}
		
	}
	
	public void keyTyped( KeyEvent e )
	{
	}
	
	public void keyPressed( KeyEvent e )
	{
			if ( e.getKeyCode() == 10 && e.isControlDown())
			{
					thread = new Thread(this);
					thread.start();
			}
			
	}
	
	public void keyReleased( KeyEvent e )
	{
	}

	private void execute() throws Exception
	{
		this.setCursor(new Cursor(Cursor.WAIT_CURSOR));
		double t1 = System.currentTimeMillis();
		
		Statement stmt = connection.getConnection().createStatement();
		StringTokenizer strTokenizer = new StringTokenizer(editorPane.getText(),";");
		
		Vector vQueries = new Vector();
		int cptQuery=0;
		String query;
		boolean resType=false;
		boolean error = false;
		StringBuffer result = new StringBuffer();
		JxtEditorPane editor = new JxtEditorPane();
		double diff = 0;
		
				
		while ( strTokenizer.hasMoreElements())
		{
				query = (String) strTokenizer.nextElement();
				try
				{
					if (query.trim().length() > 0 )
					{
						resType = stmt.execute(query);
						Jxtray.getSQLHistoryCache().put(query,new SQLHistoryEntry(query, (new java.util.Date()).toLocaleString(), true));
						editor.setForeground(new Color (18, 135, 3));
					}
				}
				catch ( Exception e)
				{
					bSaveOutput.setEnabled(false);
					Jxtray.getSQLHistoryCache().put(query,new SQLHistoryEntry(query, (new java.util.Date()).toLocaleString(), false));
					editor.setForeground(Color.red);
					result.append(query+"\nERROR : ");
					result.append(e.getMessage()+"\n");
					lQueryTime.setForeground(Color.red);
					lQueryTime.setText("ERROR");
					resType = false;
					error = true;
					break; 
				}
				
				lQueryTime.setForeground(Color.blue);
				if ( resType ) // return a ResultSet
				{
					bSaveOutput.setEnabled(true);
					ResultSet res = stmt.getResultSet();
					queryTable = new QueryTable(res);	
					diff = System.currentTimeMillis()-t1;
					lQueryTime.setText(queryTable.getRowCount()+" row(s) - time :"+ (diff/1000)+ "sec.");
				}
				else // update query
				{
					bSaveOutput.setEnabled(false);
					String time = "time :"+ (diff/1000)+ "sec.";
					lQueryTime.setText(time);
					result.append(query+"\nSUCCESS :"+time);
					result.append("\t"+stmt.getUpdateCount()+" row(s) affected.\n");
				}
				cptQuery++;
		}
		
		
		//splitPane.removeAll();
		int oldDividerLocation = splitPane.getDividerLocation();
		splitPane.setLeftComponent(new JScrollPane(editorPane));
		JScrollPane scrollPane=null;		
		if ( resType)
		{
			scrollPane = new JScrollPane(queryTable);
		}
		else
		{
			editor.setText(result.toString());
			editor.setEditable(false);
			scrollPane = new JScrollPane(editor);
		}
		if ( "TRUE".equals(Jxtray.getProperty("sqleditor.erasequeryafterxecute").toUpperCase()) && !error )
		{
				editorPane.setText("");
		}

		splitPane.setRightComponent(scrollPane);
		splitPane.setDividerLocation(oldDividerLocation);

		stmt.close();
		editorPane.requestFocus();
		this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
	}
	
	public void run()
	{
			try
			{
				this.setCursor(new Cursor(Cursor.WAIT_CURSOR));
				execute();
			}
			catch ( Exception e )
			{
				Messages.error("JxtSQLPanel.execute() : "+ e );
			}
			this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
	}
	
}


