package com.quantum.actions;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.quantum.Messages;
import com.quantum.model.Bookmark;
import com.quantum.model.BookmarkCollection;
import com.quantum.model.ConnectionException;
import com.quantum.sql.MultiSQLServer;
import com.quantum.sql.SQLParser;
import com.quantum.sql.SQLResults;
import com.quantum.ui.dialog.BookmarkSelectionDialog;
import com.quantum.ui.dialog.ExceptionDisplayDialog;
import com.quantum.util.io.InputStreamHelper;
import com.quantum.view.tableview.DefaultSizes;
import com.quantum.view.tableview.TableView;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;

/**
 * This action can be executed against any .sql file, regardless of 
 * whether or not the Quantum perspective is open.
 * 
 * @author BC
 */
public class ExecuteAgainstAction extends BaseSQLAction
    implements IObjectActionDelegate, PropertyChangeListener {

    private String selectedBookmark = null;
    private IFile[] files = null;

    private IWorkbenchPart workbenchPart;

    /**
     * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
     */
    public void setActivePart(IAction action, IWorkbenchPart targetPart) {
        this.workbenchPart = targetPart;
    }

    protected Shell getShell() {    
        return this.workbenchPart.getSite().getShell();
    }

    /**
     * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
     */
    public void run(IAction action) {
        
        BookmarkSelectionDialog dialog = new BookmarkSelectionDialog(getShell());
        dialog.addPropertyChangeListener(this);
        int result = dialog.open();

        if (result == Window.OK) {
            try {
                executeAgainstBookmark();
            } catch (SQLException e) {
                ExceptionDisplayDialog.openError(getShell(), 
                    null, 
                    null, e);
            } catch (IOException e) {
                ExceptionDisplayDialog.openError(getShell(), 
                    Messages.getString("ExecuteAgainstAction.title"), 
                    Messages.getString("ExecuteAgainstAction.IOException"), e);
            } catch (ConnectionException e) {
                ExceptionDisplayDialog.openError(getShell(), 
                    null, 
                    null, e);
            } catch (CoreException e) {
                ErrorDialog.openError(getShell(), null, null, e.getStatus());
            }
        }
    }
    
    protected Bookmark getBookmark() {
        return BookmarkCollection.getInstance().find(this.selectedBookmark);
    }
    
    private void executeAgainstBookmark()
        throws SQLException, IOException, CoreException, ConnectionException {
        Bookmark bookmark = getBookmark();
        if (bookmark != null) {
            boolean alreadyConnected = bookmark.isConnected();
            Connection connection = getConnection();
            try {
                for (int i = 0,
                    length = (this.files == null) ? 0 : this.files.length;
                    connection != null && i < length;
                    i++) {
                    executeAgainstBookmark(bookmark, connection, this.files[i]);
                }
            } finally {
                if (!alreadyConnected && connection != null) {
                    bookmark.disconnect();
                }
            }
        }
    }

    private void executeAgainstBookmark(
        Bookmark bookmark,
        Connection connection,
        IFile file)
        throws SQLException, IOException, CoreException {
        executeAgainstBookmark(
            bookmark,
            connection,
            InputStreamHelper.readIntoString(file.getContents()));
    }

    private void executeAgainstBookmark(
        Bookmark bookmark,
        Connection connection,
        String queries)
        throws SQLException {
        List queryList = SQLParser.parse(queries);
        MultiSQLServer server = MultiSQLServer.getInstance();
        
        for (Iterator i = queryList.iterator(); i.hasNext();) {
            String query = (String) i.next();
            SQLResults results =
                server.execute(
                    connection,
                    query,
                    1,
                    DefaultSizes.PAGE_SIZE,
                    DefaultSizes.MAX_COLUMN_SIZE);
            if (results.isResultSet()) {
                TableView view = TableView.getInstance();
                if (view != null) {
                    view.loadQuery(bookmark, results);
                }
            }
        }
    }

    /**
     * This method is called with a new selection has been made on one 
     * of the views.
     * 
     * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
     */
    public void selectionChanged(IAction action, ISelection selection) {
        if (selection instanceof IStructuredSelection) {
            IStructuredSelection structuredSelection =
                (IStructuredSelection) selection;
            List list = new ArrayList();

            for (Iterator i = structuredSelection.iterator(); i.hasNext();) {
                Object temp = i.next();
                if (temp != null && temp instanceof IFile) {
                    System.out.println(((IFile) temp).getName());
                    list.add(temp);
                }
            }
            this.files = (IFile[]) list.toArray(new IFile[list.size()]);
        }
    }

    /**
     * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
     */
    public void propertyChange(PropertyChangeEvent event) {
        if ("selection".equals(event.getPropertyName())) {
            this.selectedBookmark = (String) event.getNewValue();
        }
    }
}