package util;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FileDialog;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import oracle.jdbc.driver.OracleStatement;
/*
import util.DBTableModel;
import util.CloseWindow;
import util.LoginDialog;
import util.SessionBuffer;
import util.TableSorter;
 */

/**
 *  Ein einfacher SQL-Client zum Ausführen von Statements auf einer
 *  Oracle-Datenbankverbindung.
 *
 * @author     T
 * @created    15. Juni 2001
 */
public class MiniClient extends JFrame implements ActionListener, Printable, ChangeListener
{
   
   private SessionBuffer session = SessionBuffer.getInstance( true );
   private JTextArea input;
   private JTextField output = new JTextField( "DB-Verbindung: " + session.sServiceName + ":" + session.dbHost + " aufgebaut.", 70 );
   
   private JScrollPane scrollPane1;
   private JScrollPane scrollPane2;
   
   private JButton runall = new JButton( "F8 Run" );
   private JButton runsel = new JButton( "F9 Run Selection" );
   private JButton exit = new JButton( "F10 Exit" );
   private JButton prnt = new JButton( "F11 Print" );
   
   private JMenuBar menuBar = new JMenuBar();
   
   private JCheckBox printTable = new JCheckBox( "Use System.Out", false );
   private JTabbedPane tabs = new JTabbedPane();
   
   private DBTableModel dbTableModel;
   private TableSorter sorter;
   private final JTable table;
   private static boolean singleStart = false;
   
   private static OracleStatement generalStmt;
   private static ResultSet rset = null;
   
   private Vector inputAreas = new Vector();
   
   // Singleton
   private static MiniClient miniClient = null;
   
   KeyAdapter keyAdapter;
   
   
   /**
    *  Geschützter Konstruktor für das MiniClient Objekt.
    */
   protected MiniClient()
   {
      this.setTitle( "SQL - Mini - Client ( " + SessionBuffer.defaultUser + "@" + SessionBuffer.sServiceName + " )" );
      this.setSize( 900, 600 );
      this.addWindowListener( new CloseWindow( this ) );
      
      Container content = this.getContentPane();
      
      content.setLayout( new BorderLayout() );
      
      input = new JTextArea();
      inputAreas.add( input );
      
      input.setFont( new Font( "SansSerif", Font.PLAIN, 16 ) );
      input.setEditable( true );
      
      output.setFont( new Font( "Serif", Font.BOLD, 13 ) );
      output.setBackground( Color.white );
      output.setForeground( Color.red );
      output.setEditable( false );
      
      JPanel panel = new JPanel();
      
      panel.setLayout( new FlowLayout( FlowLayout.LEFT ) );
      panel.add( runall );
      panel.add( runsel );
      panel.add( exit );
      panel.add( printTable );
      
      String[] empty =
      {"EMPTY"};
      
      dbTableModel = new DBTableModel();
      dbTableModel.setColumnNames( empty );
      sorter = new TableSorter( dbTableModel );
      table = new JTable( sorter );
      sorter.addMouseListenerToHeaderInTable( table );
      scrollPane1 = new JScrollPane( input );
      scrollPane2 = new JScrollPane( table );
      
      tabs.addTab( "T", scrollPane1 );
      
      JSplitPane splitPane = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
      
      splitPane.setDividerSize( 2 );
      splitPane.setContinuousLayout( true );
      splitPane.setTopComponent( tabs );
      splitPane.setBottomComponent( scrollPane2 );
      splitPane.setDividerLocation( 120 );
      
      keyAdapter =
      new KeyAdapter()
      {
         public void keyPressed( KeyEvent e )
         {
            if ( e.getKeyCode() == KeyEvent.VK_F10 )
            {
               if ( singleStart )
               {
                  session.closeDB();
                  System.exit( 0 );
               } else
               {
                  miniClient.dispose();
               }
            } else if ( e.getKeyCode() == KeyEvent.VK_F8 )
            {
               executeAll();
            } else if ( e.getKeyCode() == KeyEvent.VK_F9 )
            {
               executeSel();
            } else if ( e.getKeyCode() == KeyEvent.VK_F2 )
            {
               input = new JTextArea();
               input.setFont( new Font( "SansSerif", Font.PLAIN, 16 ) );
               input.setEditable( true );
               input.addKeyListener( keyAdapter );
               inputAreas.add( input );
               scrollPane1 = new JScrollPane( input );
               tabs.addTab( "<neu>", scrollPane1 );
               tabs.setSelectedIndex( tabs.getTabCount() - 1 );
            } else if ( e.getKeyCode() == KeyEvent.VK_F3 )
            {
               FileDialog fileDialog = new FileDialog( miniClient, "Load Script", FileDialog.LOAD );
               
               fileDialog.setVisible( true );
               if ( fileDialog.getFile() == null )
               {
                  return;
               }
               String sFileName = fileDialog.getDirectory() + fileDialog.getFile();
               
               input = new JTextArea( readFile( sFileName ) );
               inputAreas.add( input );
               scrollPane1 = new JScrollPane( input );
               tabs.addTab( fileDialog.getFile(), scrollPane1 );
            } else if ( e.getKeyCode() == KeyEvent.VK_F4 )
            {
               FileDialog fileDialog = new FileDialog( miniClient, "Save Script", FileDialog.SAVE );
               
               fileDialog.setVisible( true );
               if ( fileDialog.getFile() == null )
               {
                  return;
               }
               String sFileName = fileDialog.getDirectory() + fileDialog.getFile();
               
               writeFile( sFileName );
               tabs.setTitleAt( tabs.getSelectedIndex(), fileDialog.getFile() );
            } else if ( e.getKeyCode() == KeyEvent.VK_F5 && singleStart )
            {
               login();
            /*
          } else if ( e.getKeyCode() == KeyEvent.VK_F11 ) {
            //printTable();
             *
             */
            } else if ( e.getKeyCode() == KeyEvent.VK_F6 )
            {
               if ( tabs.getTabCount() > 1 )
               {
                  int i = tabs.getSelectedIndex();
                  
                  inputAreas.removeElementAt( i );
                  tabs.removeTabAt( i );
               } else
               {
                  input.setText( "" );
                  tabs.setTitleAt( 0, "<new script>" );
               }
            }
         }
      };
      
      input.addKeyListener( keyAdapter );
      table.addKeyListener( keyAdapter );
      output.addKeyListener( keyAdapter );
      
      content.add( output, BorderLayout.NORTH );
      content.add( splitPane, BorderLayout.CENTER );
      content.add( panel, BorderLayout.SOUTH );
      
      // MenüLeiste
      setJMenuBar( menuBar );
      
      // Menü Datei
      JMenu mFile = new JMenu( "Datei" );
      
      menuBar.add( mFile );
      
      JMenuItem miClear = addMenuItem( mFile, "F2 New" );
      JMenuItem miOpen = addMenuItem( mFile, "F3 Open Script" );
      JMenuItem miSave = addMenuItem( mFile, "F4 Save Script" );
      
      mFile.addSeparator();
      
      JMenuItem miLogin = addMenuItem( mFile, "F5 Login" );
      
      mFile.addSeparator();
      
      JMenuItem miTerms = addMenuItem( mFile, "F6 Close" );
      
      mFile.addSeparator();
      
      JMenuItem miExit = addMenuItem( mFile, "F10 Exit" );
      
      // Hilfe
      //JMenu mHelp = new JMenu( "Help" );
      //menuBar.add( mHelp );
      //JMenuItem miHelp = addMenuItem( mHelp, "What?" );
      
      runall.addActionListener( this );
      runsel.addActionListener( this );
      exit.addActionListener( this );
      prnt.addActionListener( this );
      miOpen.addActionListener( this );
      miSave.addActionListener( this );
      miClear.addActionListener( this );
      miExit.addActionListener( this );
      miLogin.addActionListener( this );
      miTerms.addActionListener( this );
      tabs.addChangeListener( this );
      
      generalStmt = SessionBuffer.getStatement();
      
      if ( !singleStart )
      {
         miLogin.setEnabled( false );
      }
      
      if ( !session.dbConnect )
      {
         output.setText( "DB Conncetion: <none>" );
      }
   }
   
   
   /**
    *  Überwacht die Buttons und Menüleiste.
    *
    * @param  e  Das Event.
    */
   public void actionPerformed( ActionEvent e )
   {
      String cmd = e.getActionCommand();
      
      if ( cmd.equals( "F10 Exit" ) )
      {
         if ( singleStart )
         {
            session.closeDB();
            System.exit( 0 );
         } else
         {
            miniClient.dispose();
         }
      } else if ( cmd.equals( "F8 Run" ) )
      {
         executeAll();
      } else if ( cmd.equals( "F9 Run Selection" ) )
      {
         executeSel();
      } else if ( cmd.equals( "F2 New" ) )
      {
         input = new JTextArea();
         input.setFont( new Font( "SansSerif", Font.PLAIN, 16 ) );
         input.setEditable( true );
         input.addKeyListener( keyAdapter );
         inputAreas.add( input );
         scrollPane1 = new JScrollPane( input );
         tabs.addTab( "<neu>", scrollPane1 );
         tabs.setSelectedIndex( tabs.getTabCount() - 1 );
      } else if ( cmd.equals( "F3 Öffnen" ) )
      {
         FileDialog fileDialog = new FileDialog( this, "Open Script", FileDialog.LOAD );
         
         fileDialog.setVisible( true );
         if ( fileDialog.getFile() == null )
         {
            return;
         }
         String sFileName = fileDialog.getDirectory() + fileDialog.getFile();
         
         input = new JTextArea( readFile( sFileName ) );
         input.setFont( new Font( "SansSerif", Font.PLAIN, 16 ) );
         input.setEditable( true );
         input.addKeyListener( keyAdapter );
         inputAreas.add( input );
         scrollPane1 = new JScrollPane( input );
         tabs.addTab( fileDialog.getFile(), scrollPane1 );
         tabs.setSelectedIndex( tabs.getTabCount() - 1 );
      } else if ( cmd.equals( "F4 Speichern" ) )
      {
         FileDialog fileDialog = new FileDialog( this, "Save Script", FileDialog.SAVE );
         
         fileDialog.setVisible( true );
         if ( fileDialog.getFile() == null )
         {
            return;
         }
         String sFileName = fileDialog.getDirectory() + fileDialog.getFile();
         
         writeFile( sFileName );
         tabs.setTitleAt( tabs.getSelectedIndex(), fileDialog.getFile() );
      } else if ( cmd.equals( "F5 Login" ) )
      {
         login();
      } else if ( cmd.equals( "F6 Close" ) )
      {
         if ( tabs.getTabCount() > 1 )
         {
            int i = tabs.getSelectedIndex();
            
            inputAreas.removeElementAt( i );
            tabs.removeTabAt( i );
         } else
         {
            input.setText( "" );
            tabs.setTitleAt( 0, "<new script>" );
         }
         
      } /*else if ( cmd.equals( "F11 Print" ) ) {
      //printTable();
    }*/
   }
   
   
   /**
    *  Start-Methode für JEdit-Plugin.
    */
   public static void start()
   {
      singleStart = true;
      
      MiniClient mc = MiniClient.getInstance();
      
      mc.setVisible( true );
   }
   
   
   public void stateChanged( ChangeEvent e )
   {
      input = (JTextArea) inputAreas.elementAt( tabs.getSelectedIndex() );
   }
   
   
   private JMenuItem addMenuItem( JMenu target, String text )
   {
      JMenuItem mi = new JMenuItem( text );
      
      target.add( mi );
      return mi;
   }
   
   
   private void executeAll()
   {
      output.setText( "" );
      
      StringTokenizer tokenizer = new StringTokenizer( input.getText(), ";", false );
      
      while ( tokenizer.hasMoreTokens() )
      {
         String query = tokenizer.nextToken();
         
         query = query.trim();
         session.log( "\n" + query, 5 );
         if ( !query.equals( "" ) )
         {
            executeQuery( query );
         }
      }
   }
   
   
   private void executeSel()
   {
      output.setText( "" );
      
      String text = input.getSelectedText();
      
      if ( text == null || text.equals( "" ) )
      {
         return;
      }
      String query;
      
      if ( text.indexOf( ";" ) > 0 )
      {
         query = text.substring( 0, text.indexOf( ";" ) );
      } else
      {
         query = text;
      }
      executeQuery( query );
   }
   
   
   private String readFile( String file )
   {
      String text = "";
      String readLine;
      
      try
      {
         BufferedReader reader = new BufferedReader( new FileReader( file ) );
         
         while ( ( readLine = reader.readLine() ) != null )
         {
            text += readLine + "\n";
         }
         reader.close();
      }
      catch ( Exception e )
      {
         session.log(e);
      }
      return text;
   }
   
   
   private void writeFile( String file )
   {
      String text = input.getText();
      
      try
      {
         BufferedWriter writer = new BufferedWriter( new FileWriter( file ) );
         
         writer.write( text );
         writer.flush();
         writer.close();
      }
      catch ( Exception e )
      {
         session.log(e);
      }
   }
   
   
   private void executeQuery( String query )
   {
      if ( !session.dbConnect )
      {
         return;
      }
      
      ResultSetMetaData rdata;
      Vector data = new Vector();
      boolean pp = printTable.isSelected();
      
      query = query.replace( '\n', ' ' );
      
      try
      {
         rset = generalStmt.executeQuery( query );
         output.setText( query + "  -> OK" );
      }
      catch ( Exception e )
      {
         output.setText( e.getMessage().trim() );
      }
      
      try
      {
            rdata = rset.getMetaData();
            
            String[] columnNames = new String[rdata.getColumnCount()];
            int cCount = rdata.getColumnCount();
            
            if ( pp )
            {
               System.out.println();
            }
            
            for ( int i = 0; i < cCount; i++ )
            {
               String cName = rdata.getColumnName( i + 1 );
               
               columnNames[i] = cName;
               if ( pp )
               {
                  System.out.print( spaces( cName, 79 / cCount ) );
               }
            }
            
            if ( pp )
            {
               System.out.println();
               for ( int i = 0; i < cCount; i++ )
               {
                  String cName = "-------------------------------------------------------------------------------";
                  
                  System.out.print( spaces( cName, ( 79 / cCount - 1 ) ) + " " );
               }
               System.out.println();
            }
            
            int lines = 0;
            
            while ( rset.next() )
            {
               String[] row = new String[rdata.getColumnCount()];
               
               try
               {
                  for ( int i = 0; i < rdata.getColumnCount(); i++ )
                  {
                     row[i] = rset.getString( i + 1 );
                     if ( pp )
                     {
                        System.out.print( spaces( row[i], ( 79 / cCount - 1 ) ) + " " );
                     }
                  }
                  data.addElement( row );
                  lines++;
                  if ( pp )
                  {
                     System.out.println();
                  }
               }
               catch ( Exception readException )
               {
               }
            }
         rset.close();
         output.setText( query + " -> " + String.valueOf( lines ) + " Zeilen." );
         dbTableModel.setColumnNames( columnNames );
         dbTableModel.setDataVector( data );
         sorter.reallocateIndexes();
      }
      catch ( Exception e )
      {
         // session.log(e);
      }
   }
   
   
   private void login()
   {
      try
      {
         session.closeDB();
         this.setTitle( "SQL - Mini - Client" );
         
         LoginDialog lDialog = new LoginDialog();
         
         if ( lDialog.isOK() )
         {
            session.defaultUser = lDialog.getUser();
            session.defaultUserPasswd = lDialog.getPassword();
            session.dbHost = lDialog.getHost();
            session.sServiceName = lDialog.getSID();
         }
         if ( session.dbHost == null )
         {
            session.dbConnect = false;
         } else
         {
            session.oracleConnection = session.getOracleConnection();
            generalStmt = session.getStatement();
            if ( generalStmt != null )
            {
               output.setText( "DB Connection " + session.sServiceName + ":" + session.dbHost + " aufgebaut." );
            } else
            {
               output.setText( "DB Connection: <none>" );
            }
         }
         this.setTitle( "SQL - Mini - Client ( " + SessionBuffer.defaultUser + "@" + SessionBuffer.sServiceName + " )" );
      }
      catch ( Exception any )
      {
         System.err.println( any );
      }
   }
   
/*
  private void printTable() {
    PrinterJob printerJob = PrinterJob.getPrinterJob();
    Book book = new Book();
    PageFormat format = new PageFormat();
 
    Paper paper = new Paper();
 
    paper.setImageableArea( 10.0, 10.0, 300.0, 800.0 );
    format.setPaper( paper );
 
    book.append( this, format );
    printerJob.setPageable( book );
 
    boolean doPrint = printerJob.printDialog();
 
    if ( doPrint ) {
      try {
        printerJob.print();
      }
      catch ( PrinterException exception ) {
        System.err.println( "Printing error: " + exception );
      }
    }
  }
 */
   
   public int print( Graphics g, PageFormat format, int pageIndex )
   {
      Graphics2D g2d = (Graphics2D) g;
      
      g2d.translate( format.getImageableX(), format.getImageableY() );
      g2d.setPaint( Color.black );
      table.print( g2d );
      return Printable.PAGE_EXISTS;
   }
   
   
   private String spaces( String s, int k )
   {
      String spc = "";
      
      if ( s != null )
      {
         spc = s;
      }
      int diff = k - spc.length();
      
      if ( diff < 0 )
      {
         spc = spc.substring( 0, k );
      } else
      {
         for ( int i = 0; i < diff; i++ )
         {
            spc += " ";
         }
      }
      return spc;
   }
   
   
   /**
    *  Die Methode dient dem Aufruf der (einzigen) Instanz der Klasse.
    *
    * @return    Die Instanz.
    */
   public static MiniClient getInstance()
   {
      if ( miniClient == null )
      {
         miniClient = new MiniClient();
      }
      return miniClient;
   }
   
   
   /**
    *  Die Main-Methode.
    *
    * @param  argv  Die Kommandozeilenparameter.
    */
   public static void main( String[] argv )
   {
      singleStart = true;
      
      MiniClient mc = MiniClient.getInstance();
      
      mc.setVisible( true );
   }
}

