package Common.Visual;
import Common.CommonConstants;
import Common.Current_;
import Common.Utils.Utils_;
import Common.Database.Objects.DBObject;
import Common.Database.Tables.DBTable;
import Common.Database.Tables.DataSet;
import Common.Database.Tables.FKBehaviour;
import _VisualDVM.Global;
import _VisualDVM.Visual.UI;
import Common.Visual.Menus.TableMenu;
import Common.Visual.Tables.ColumnInfo;
import Common.Visual.Tables.DataTable;
import Common.Visual.Tables.Grid.GridAnchestor;
import _VisualDVM.GlobalData.Grid.TableVisualData;

import javax.swing.*;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Arrays;
import java.util.Vector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static Common.Visual.Tables.TableEditors.EditorSelect;
import static Common.Visual.Tables.TableRenderers.RendererSelect;
public class DataSetControlForm extends ControlWithCurrentForm<DataTable> {
    protected JPanel dataPanel;
    protected DataSet dataSource;
    public JPanel getDataPanel() {
        return dataPanel;
    }
    protected int current_row_i;
    protected boolean events_on = true;
    protected String colNamesAndSizes = "";
    protected Vector<ColumnInfo> columns = new Vector<>();
    public DataSetControlForm(DataSet dataSource_in) {
        this(dataSource_in, DataTable.class);
    }
    public DataSetControlForm(DataSet dataSource_in, Class tableClass) {
        super(tableClass);
        dataSource = dataSource_in;
        //---
        dataPanel = new JPanel(new BorderLayout());
        content.add(dataPanel, BorderLayout.CENTER);
    }
    @Override
    public void Show() {
        super.Show();
        dataPanel.add(scroll);
        dataPanel.updateUI();
    }
    @Override
    public void Clear() {
        super.Clear();
        UI_.Clear(dataPanel);
    }
    public DataSet getDataSource() {
        return dataSource;
    }
    @Override
    public Current_ CurrentName() {
        return getDataSource().CurrentName();
    }
    public void SaveColumns() {
        if (Global.mainModule.getDb() != null) {
            try {
                if ((CurrentName() != null)) {
                    String tableName= CurrentName().toString();
                    Vector<String> widths = IntStream.range(0, columns.size()).mapToObj(i -> String.valueOf(control.getColumnModel().getColumn(i).getWidth())).collect(Collectors.toCollection(Vector::new));
                    String packed = String.join("|", widths);
                    TableVisualData tableVisualData;
                    if (Global.mainModule.getDb().tablesVisualData.containsKey(tableName)) {
                        tableVisualData = Global.mainModule.getDb().tablesVisualData.get(tableName);
                    } else {
                        tableVisualData = new TableVisualData(tableName);
                        Global.mainModule.getDb().Insert(tableVisualData);
                    }
                    tableVisualData.sizes = packed;
                    Global.mainModule.getDb().Update(tableVisualData);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
    public boolean hasCheckBox() {
        return false;
    }
    private Vector<String> getHeaders() {
        return columns.stream().map(ColumnInfo::getName).collect(Collectors.toCollection(Vector::new));
    }
    protected void CreateColumnsInfo() {
        columns.clear();
        columns.add(new ColumnInfo(getDataSource().getPKName()));
        if (hasCheckBox()) {
            columns.add(new ColumnInfo("", RendererSelect, EditorSelect));
            columns.get(1).setMinWidth(25);
            columns.get(1).setMaxWidth(25);
        }
        Arrays.stream(getDataSource().getUIColumnNames()).forEach(name -> columns.add(new ColumnInfo(name)));
        AdditionalInitColumns();
    }
    protected void AdditionalInitColumns() {
        //уточнение инфы по столбцам.
    }
    @SuppressWarnings("unchecked")
    @Override
    public void CreateControl() {
        CreateColumnsInfo();
        GridAnchestor table_data_model = new GridAnchestor(getHeaders(), dataSource.getVisibleKeys()) {
            @SuppressWarnings("unchecked")
            @Override
            public Object getValueAt(int rowIndex, int columnIndex) {
                Object key = data.get(rowIndex);
                if (columnIndex == 0)
                    return key;
                DBObject object = getDataSource().get((key));
                if ((columnIndex == 1) && hasCheckBox())
                    return object.isSelected();
                return getDataSource().getFieldAt(object, columnIndex);
            }
            @Override
            public boolean isCellEditable(int row, int col) {
                return columns.get(col).isEditable();
            }
            //------------------------------------------------------------------------------------
            @Override
            public void setValueAt(Object value, int row, int col) {
                fireTableCellUpdated(row, col);
            }
        };
        control = new DataTable(table_data_model) {
            @Override
            public TableMenu CreateMenu() {
                return new TableMenu(this);
            }
            //строго говоря эта штука нужна только для рендереров и едиторов клеток.
            @Override
            public DBObject getRowObject(int rowIndex) {
                //вот так делать НЕЛЬЗЯ. модель только для внутреннего пользования
                // Object key = table_data_model.data.get(rowIndex);
                //из таблицы можно пользоваться только getValueAt
                //иначе сортировка не будет работать.
                Object key = getValueAt(rowIndex, 0);
                return getDataSource().get(key);
            }
            //-----------------------------NEW-------------------------------------
            @Override
            public void CorrectColumnsSizes() {
                if ((Global.mainModule.getDb() != null)
                        && CurrentName() != null
                        && Global.mainModule.getDb().tablesVisualData.containsKey(CurrentName().toString())) {
                    if (!getColumnsProfile().equalsIgnoreCase(colNamesAndSizes)) {
                        TableVisualData grid = Global.mainModule.getDb().tablesVisualData.get(CurrentName().toString());
                        String[] data = grid.sizes.split("\\|");
                        for (int i = 0; i < columns.size(); ++i) {
                            if (i <= (data.length - 1)) {
                                int width = Integer.parseInt(data[i]);
                                getColumnModel().getColumn(i).setPreferredWidth(width);
                                getColumnModel().getColumn(i).setWidth(width);
                            }
                        }
                    }
                } else
                    super.CorrectColumnsSizes(); //обычный авторазмер.
            }
            public String getColumnsProfile() {
                String res = "";
                for (int i = 0; i < getColumnModel().getColumnCount(); i++) {
                    if (i > 0) res += ",";
                    TableColumn column = getColumnModel().getColumn(i);
                    res += column.getHeaderValue();
                    res += ":";
                    res += column.getWidth();
                }
                return res;
            }
            @Override
            public void Init() {
                for (int i = 0; i < columns.size(); i++) {
                    ColumnInfo columnInfo = columns.get(i);
                    if (columnInfo.isVisible()) {
                        if (columnInfo.hasRenderer())
                            getColumnModel().getColumn(i).setCellRenderer(UI.TableRenderers.get(columnInfo.getRenderer()));
                        if (columnInfo.hasEditor())
                            getColumnModel().getColumn(i).setCellEditor(UI.TableEditors.get(columnInfo.getEditor()));
                        if (columnInfo.hasMaxWidth())
                            getColumnModel().getColumn((i)).setMaxWidth(columnInfo.getMaxWidth());
                        if (columnInfo.hasMinWidth())
                            getColumnModel().getColumn((i)).setMinWidth(columnInfo.getMinWidth());
                    } else {
                        getColumnModel().getColumn(i).setMinWidth(0);
                        getColumnModel().getColumn(i).setMaxWidth(0);
                    }
                }
                //обновление в БД при ручном изменении размера столбиков.--------->>
                getTableHeader().addMouseListener(new MouseAdapter() {
                    public void mouseReleased(MouseEvent arg0) {
                        String new_colNamesAndSizes = getColumnsProfile();
                        // check if changed, if yes, persist...
                        if (!colNamesAndSizes.equals(new_colNamesAndSizes)) {
                            colNamesAndSizes = new_colNamesAndSizes;
                            SaveColumns();
                        }
                    }
                });
                //------------------------->>
            }
        };
        if (CurrentName() != null) {
            current_row_i = CommonConstants.Nan;
            ListSelectionModel selModel = control.getSelectionModel();
            selModel.addListSelectionListener(e -> {
                int row = control.getSelectedRow();
                if ((row >= 0)) {
                    if (row != current_row_i) {
                        current_row_i = row;
                        getDataSource().setCurrent(control.getRowObject(row));
                        if (events_on) {
                            try {
                                ShowCurrentObject();
                            } catch (Exception ex) {
                                Utils_.MainLog.PrintException(ex);
                            }
                        }
                    }
                } else {
                    current_row_i = CommonConstants.Nan;
                    getDataSource().dropCurrent();
                    if (events_on) {
                        try {
                            ShowNoCurrentObject();
                        } catch (Exception ex) {
                            Utils_.MainLog.PrintException(ex);
                        }
                    }
                }
            });
            //двойной клик мыши.------------------------------------------------------
            control.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    if ((e.getClickCount() == 2) && (dataSource.getCurrent() != null)) {
                        try {
                            MouseAction2();
                        } catch (Exception ex) {
                            Utils_.MainLog.PrintException(ex);
                        }
                    }
                }
            });
            //----------------------------------------------------------------------------
            //при переотображении таблицы скидываем текущий объект!!
            getDataSource().dropCurrent();
            try {
                ShowNoCurrentObject();
            } catch (Exception e) {
                Utils_.MainLog.PrintException(e);
            }
        }
        //---
        /*
        if (hasCheckBox()) {
            TableColumn column = control.getColumnModel().getColumn(1)
                    column.setHeaderRenderer(new TableCellRenderer() {
                        @Override
                        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                            return null;
                        }

                    });
        }
         */
    }
    @Override
    protected void refresh() {
        control.CorrectSizes();
    }
    public void Show(Object pk) {
        Show();
        Select(pk);
    }
    public void Select(Object pk) {
        if (isShown())
            control.SelectRowByPK(pk);
    }
    public void ClearSelection() {
        if (isShown())
            control.clearSelection(); //строка сбросится сама. благодаря сбросу события выбора
    }
    public int getRowCount() {
        return control.getRowCount();
    }
    @Override
    public void ShowCurrentObject() throws Exception {
        if (dataSource instanceof DBTable) {
            DBTable table = (DBTable) dataSource;
            for (Class dep : table.getFKDependencies().keySet()) {
                FKBehaviour behaviour = table.getFKDependencies().get(dep);
                switch (behaviour.ui) {
                    case ACTIVE:
                        table.getDb().tables.get(dep).ShowUI();
                        break;
                    case PASSIVE:
                        break;
                }
            }
        }
    }
    @Override
    public void ShowNoCurrentObject() throws Exception {
        if (dataSource instanceof DBTable) {
            DBTable table = (DBTable) dataSource;
            for (Class dep : table.getFKDependencies().keySet()) {
                FKBehaviour behaviour = table.getFKDependencies().get(dep);
                switch (behaviour.ui) {
                    case ACTIVE:
                        table.getDb().tables.get(dep).ClearUI();
                        break;
                    case PASSIVE:
                        break;
                }
            }
        }
    }
}
