package Common.Database.Tables;
import Common.Current_;
import Common.Visual.DataSetFilter;
import Common.Visual.DataSetControlForm;
import Common.Visual.Menus.DataMenuBar;
import Common.Visual.Tables.ColumnFilter;
import Common.Visual.Windows.Dialog.DBObjectDialog;
import Common.Visual.Windows.Dialog.DialogFields;
import Common.Utils.TextLog;
import Common.Database.Objects.DBObject;
import Common.Visual.UI_;
import Common.Visual.FilterInterface;
import _VisualDVM.Global;

import javax.swing.*;
import java.awt.*;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Vector;
import java.util.stream.Collectors;
public class DataSet<K, D extends DBObject> extends DataSetAnchestor {
    //-
    public LinkedHashMap<Class, Object> selections = new LinkedHashMap<>();
    //---
    public String Name;
    public Class<K> k; //класс первичного ключа.
    public Class<D> d; //класс объектов.
    public LinkedHashMap<K, D> Data = new LinkedHashMap<>(); //наполнение
    //-
    public DataSetControlForm ui_;
    protected FilterInterface f_ui; // отображение количества объектов
    //-
    public LinkedHashMap<Integer, ColumnFilter> columnsFilters = new LinkedHashMap<>(); //текстовые фильтры столбцов
    //--
    protected Vector<DataSetFilter<D>> filters = new Vector<>();
    protected void createFilters() {
    }
    //--
    public DataSet(Class<K> k_in, Class<D> d_in) {
        k = k_in;
        d = d_in;
        Name = d.getSimpleName();
    }
    public void mountUI(JPanel content_in) {
        UI_.Clear(content_in);
        //-->
        ui_ = createUI();
        ui_.setContent(content_in);
        //-->
        if ( UI_.menuBars.containsKey(getClass())) {
            DataMenuBar bar =  UI_.menuBars.get(getClass());
            content_in.add(bar, BorderLayout.NORTH);
            setFilterUI(count ->  UI_.menuBars.get(getClass()).countLabel.setText(String.valueOf(count)));
            if (ui_.hasCheckBox())
                bar.createSelectionButtons(this);
        }
        content_in.add(ui_.getDataPanel(), BorderLayout.CENTER);
        //----
        createFilters();
        if (!filters.isEmpty()) {
            DataMenuBar menuBar =  UI_.menuBars.get(getClass());
            for (DataSetFilter<D> filter : filters)
                menuBar.addMenus(filter.menu);
        }
    }
    public DataSetControlForm getUi() {
        return ui_;
    }
    public void setFilterUI(FilterInterface ui_in) {
        f_ui = ui_in;
    }
    public void ClearUI() {
        if ((ui_ != null) && ui_.isShown()) {
            ui_.ClearSelection();
            ui_.Clear();
            if (f_ui != null)
                f_ui.ShowNoMatches();
        }
    }
    public void RefreshUI() {
        if (ui_ != null) ui_.Refresh();
    }
    public int getRowCountUI() {
        return ui_.getRowCount();
    }
    public void SetCurrentObjectUI(Object pk) {
        if (ui_ != null) {
            //todo возможно проверить, что текущий объект уже соответствует ключу, и если да, то ничего делать.
            ui_.ClearSelection(); //сброс текущего объекта и всего что с ним связано.
            ui_.Select(pk);
        }
    }
    public String[] getUIColumnNames() {
        return new String[]{};
    }
    protected DataSetControlForm createUI() {
        return null;
    }
    public boolean hasUI() {
        return ui_ != null;
    }
    public void CheckAll(boolean flag) {
        for (D object : Data.values()) {
            if (object.isVisible())
                object.Select(flag);
        }
        RefreshUI();
    }
    public D getFirstRecord() {
        return Data.values().stream().findFirst().orElse(null);
    }
    public Vector<D> getOrderedRecords(Comparator<D> comparator) {
        Vector<D> res = new Vector<>(Data.values());
        res.sort(comparator);
        return res;
    }
    @SuppressWarnings("unchecked")
    public DBObjectDialog<D, ? extends DialogFields> getDialog() {
        return null;
    }
    public boolean ShowAddObjectDialog(DBObject object) {
        return getDialog().ShowDialog(getSingleDescription() + ": добавление", object);
    }
    public boolean ShowEditObjectDialog(DBObject object) {
        DBObjectDialog dialog = getDialog();
        dialog.edit = true;
        dialog.SetEditLimits();
        return dialog.ShowDialog(getSingleDescription() + ": редактирование", object);
    }
    public boolean ViewObject(DBObject object) {
        DBObjectDialog dialog = getDialog();
        dialog.SetReadonly();
        dialog.ShowDialog(getSingleDescription() + ": просмотр", object);
        return false;
    }
    public boolean ShowDeleteObjectDialog(DBObject object) {
        return UI_.Warning(getSingleDescription() + " " + object.getBDialogName() + " будет удален(а)");
    }
    public String QName() {
        return "\"" + Name + "\"";
    }
    public String getPKName() {
        return "";
    } //получить имя ключевого поля. нужно для таблиц.
    public String getPluralDescription() {
        return "";
    }
    public String getSingleDescription() {
        return "";
    }
    //-
    public void put(Object key, D object) {
        Data.put((K) key, object);
    }
    public D get(Object key) {
        return Data.get(key);
    }
    public Object getFieldAt(D object, int columnIndex) {
        return null;
    }
    public void clear() {
        Data.clear();
    }
    public int size() {
        return Data.size();
    }
    public boolean containsKey(Object key) {
        return Data.containsKey(key);
    }
    //-
    public Vector<K> getVisibleKeys() {
        Comparator<D> comparator = getComparator();
        Vector<K> res = new Vector<>();
        if (comparator == null) {
            for (K key : Data.keySet())
                if (Data.get(key).isVisible())
                    res.add(key);
        } else {
            Vector<D> raw = new Vector<>();
            for (D object : Data.values()) {
                if (object.isVisible())
                    raw.add(object);
            }
            raw.sort(comparator);
            for (D object : raw)
                res.add((K) object.getPK());
        }
        return res;
    }
    protected Comparator<D> getComparator() {
        return null;
    }
    public int getCheckedCount() {
        return (int) Data.values().stream().filter(d -> d.isVisible() && d.isSelected()).count();
    }
    public Vector<D> getCheckedItems() {
        return Data.values().stream().filter(d -> d.isVisible() && d.isSelected()).collect(Collectors.toCollection(Vector::new));
    }
    public Vector<K> getCheckedKeys() {
        return Data.values().stream().filter(DBObject::isSelected).map(d -> (K) d.getPK()).collect(Collectors.toCollection(Vector::new));
    }
    //--
    // применить значение фильтра к фильру объекта  напирмер Message.filterValue = text;
    public void changeColumnFilterValue(int columnIndex, String text) {
    }
    public Object getColumnFilterValue(int columnIndex) {
        return "";
    }
    //--
    public void ShowUI() {
        for (DataSetFilter<D> filter : filters)
            filter.Drop();
        //--
        if (ui_ != null) {
            ui_.Show();
            if (f_ui != null)
                f_ui.ShowMatchesCount(getRowCountUI());
        }
        //--
        for (DataSetFilter<D> filter : filters)
            filter.Refresh();
    }
    public void ShowUI(Object key) {
        for (DataSetFilter<D> filter : filters)
            filter.Drop();
        //--
        if (ui_ != null) {
            ui_.Show(key);
            if (f_ui != null)
                f_ui.ShowMatchesCount(getRowCountUI());
        }
        //--
        for (DataSetFilter<D> filter : filters)
            filter.Refresh();
    }
    public boolean applyFilters(D object) {
        for (DataSetFilter<D> filter : filters) {
            if (!filter.Validate(object))
                return false;
        }
        return true;
    }
    //------------------------------------------------------------------------------------
    public Current_ CurrentName() {
        return null;
    }
    public boolean CheckCurrent(TextLog log) {
        return Global.mainModule.Check(log, CurrentName());
    }
    public boolean hasCurrent() {
        return Global.mainModule.get(CurrentName()) != null;
    }
    public void dropCurrent() {
        Global.mainModule.set(CurrentName(), null);
    }
    public D getCurrent() {
        return (D) Global.mainModule.get(CurrentName());
    }
    public void setCurrent(D o) {
        Global.mainModule.set(CurrentName(), o);
    }
    public Vector<D> getCheckedOrCurrent() {
        Vector<D> res = new Vector<>();
        if (getCheckedCount() > 0)
            res = getCheckedItems();
        else {
            if (CurrentName()!=null) {
                if (getCurrent() != null) {
                    res.add(getCurrent());
                }
            }
        }
        return res;
    }
    public void SaveLastSelections() {
        if (hasUI()) {
            Object lastPk = null;
            if ((CurrentName() != null) && (getCurrent() != null))
                lastPk = getCurrent().getPK();
            if (!selections.containsKey(getClass()))
                selections.put(getClass(), lastPk);
            else selections.replace(getClass(), lastPk);
        }
    }
    public void RestoreLastSelections() {
        if (hasUI()) {
            Object lastPk = selections.get(getClass());
            if ((CurrentName() != null) && (lastPk != null)) {
                ui_.Select(lastPk);
            }
        }
    }
    //-------------------------------------------------------------------------------------
}
