package asandatabasebrowser.view;

import javax.swing.*;

import net.sourceforge.swingx.SxOptionPane;

import asandatabasebrowser.*;
import asandatabasebrowser.action.*;
import asandatabasebrowser.model.*;
import blanco.commons.sql.format.BlancoSqlParser;
import blanco.commons.sql.format.BlancoSqlTokenConstants;
import blanco.commons.sql.format.valueobject.BlancoSqlToken;


import java.awt.BorderLayout;
import java.awt.event.*;
import java.awt.Cursor;
import java.util.ArrayList;


/**
 * 実行フレーム
 * <<view>>
 */
public class DbExecuteFrame extends JFrame {
	public VvDatabase db;
	JTabbedTextArea textarea;
	
    public DbExecuteFrame(VvDatabase db) {
    	this.db = db;
    	setTitle(db.name+"(autoCommit=false)");
    	setIconImage(Global.getImage("/resources/UpdateView.png"));
    	String text = 
    		"-- UPDATE テーブル名 SET カラム名1 = 値1 {, カラム名2 = 値2 } [ WHERE 条件 ]\n"+
    		"-- INSERT INTO テーブル名 [ ( カラム名1, ... ) ] VALUES ( 値1, ...)\n"+
    		"-- DELETE FROM テーブル名 [ WHERE 条件 ]";
    	text = text.toLowerCase();
    	textarea = new JTabbedTextArea(db, new SqlKeyListener());
    	textarea.addTextArea(text);
        // ビューを作成。レイアウトする。
        this.getContentPane().setLayout(new BorderLayout());
        this.getContentPane().add(textarea, BorderLayout.CENTER);
        // ツールバーを作る
        JToolBar toolbar = new JToolBar();
        toolbar.setFloatable(false);
        toolbar.setRollover(true);
        toolbar.add(new ExecuteUpdateAction(this));
        toolbar.addSeparator();
        toolbar.add(new ExecuteCommitAction(this, db, "commit", null));
        toolbar.add(new ExecuteCommitAction(this, db, "rollback", null));
        toolbar.addSeparator();
		toolbar.add(new TabAddAction(textarea));
		toolbar.add(new TabRemoveAction(textarea));
        this.getContentPane().add(toolbar, BorderLayout.NORTH);

        // 表示。
        setSize(640, 360);
        setVisible(true);
    }

    /**
     * SQLを実行します。
     * 選択されていればそのSQLで更新します。
     * 選択されていなければすべてのSQLで更新します。
     */
    public void executeUpdate() {
    	String text = textarea.getSelectedText();
    	if (text != null) text = text.trim();
    	if (text == null || text.length() == 0) {
    		text = textarea.getCurrentText();
        	if (text != null) text = text.trim();
    	}
    	if (text == null) return;
		// SQL文を字句解析し、字句ごとにぶった切る。
		ArrayList tokens = null;
		try {
			tokens = new BlancoSqlParser().parse(text);
		} catch (RuntimeException e) {
            AsanDatabaseBrowser.theApp.showMessage(textarea, 
            		"SQLが不正と思われます",
            		e, SxOptionPane.ERROR_MESSAGE);
			return;	// 不完全なSQLだと起こりえる。
		}    	
    	// セミコロンでSQLを分割する。
		ArrayList sqlList = new ArrayList();
		StringBuffer sb = new StringBuffer();
		for (int i=0; i<tokens.size(); i++) {
			BlancoSqlToken t = (BlancoSqlToken) tokens.get(i);
			switch (t.getType()) {
			case BlancoSqlTokenConstants.SPACE:
				sb.append(" ");
				break;
			case BlancoSqlTokenConstants.SYMBOL:
				if (t.getString().equals(";")) {
					sqlList.add(sb.toString());
					sb = new StringBuffer();
				} else {
					sb.append(t.getString().trim());
				}
				break;
			case BlancoSqlTokenConstants.KEYWORD:
			case BlancoSqlTokenConstants.NAME:
			case BlancoSqlTokenConstants.VALUE:
				sb.append(t.getString());
				break;
			case BlancoSqlTokenConstants.COMMENT:
				// 省く
				break;
			case BlancoSqlTokenConstants.END:
				sqlList.add(sb.toString());
				sb = new StringBuffer();
				break;
			case BlancoSqlTokenConstants.UNKNOWN:
			default:
				assert false: t.getType();
			}
		}
		if (sb.toString().trim().length() > 0) {
			sqlList.add(sb.toString().trim());
		}
    	// 複数のSQLを実行.
        setCursor(new Cursor(Cursor.WAIT_CURSOR));
        try {
        	int records = 0;
        	for (int i=0; i<sqlList.size(); i++) {
        		String sql = (String) sqlList.get(i);
        		records += db.executeUpdate(sql);
        	}
           	AsanDatabaseBrowser.theApp.showMessage(textarea, 
           			"更新しました "+records+" 件", 
           			null, SxOptionPane.INFORMATION_MESSAGE);
        } catch (Exception e) {
            AsanDatabaseBrowser.theApp.showMessage(textarea, "エラーが発生しました", e, SxOptionPane.ERROR_MESSAGE);
        }
        setCursor(Cursor.getDefaultCursor());
    }

    /** Shift+Enterが押されたらSQLを実行します。*/
    class SqlKeyListener extends KeyAdapter {
        public void keyReleased(KeyEvent e) {
            //System.out.println(e);
            if (e.getKeyCode() == KeyEvent.VK_ENTER && e.isShiftDown()) {
                executeUpdate();
            }
        }
    }

}


