package gui.detail;

import core.manager.ColorManager;
import core.processing.GetFromRemoteAndStore;
import gui.BasicFrame;
import gui.chart.CategoryTableXYDatasetRDA;
import gui.chart.panel.StackChartPanel;
import gui.detail.explainplan.ExplainPlanModel10g2;
import gui.detail.template.RowToTableJPanel;
import gui.gantt.MonitorGantt3;
import gui.util.ProgressBarUtil;
import lombok.extern.slf4j.Slf4j;
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.table.TableColumnExt;
import org.jdesktop.swingx.treetable.TreeTableModel;
import org.jfree.chart.util.GanttParam;
import store.StoreManager;

import javax.swing.*;
import javax.swing.table.TableColumnModel;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import static java.awt.BorderLayout.CENTER;

@Slf4j
public class SqlDetail extends JFrame implements ActionListener {
    private BasicFrame jFrame;
    private GanttParam ganttParam;
    private final String valueAtSqlId;
    private StoreManager storeManager;
    private GetFromRemoteAndStore getFromRemoteAndStore;
    private ColorManager colorManager;

    private JButton start10046;
    private JButton stop10046;
    private JButton updateButton;

    private JToolBar toolBarPanel;
    private JSplitPane mainSplitPane;
    private JTabbedPane tabsSessionDetails;
    private JTabbedPane tabsHashValueSqlId;
    private JTabbedPane tabsStatsDetails;

    private StackChartPanel stackedChartPanel;
    private JSplitPane sqlTextSplitPane;

    private CategoryTableXYDatasetRDA categoryTableXYDatasetRTV;
    private MonitorGantt3 monitorGantt;

    public SqlDetail(BasicFrame jFrame,
                     GanttParam ganttParam,
                     String valueAtSqlId,
                     StoreManager storeManager,
                     GetFromRemoteAndStore getFromRemoteAndStore,
                     ColorManager colorManager) {
        this.jFrame = jFrame;
        this.ganttParam = ganttParam;
        this.valueAtSqlId = valueAtSqlId;
        this.storeManager = storeManager;
        this.getFromRemoteAndStore = getFromRemoteAndStore;
        this.colorManager = colorManager;

        this.setLayout(new BorderLayout());

        this.initialize();
        this.repaint();
        this.requestFocus();
        this.setVisible(true);
    }

    public void initialize(){
        ProgressBarUtil.runProgressDialog(() -> this.init(), jFrame, "Loading data for sql_id="+ this.valueAtSqlId);
    }

    private void init() {
        this.start10046 = new JButton("10046 start");
        this.stop10046 = new JButton("10046 stop");
        this.updateButton = new JButton("update");

        this.start10046.addActionListener(this);
        this.stop10046.addActionListener(this);
        this.updateButton.addActionListener(this);

        this.toolBarPanel = new JToolBar("PanelButton");
        this.toolBarPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        this.toolBarPanel.add(start10046);
        this.toolBarPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        this.toolBarPanel.add(stop10046);
        this.toolBarPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        this.toolBarPanel.add(updateButton);

        this.setTitle("SQL_ID = " + this.valueAtSqlId);
        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        this.mainSplitPane = new JSplitPane();
        this.mainSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);

        this.tabsSessionDetails = new JTabbedPane();
        this.tabsStatsDetails = new JTabbedPane();
        this.sqlTextSplitPane = new JSplitPane();

        this.tabsHashValueSqlId = new JTabbedPane();

        /** Create stacked chart panel + depend gantt chart interface **/
        categoryTableXYDatasetRTV = new CategoryTableXYDatasetRDA();
        stackedChartPanel = new StackChartPanel("SQL_ID: " + this.valueAtSqlId, colorManager);
        stackedChartPanel.setXyDatasetRDA(categoryTableXYDatasetRTV);
        stackedChartPanel.setLegendFontSize(10);
        stackedChartPanel.initialize();

        monitorGantt = new MonitorGantt3(new GanttParam.Builder(ganttParam.getBeginTime(), ganttParam.getEndTime())
                                .sqlId(this.valueAtSqlId).build(), jFrame, storeManager, getFromRemoteAndStore, colorManager);
        monitorGantt.setHistory(true);
        monitorGantt.setGanttParam(new GanttParam.Builder(ganttParam.getBeginTime(), ganttParam.getEndTime()).build());
        stackedChartPanel.addChartListenerReleaseMouse(monitorGantt);

        JSplitPane splitPaneChart = new JSplitPane();
        splitPaneChart.setOrientation(JSplitPane.VERTICAL_SPLIT);
        splitPaneChart.setDividerLocation(150);

        splitPaneChart.add(stackedChartPanel.getStackedChart().getChartPanel(), "top");
        splitPaneChart.add(monitorGantt, "bottom");

        /** SQL text**/
        JTextArea textArea = new JTextArea(getFromRemoteAndStore.getSqlFullText(this.valueAtSqlId));
        textArea.setFont(new Font("Serif", Font.ITALIC, 16));
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);

        JScrollPane areaScrollPane = new JScrollPane(textArea);
        areaScrollPane.setVerticalScrollBarPolicy(
                JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        areaScrollPane.setPreferredSize(new Dimension(250, 250));

        /** SQL plan*/
        JTabbedPane tabsSQLPlan = new JTabbedPane();
        getFromRemoteAndStore.getSqlPlanHashValue(this.valueAtSqlId).stream().forEach(k -> {
            String phvTabTitle = "PHV: " + k.getPlan_hash_value();
            getFromRemoteAndStore.loadSqlPlanHashValueFromRemoteToLocalBDB(this.valueAtSqlId, k.getPlan_hash_value());
            ExplainPlanModel10g2 sqlPlanModel = (ExplainPlanModel10g2)
                    getFromRemoteAndStore.getSqlPlanModelByPlanHashValue(new HashMap<>(), k.getPlan_hash_value(), this.valueAtSqlId);
            JScrollPane scrollPane = new JScrollPane(createTreeTable(sqlPlanModel));
            tabsSQLPlan.addTab(phvTabTitle, scrollPane);
        });

        /** SQL ID detail -- in table mode **/
        getFromRemoteAndStore.getIProfile().getSqlStatsQuery().entrySet()
                .stream().forEach(k -> {
            AtomicInteger atomicInt = new AtomicInteger(0);
            JTabbedPane jTabbedPane = new JTabbedPane();

            getFromRemoteAndStore.getSqlPlanHashValue(this.valueAtSqlId).stream().forEach(l -> {
                RowToTableJPanel rowToTableJPanelSqlIdDetail = new RowToTableJPanel();
                rowToTableJPanelSqlIdDetail.loadNewData(
                        getFromRemoteAndStore.getVectorDataForRowToTableForSql(this.valueAtSqlId, l.getChild_address(), k.getValue()));

                if (k.getKey().equalsIgnoreCase("V$SQL")) {
                    jTabbedPane.add(String.valueOf(atomicInt.getAndIncrement()), rowToTableJPanelSqlIdDetail);
                } else {
                    if (atomicInt.getAndIncrement() == 0) {
                        jTabbedPane.add(String.valueOf(atomicInt.getAndIncrement()-1), rowToTableJPanelSqlIdDetail);
                    }
                }

            });

            tabsStatsDetails.add(k.getKey(), jTabbedPane);

        });

        sqlTextSplitPane.add(areaScrollPane, "top");
        sqlTextSplitPane.add(tabsSQLPlan, "bottom");
        sqlTextSplitPane.setDividerLocation(150);
        sqlTextSplitPane.setOneTouchExpandable(true);
        sqlTextSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);

        // Load data from remote to local databases
        this.loadData();

        // Add View to JTabbedpane
        this.tabsSessionDetails.add("ASH", splitPaneChart);
        this.tabsSessionDetails.add("Sql text/plan", sqlTextSplitPane);
        this.tabsSessionDetails.add("Statistics", tabsStatsDetails);

        int x = (jFrame.getX() + jFrame.getWidth() / 2) - 450;
        int y = (jFrame.getY() + jFrame.getHeight() / 2) - 250;
        this.setBounds(x, y, 900, 500);

        this.add(CENTER, tabsSessionDetails);
    }

    private void loadData(){
        storeManager.getOlapDAO().loadDataToCategoryTableXYDatasetRTVBySqlSessionID(
                new GanttParam.Builder(ganttParam.getBeginTime(), ganttParam.getEndTime()).sqlId(this.valueAtSqlId).build(),
                categoryTableXYDatasetRTV,
                stackedChartPanel
        );
    }

    protected JXTreeTable createTreeTable(TreeTableModel model) {
        if (model == null) {
            return null;
        }
        JXTreeTable treeTable = new JXTreeTable(model);
        treeTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
        treeTable.setColumnControlVisible(true);
        treeTable.setRolloverEnabled(true);
        DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
        renderer.setOpenIcon(null);
        renderer.setClosedIcon(null);
        renderer.setLeafIcon(null);
        treeTable.setTreeCellRenderer(renderer);
        treeTable.setShowGrid(true, true);
        treeTable.setBackground(new Color(255, 250, 237));
        treeTable.expandAll();

        TableColumnModel columnModel = treeTable.getColumnModel();

        if (model instanceof ExplainPlanModel10g2) {
            columnModel.getColumn(0).setPreferredWidth(300);
            columnModel.getColumn(11).setPreferredWidth(70);
            columnModel.getColumn(13).setPreferredWidth(50);
            columnModel.getColumn(20).setPreferredWidth(40);
            columnModel.getColumn(21).setPreferredWidth(40);
            columnModel.getColumn(22).setPreferredWidth(40);


            List tableColumnExtList = new ArrayList<TableColumnExt>();
            for (int i = 0; i < 38; i++) {
                tableColumnExtList.add(treeTable.getColumnExt(i));
            }
            int i = 0;
            Iterator tableColumnExtListIter = tableColumnExtList.iterator();
            while (tableColumnExtListIter.hasNext()) {
                TableColumnExt tmpColumn = (TableColumnExt) tableColumnExtListIter
                        .next();
                if (i == 0 || i == 11 || i == 13 || i == 20 || i == 21
                        || i == 22) {
                    tmpColumn.setVisible(true);
                } else {
                    tmpColumn.setVisible(false);
                }
                i++;
            }

        } else { // ExplainPlanModel9i
            columnModel.getColumn(0).setPreferredWidth(300);
            columnModel.getColumn(11).setPreferredWidth(70);
            columnModel.getColumn(18).setPreferredWidth(50);
            columnModel.getColumn(19).setPreferredWidth(40);
            columnModel.getColumn(20).setPreferredWidth(40);
            //columnModel.getColumn(22).setPreferredWidth(40);

            List tableColumnExtList = new ArrayList<TableColumnExt>();
            for (int i = 0; i < 32; i++) {
                tableColumnExtList.add(treeTable.getColumnExt(i));
            }
            int i = 0;
            Iterator tableColumnExtListIter = tableColumnExtList.iterator();
            while (tableColumnExtListIter.hasNext()) {
                TableColumnExt tmpColumn = (TableColumnExt) tableColumnExtListIter
                        .next();
                if (i == 0 || i == 11 || i == 18 || i == 19 || i == 20) {
                    tmpColumn.setVisible(true);
                } else {
                    tmpColumn.setVisible(false);
                }
                i++;
            }
        }

        return treeTable;
    }

    @Override
    public void actionPerformed(ActionEvent e) {

    }
}
