/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.ctecinf.swing;

import br.com.ctecinf.autocomplete.AutoCompleteField;
import br.com.ctecinf.combobox.ComboBox;
import br.com.ctecinf.Database;
import br.com.ctecinf.Utils;
import br.com.ctecinf.text.DateFormatter;
import br.com.ctecinf.text.MaskFormatter;
import br.com.ctecinf.text.NumberFormatter;
import br.com.ctecinf.text.PasswordFormatter;
import br.com.ctecinf.text.TimeFormatter;
import br.com.ctecinf.text.TimestampFormatter;
import br.com.ctecinf.text.UpperCaseFormatter;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.security.NoSuchAlgorithmException;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JFormattedTextField;
import javax.swing.JPasswordField;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.border.TitledBorder;

/**
 *
 * @author Cássio Conceição
 * @since 11/06/2019
 * @version 1906
 * @see http://ctecinf.com.br/
 */
public class Fields {

    private final Map<String, JComponent> components;

    public Fields() {
        this.components = new HashMap();
    }

    public Map<String, JComponent> getComponents() {
        return components;
    }

    public JComponent put(JComponent component) {

        if (component.getName() != null && !component.getName().isEmpty()) {
            components.put(component.getName(), component);
        }

        return component;
    }

    public JFormattedTextField create(String name, Object value, String Mask) {

        JFormattedTextField field = new JFormattedTextField(new MaskFormatter(Mask));
        field.setValue(value);
        field.setName(name);

        components.put(name, field);

        return field;
    }

    public ComboBox create(String name, Object[] values) {
        return create(name, null, values);
    }

    public ComboBox create(String name, Object selected, Object[] values) {

        ComboBox combo = new ComboBox(values);
        combo.setName(name);
        //combo.setPrototypeDisplayValue("XXXXXXXXXXXXXXXXXXXXXXXXXX");
        combo.setSelectedItem(selected);
        combo.setMaximumSize(new Dimension(300, 15));

        components.put(name, combo);

        return combo;
    }

    public JFormattedTextField create(String name) {
        return create(name, null, Types.VARCHAR);
    }

    public <T extends JComponent> T create(String name, Object value) {
        return create(name, value, value == null ? Types.VARCHAR : Database.class2Type(value.getClass()));
    }

    public <T extends JComponent> T create(String name, Object value, Class type) {
        return create(name, value, Database.class2Type(type));
    }

    public <T extends JComponent> T create(String name, int sqlType) {
        return create(name, null, sqlType);
    }

    public <T extends JComponent> T create(String name, Object value, int sqlType) {

        JComponent field;

        if (name.toLowerCase().contains("fone") || name.toLowerCase().contains("celular")) {
            field = new JFormattedTextField(new MaskFormatter(MaskFormatter.PHONE));
            ((JFormattedTextField) field).setValue(value);
        } else if (name.toLowerCase().contains("senha")) {
            field = new JFormattedTextField(new PasswordFormatter());
            ((JFormattedTextField) field).setValue(value);
        } else if (name.toLowerCase().contains("email")) {
            field = new JFormattedTextField();
            ((JFormattedTextField) field).setValue(value);
        } else {

            switch (sqlType) {

                case Types.BIGINT:
                case Types.INTEGER:
                    field = new JFormattedTextField(new NumberFormatter(0));
                    ((JFormattedTextField) field).setValue(value);
                    break;

                case Types.DECIMAL:
                case Types.DOUBLE:
                case Types.FLOAT:
                    field = new JFormattedTextField(new NumberFormatter(2));
                    ((JFormattedTextField) field).setValue(value);
                    break;

                case Types.BLOB:
                case Types.LONGVARCHAR:

                    field = new JTextArea();
                    ((JTextArea) field).setRows(5);
                    ((JTextArea) field).setText(value == null ? "" : value.toString());
                    break;

                case Types.BOOLEAN:
                case Types.TINYINT:
                case Types.SMALLINT:
                case Types.BIT:

                    field = new JCheckBox();

                    if (value != null) {

                        if (value.toString().equalsIgnoreCase("1")
                                || value.toString().equalsIgnoreCase("true")
                                || value.toString().equalsIgnoreCase("yes")
                                || value.toString().equalsIgnoreCase("sim")
                                || value.toString().equalsIgnoreCase("s")) {
                            value = true;
                        }

                        ((JCheckBox) field).setSelected(Boolean.valueOf(value.toString()));
                    }

                    break;

                case Types.DATE:
                    field = new JFormattedTextField(new DateFormatter());
                    ((JFormattedTextField) field).setValue(value);
                    break;

                case Types.TIME:
                    field = new JFormattedTextField(new TimeFormatter());
                    ((JFormattedTextField) field).setValue(value);
                    break;

                case Types.TIMESTAMP:
                    field = new JFormattedTextField(new TimestampFormatter());
                    ((JFormattedTextField) field).setValue(value);
                    break;

                default:
                    field = new JFormattedTextField(new UpperCaseFormatter());
                    ((JFormattedTextField) field).setValue(value);
                    break;
            }
        }

        field.setName(name);

        components.put(name, field);

        return (T) field;
    }

    public void setLabel(String fieldName, String label, boolean notNull) {

        JComponent c = getComponent(fieldName);

        if (c != null) {

            if (c instanceof JCheckBox) {

                ((JCheckBox) c).setText(label);

                if (notNull) {
                    c.setForeground(Color.RED);
                }

            } else {
                c.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(null, " " + (notNull ? "* " : "") + label + " ", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, getComponent(fieldName).getFont().deriveFont(Font.BOLD), notNull ? Color.RED : Color.BLACK), BorderFactory.createEmptyBorder(1, 1, 1, 1)));
            }
        }
    }

    public <T extends JComponent> T getComponent(String name) {

        JComponent c = null;

        if (components.containsKey(name)) {
            c = components.get(name);
        } else if (components.containsKey(name.toUpperCase())) {
            c = components.get(name.toUpperCase());
        } else if (components.containsKey(name.toLowerCase())) {
            c = components.get(name.toLowerCase());
        }

        return (T) c;
    }

    public void setValue(String name, Object value) {

        JComponent c = getComponent(name);

        if (c != null) {

            if (c instanceof AutoCompleteField) {
                AutoCompleteField field = (AutoCompleteField) c;
                field.setValue(value);
            } else if (c instanceof ComboBox) {
                ComboBox field = (ComboBox) c;
                field.setSelectedItem(value);
            } else if (c instanceof JComboBox) {
                JComboBox field = (JComboBox) c;
                field.setSelectedItem(value);
            } else if (c instanceof JCheckBox) {
                JCheckBox field = (JCheckBox) c;
                field.setSelected(value == null ? false : (Boolean) value);
            } else if (c instanceof JTextArea) {
                JTextArea field = (JTextArea) c;
                field.setText(value == null ? "" : value.toString());
            } else if (c instanceof JTextPane) {
                JTextPane field = (JTextPane) c;
                field.setText(value == null ? "" : value.toString());
            } else if (c instanceof JEditorPane) {
                JEditorPane field = (JEditorPane) c;
                field.setText(value == null ? "" : value.toString());
            } else if (c instanceof JFormattedTextField) {

                JFormattedTextField field = (JFormattedTextField) c;

                if (field.getFormatter() == null) {
                    field.setValue(value);
                } else if (!field.getName().toLowerCase().contains("senha") && !field.getFormatter().getClass().isAssignableFrom(PasswordFormatter.class)) {
                    field.setValue(value);
                }

            } else if (c instanceof JTextField) {
                JTextField field = (JTextField) c;
                field.setText(value == null ? "" : value.toString());
            }
        }
    }

    public Object getValue(String name) {

        JComponent c = getComponent(name);

        if (c != null) {

            if (c instanceof AutoCompleteField) {
                AutoCompleteField field = (AutoCompleteField) c;
                return field.getValue();
            } else if (c instanceof ComboBox) {
                ComboBox field = (ComboBox) c;
                return field.getSelectedItem();
            } else if (c instanceof JComboBox) {
                JComboBox field = (JComboBox) c;
                return field.getSelectedItem();
            } else if (c instanceof JCheckBox) {
                JCheckBox field = (JCheckBox) c;
                return field.isSelected();
            } else if (c instanceof JTextArea) {
                JTextArea field = (JTextArea) c;
                return field.getText();
            } else if (c instanceof JTextPane) {
                JTextPane field = (JTextPane) c;
                return field.getText();
            } else if (c instanceof JEditorPane) {
                JEditorPane field = (JEditorPane) c;
                return field.getText();
            } else if (c instanceof JFormattedTextField) {

                JFormattedTextField field = (JFormattedTextField) c;

                if (!field.getText().isEmpty() && (field.getName().toLowerCase().contains("senha") || field.getFormatter().getClass().isAssignableFrom(PasswordFormatter.class))) {
                    try {
                        return Utils.md5(field.getValue().toString());
                    } catch (NoSuchAlgorithmException ex) {
                        return null;
                    }
                } else {
                    return field.getValue();
                }

            } else if (c instanceof JPasswordField) {

                JPasswordField field = (JPasswordField) c;

                if (field.getPassword().length > 0) {
                    try {
                        return Utils.md5(new String(field.getPassword()));
                    } catch (NoSuchAlgorithmException ex) {
                        return null;
                    }
                }

            } else if (c instanceof JTextField) {
                JTextField field = (JTextField) c;
                return field.getText();
            }
        }

        return null;
    }

    public Map<String, Object> getValues() {

        Map<String, Object> values = new HashMap();

        for (String name : components.keySet()) {
            values.put(name, getValue(name));
        }

        return values;
    }

    public void cleanValues() {

        for (String name : components.keySet()) {

            JComponent c = getComponent(name);

            if (c instanceof ComboBox) {
                ((ComboBox) c).setSelectedIndex(0);
                setValue(name, ((ComboBox) c).getSelectedItem());
            } else if (c instanceof JComboBox) {
                ((JComboBox) c).setSelectedIndex(0);
                setValue(name, ((JComboBox) c).getSelectedItem());
            } else {
                setValue(name, null);
            }
        }
    }
}
