/*
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 2002-2005 Julian Hyde
// Copyright (C) 2005-2011 Pentaho and others
// Copyright (C) 2006-2007 Cincom Systems, Inc.
// All Rights Reserved.
*/

package mondrian.gui;

import mondrian.gui.validate.ValidationUtils;
import mondrian.olap.*;
import mondrian.olap.Util.PropertyList;

import org.apache.log4j.Logger;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.text.DefaultEditorKit;

/**
 * @author sean
 */
public class QueryPanel extends javax.swing.JPanel {

    private static final Logger LOGGER = Logger.getLogger(QueryPanel.class);

    Connection connection;
    JMenuItem queryMenuItem;
    int windowMenuIndex;

    // map of schema frames and schema menu items
    Map<JInternalFrame, JMenuItem> schemaWindowMap;

    final Workbench workbench;

    /**
     * Creates new form QueryPanel
     */
    public QueryPanel(Workbench workbench) {
        this.workbench = workbench;
        initComponents();
    }

    public void setConnection(Connection c) {
        connection = c;
    }

    public Connection getConnection() {
        return connection;
    }

    //====================================================

    public void setMenuItem(JMenuItem mi) {
        this.queryMenuItem = mi;
    }

    public void setSchemaWindowMap(
        Map<JInternalFrame, JMenuItem> schemaWindowMap)
    {
        this.schemaWindowMap = schemaWindowMap;
        setCatalogs();
    }

    private void setCatalogs() {
        List<String> v = new ArrayList<String>();
        Iterator<JMenuItem> it = schemaWindowMap.values().iterator();
        while (it.hasNext()) {
            JMenuItem elem = it.next();
            v.add(elem.getText());
        }
        ComboBoxModel cCatalogs =
            new DefaultComboBoxModel(new Vector<String>(v));
        schemaList.setModel(cCatalogs);
    }

    public void setWindowMenuIndex(int i) {
        this.windowMenuIndex = i;
    }

    /**
     * @return the workbench i18n converter
     */
    public I18n getResourceConverter() {
        return workbench.getResourceConverter();
    }

    public void initConnection(String smenutext) {
        schemaList.setSelectedItem(smenutext);
        connectButtonActionPerformed(null);
    }
    //=====================================================

    /**
     * This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {
        jScrollPane3 = new javax.swing.JScrollPane();
        executeButton = new javax.swing.JButton();
        jSplitPane1 = new javax.swing.JSplitPane();
        jScrollPane1 = new javax.swing.JScrollPane();
        queryTextPane = new javax.swing.JTextPane();
        jScrollPane2 = new javax.swing.JScrollPane();
        resultTextPane = new javax.swing.JTextPane();
        connectButton = new javax.swing.JButton();
        jPopupMenu = new JPopupMenu();
        jPopupMenu.add(new DefaultEditorKit.CutAction());
        jPopupMenu.add(new DefaultEditorKit.CopyAction());
        jPopupMenu.add(new DefaultEditorKit.PasteAction());

        schemaScrollPane1 = new javax.swing.JScrollPane();
        schemaLabel = new javax.swing.JLabel();
        schemaList = new JComboBox(
            new String[]{
                getResourceConverter().getString(
                    "common.join.title", "Join"),
                getResourceConverter().getString(
                    "common.table.title", "Table")
            });
        //schemaScrollPane1.setViewportView(schemaList);
        schemaPanel = new JPanel();
        //schemaPanel.setLayout(new BorderLayout(25,0));
        schemaPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0));

        setLayout(new java.awt.BorderLayout());

        schemaLabel.setFont(new Font("Dialog", 1, 12));
        schemaLabel.setForeground(
            (Color) UIManager.getDefaults().get(
                "CheckBoxMenuItem.acceleratorForeground"));
        schemaLabel.setHorizontalAlignment(SwingConstants.CENTER);
        schemaLabel.setText(
            getResourceConverter().getString(
                "common.schema.title", "Schema"));
        //schemaLabel.setBorder(new EtchedBorder());

        schemaList.setBackground(Color.white);
        final JPanel qpanel = this;
        schemaList.addItemListener(
            new ItemListener() {
                public void itemStateChanged(ItemEvent e) {
                }
            });
        connectButton.setText(
            getResourceConverter().getString(
                "queryPanel.connect.title", "Connect"));
        connectButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    connectButtonActionPerformed(evt);
                }
            });

        schemaPanel.add(schemaLabel); //java.awt.BorderLayout.WEST
        schemaPanel.add(schemaList);
        schemaPanel.add(connectButton);

        add(schemaPanel, java.awt.BorderLayout.NORTH);

        executeButton.setText(
            getResourceConverter().getString(
                "queryPanel.execute.title", "Execute"));
        executeButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    executeButtonActionPerformed(evt);
                }
            });

        add(executeButton, java.awt.BorderLayout.SOUTH);

        jSplitPane1.setDividerLocation(100);
        jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        queryTextPane.setFont(new java.awt.Font("Courier New", 0, 12));
        queryTextPane.setText("");
        queryTextPane.addMouseListener(
            new MouseAdapter() {
                // From MouseAdapter javadoc:
                //
                // Popup menus are triggered differently
                // on different systems. Therefore, isPopupTrigger
                // should be checked in both mousePressed
                // and mouseReleased
                // for proper cross-platform functionality.

                public void mousePressed(MouseEvent e) {
                    checkPopupTrigger(e);
                }

                public void mouseReleased(MouseEvent e) {
                    checkPopupTrigger(e);
                }

                public void checkPopupTrigger(MouseEvent e) {
                    if (e.isPopupTrigger()) {
                        int x = e.getX();
                        int y = e.getY();

                        jPopupMenu.show(queryTextPane, x, y);
                    }
                }
            });

        jScrollPane1.setViewportView(queryTextPane);

        jSplitPane1.setTopComponent(jScrollPane1);

        resultTextPane.setEditable(false);
        resultTextPane.setFont(new java.awt.Font("Courier New", 0, 12));
        jScrollPane2.setViewportView(resultTextPane);

        jSplitPane1.setBottomComponent(jScrollPane2);

        add(jSplitPane1, java.awt.BorderLayout.CENTER);
    }

    private void executeButtonActionPerformed(ActionEvent evt) {
        //run the query, and show the results.
        try {
            if (connection == null) {
                JOptionPane.showMessageDialog(
                    this, getResourceConverter().getString(
                        "queryPanel.noConnection.alert",
                        "No Mondrian connection. Select a Schema to connect."),
                    getResourceConverter().getString(
                        "common.alertDialog.title", "Alert"),
                    JOptionPane.WARNING_MESSAGE);
                return;
            } //common.alertDialog.title
            Query q = connection.parseQuery(queryTextPane.getText());

            Result r = connection.execute(q);

            //document = DomBuilder.build(getResult());
            java.io.StringWriter sw = new java.io.StringWriter();
            java.io.PrintWriter pw = new java.io.PrintWriter(sw);

            r.print(pw);

            resultTextPane.setText(sw.getBuffer().toString());
        } catch (Exception ex) {
            ByteArrayOutputStream os = new ByteArrayOutputStream();

            PrintStream p = new PrintStream(os);

            Throwable e = ex;
            while (e != null) {
                p.println(e.getLocalizedMessage());
                LOGGER.error("", e);
                Throwable prev = e;
                e = e.getCause();
                if (e == prev) {
                    break;
                }
                p.println();
            }

            resultTextPane.setText(os.toString());
        }
    }

    private void connectButtonActionPerformed(ActionEvent evt) {
        File sfile = null;
        try {
            String sfname = (String) schemaList.getSelectedItem();
            JInternalFrame sf = lookupFrame(sfname);

            if (sf == null) {
                // this case may arise when a schema file is opened, mdx query
                // is opened and the schema frame is closed
                JOptionPane.showMessageDialog(
                    this, getResourceConverter().getString(
                        "queryPanel.schemaNotOpen.alert",
                        "Schema file is not open"),
                    getResourceConverter().getString(
                        "common.errorDialog.title", "Error"),
                    JOptionPane.ERROR_MESSAGE);
                return;
            }

            SchemaExplorer se =
                (SchemaExplorer) sf.getContentPane().getComponent(0);
            if (se.isNewFile()) {
                JOptionPane.showMessageDialog(
                    this,
                    getResourceConverter().getString(
                        "queryPanel.saveSchemaFirst.alert",
                        "You must first save the Schema to open a Mondrian connection"),
                    getResourceConverter().getString(
                        "common.alertDialog.title", "Alert"),
                    JOptionPane.WARNING_MESSAGE);
                sf.setSelected(true);
                return;
            }
            sfile = se.getSchemaFile();
            PropertyList list = new PropertyList();
            list.put("Provider", "mondrian");
            list.put("Jdbc", se.getJdbcConnectionUrl());
            list.put("Catalog", se.getSchemaFile().toURL().toString());
            final String jdbcUsername = se.getJdbcUsername();
            if (!ValidationUtils.isEmpty(jdbcUsername)) {
                list.put("JdbcUser", jdbcUsername);
            }
            final String jdbcPassword = se.getJdbcPassword();
            if (!ValidationUtils.isEmpty(jdbcPassword)) {
                list.put("JdbcPassword", jdbcPassword);
            }
            Connection con = DriverManager.getConnection(list, null);

            // clear cache before connecting
            con.getCacheControl(null).flushSchemaCache();

            if (con != null) {
                connection = con;
                queryMenuItem.setText(
                    getResourceConverter().getFormattedString(
                        "queryPanel.successfulConnection.menuItem",
                        "{0} MDX - {1}",
                        Integer.toString(windowMenuIndex),
                        se.getSchemaFile().getName()));
                Component o = this;
                while (o != null) {
                    if (o.getClass() == JInternalFrame.class) {
                        ((JInternalFrame) o).setTitle(
                            getResourceConverter().getFormattedString(
                                "queryPanel.successfulConnection.internalFrame.title",
                                "MDX Query - connected to {0}",
                                se.getSchemaFile().getName()));
                        break;
                    }
                    o = o.getParent();
                }
                JOptionPane.showMessageDialog(
                    this,
                    "Mondrian connection Successful.",
                    getResourceConverter().getString(
                        "common.informationDialog.title", "Information"),
                    JOptionPane.INFORMATION_MESSAGE);
            } else {
                JOptionPane.showMessageDialog(
                    this,
                    getResourceConverter().getFormattedString(
                        "queryPanel.unsuccessfulConnection.alert",
                        "Mondrian connection could not be done for - {0}",
                        se.getSchemaFile().getName()),
                    getResourceConverter().getString(
                        "common.errorDialog.title", "Error"),
                    JOptionPane.ERROR_MESSAGE);
            }
        } catch (Exception ex) {
            LOGGER.error("Exception: " + ex.getMessage(), ex);
            JOptionPane.showMessageDialog(
                this,
                getResourceConverter().getFormattedString(
                    "queryPanel.unsuccessfulConnection.exception",
                    "Mondrian connection could not be done for - {0}",
                    sfile == null
                        ? getResourceConverter().getString(
                            "queryPanel.selectedSchema.alert",
                            "selected Schema")
                        : sfile.getName()),
                getResourceConverter().getString(
                    "common.errorDialog.title", "Error"),
                JOptionPane.ERROR_MESSAGE);
            resultTextPane.setText(getResourceConverter().getFormattedString(
                "queryPanel.exceptionMessage",
                "Exception: {0}\n\nSee workbench log for full stacktrace.",
                ex.getMessage()));
        }
    }

    private JInternalFrame lookupFrame(String sfname) {
        JInternalFrame sf = null;
        for (Map.Entry<JInternalFrame, JMenuItem> entry
            : schemaWindowMap.entrySet())
        {
            if ((entry.getValue()).getText().equals(sfname)) {
                sf = entry.getKey();
                break;
            }
        }
        return sf;
    }

    // Variables declaration - do not modify
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JTextPane resultTextPane;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextPane queryTextPane;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JButton executeButton;
    private javax.swing.JComboBox schemaList;
    private JLabel schemaLabel;
    private JPanel schemaPanel;
    private javax.swing.JScrollPane schemaScrollPane1;
    private javax.swing.JButton connectButton;
    private JPopupMenu jPopupMenu;

    // End of variables declaration

}

// End QueryPanel.java
