/*
 *   Copyright (C) 2014  Alfons Wirtz
 *   website www.freerouting.net
 *
 *   Copyright (C) 2017 Michael Hoffer <info@michaelhoffer.de>
 *   Website www.freerouting.mihosoft.eu
*
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License at <http://www.gnu.org/licenses/> 
 *   for more details.
 *
 * WindowAutorouteDetailParameter.java
 *
 * Created on 25. Juli 2006, 08:17
 *
 */
package eu.mihosoft.freerouting.gui;

import java.text.DecimalFormat;

/**
 *
 * @author Alfons Wirtz
 */
public class WindowAutorouteDetailParameter extends BoardSavableSubWindow
{

    /** Creates a new instance of WindowAutorouteDetailParameter */
    public WindowAutorouteDetailParameter(BoardFrame p_board_frame)
    {
        this.board_handling = p_board_frame.board_panel.board_handling;
        java.util.ResourceBundle resources =
                java.util.ResourceBundle.getBundle("eu.mihosoft.freerouting.gui.WindowAutorouteParameter", p_board_frame.get_locale());
        this.setTitle(resources.getString("detail_autoroute_parameter"));

        // create main panel

        final javax.swing.JPanel main_panel = new javax.swing.JPanel();
        getContentPane().add(main_panel);
        java.awt.GridBagLayout gridbag = new java.awt.GridBagLayout();
        main_panel.setLayout(gridbag);
        java.awt.GridBagConstraints gridbag_constraints = new java.awt.GridBagConstraints();
        gridbag_constraints.anchor = java.awt.GridBagConstraints.WEST;
        gridbag_constraints.insets = new java.awt.Insets(5, 10, 5, 10);

        // add label and number field for the via costs.

        gridbag_constraints.gridwidth = 2;
        javax.swing.JLabel via_cost_label = new javax.swing.JLabel(resources.getString("via_costs"));
        gridbag.setConstraints(via_cost_label, gridbag_constraints);
        main_panel.add(via_cost_label);

        java.text.NumberFormat number_format = java.text.NumberFormat.getIntegerInstance(p_board_frame.get_locale());
        this.via_cost_field = new javax.swing.JFormattedTextField(number_format);
        this.via_cost_field.setColumns(3);
        this.via_cost_field.addKeyListener(new ViaCostFieldKeyListener());
        this.via_cost_field.addFocusListener(new ViaCostFieldFocusListener());
        gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridbag.setConstraints(via_cost_field, gridbag_constraints);
        main_panel.add(via_cost_field);

        this.plane_via_cost_field = new javax.swing.JFormattedTextField(number_format);
        this.plane_via_cost_field.setColumns(3);
        this.plane_via_cost_field.addKeyListener(new PlaneViaCostFieldKeyListener());
        this.plane_via_cost_field.addFocusListener(new PlaneViaCostFieldFocusListener());

        gridbag_constraints.gridwidth = 2;
        javax.swing.JLabel plane_via_cost_label = new javax.swing.JLabel(resources.getString("plane_via_costs"));
        gridbag.setConstraints(plane_via_cost_label, gridbag_constraints);
        main_panel.add(plane_via_cost_label);
        gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridbag.setConstraints(plane_via_cost_field, gridbag_constraints);
        main_panel.add(plane_via_cost_field);

        // add label and number field for the start pass no.

        gridbag_constraints.gridwidth = 2;
        javax.swing.JLabel start_pass_label = new javax.swing.JLabel(resources.getString("start_pass"));
        gridbag.setConstraints(start_pass_label, gridbag_constraints);
        main_panel.add(start_pass_label);

        start_pass_no = new javax.swing.JFormattedTextField(number_format);
        start_pass_no.setColumns(5);
        this.start_pass_no.addKeyListener(new StartPassFieldKeyListener());
        this.start_pass_no.addFocusListener(new StartPassFieldFocusListener());
        gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridbag.setConstraints(start_pass_no, gridbag_constraints);
        main_panel.add(start_pass_no);

        // add label and number field for the start ripup costs.

        gridbag_constraints.gridwidth = 2;
        javax.swing.JLabel start_ripup_costs_label = new javax.swing.JLabel();
        start_ripup_costs_label.setText(resources.getString("start_ripup_costs"));
        gridbag.setConstraints(start_ripup_costs_label, gridbag_constraints);
        main_panel.add(start_ripup_costs_label);

        start_ripup_costs = new javax.swing.JFormattedTextField(number_format);
        start_ripup_costs.setColumns(3);
        this.start_ripup_costs.addKeyListener(new StartRipupCostFieldKeyListener());
        this.start_ripup_costs.addFocusListener(new StartRipupCostFieldFocusListener());
        gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridbag.setConstraints(start_ripup_costs, gridbag_constraints);
        main_panel.add(start_ripup_costs);



        // add label and combo box for the router speed (if the speed is set to slow, free angle geometry
        // is used also in the 45 and 90 degree modes.
        this.speed_fast = resources.getString("fast");
        this.speed_slow = resources.getString("slow");
        speed_combo_box = new javax.swing.JComboBox();
        speed_combo_box.addItem(this.speed_fast);
        speed_combo_box.addItem(this.speed_slow);
        speed_combo_box.addActionListener(new SpeedListener());

        if (this.board_handling.get_routing_board().get_test_level() != eu.mihosoft.freerouting.board.TestLevel.RELEASE_VERSION)
        {
            gridbag_constraints.gridwidth = 2;
            javax.swing.JLabel speed_label = new javax.swing.JLabel();
            speed_label.setText(resources.getString("speed"));
            gridbag.setConstraints(speed_label, gridbag_constraints);
            main_panel.add(speed_label);

            gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
            gridbag.setConstraints(speed_combo_box, gridbag_constraints);
            main_panel.add(speed_combo_box);
        }


        javax.swing.JLabel separator = new javax.swing.JLabel("----------------------------------------------------------------  ");
        gridbag.setConstraints(separator, gridbag_constraints);
        main_panel.add(separator, gridbag_constraints);

        // add label and number field for the trace costs on each layer.

        gridbag_constraints.gridwidth = 3;
        javax.swing.JLabel layer_label = new javax.swing.JLabel(resources.getString("trace_costs_on_layer"));
        gridbag.setConstraints(layer_label, gridbag_constraints);
        main_panel.add(layer_label);

        javax.swing.JLabel pref_dir_label = new javax.swing.JLabel(resources.getString("in_preferred_direction"));
        gridbag.setConstraints(pref_dir_label, gridbag_constraints);
        main_panel.add(pref_dir_label);

        gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        javax.swing.JLabel against_pref_dir_label = new javax.swing.JLabel(resources.getString("against_preferred_direction"));
        gridbag.setConstraints(against_pref_dir_label, gridbag_constraints);
        main_panel.add(against_pref_dir_label);

        eu.mihosoft.freerouting.board.LayerStructure layer_structure = this.board_handling.get_routing_board().layer_structure;
        int signal_layer_count = layer_structure.signal_layer_count();
        layer_name_arr = new javax.swing.JLabel[signal_layer_count];
        preferred_direction_trace_cost_arr = new javax.swing.JFormattedTextField[signal_layer_count];
        against_preferred_direction_trace_cost_arr = new javax.swing.JFormattedTextField[signal_layer_count];
        preferred_direction_trace_costs_input_completed = new boolean[signal_layer_count];
        against_preferred_direction_trace_costs_input_completed = new boolean[signal_layer_count];
        number_format = java.text.NumberFormat.getInstance(p_board_frame.get_locale());
        number_format.setMaximumFractionDigits(2);
        final int TEXT_FIELD_LENGTH = 2;
        java.text.NumberFormat float_number_format = new DecimalFormat("0.0");
        for (int i = 0; i < signal_layer_count; ++i)
        {
            layer_name_arr[i] = new javax.swing.JLabel();
            eu.mihosoft.freerouting.board.Layer curr_signal_layer = layer_structure.get_signal_layer(i);
            layer_name_arr[i].setText(curr_signal_layer.name);
            gridbag_constraints.gridwidth = 3;
            gridbag.setConstraints(layer_name_arr[i], gridbag_constraints);
            main_panel.add(layer_name_arr[i]);
            preferred_direction_trace_cost_arr[i] = new javax.swing.JFormattedTextField(float_number_format);
            preferred_direction_trace_cost_arr[i].setColumns(TEXT_FIELD_LENGTH);
            preferred_direction_trace_cost_arr[i].addKeyListener(new PreferredDirectionTraceCostKeyListener(i));
            preferred_direction_trace_cost_arr[i].addFocusListener(new PreferredDirectionTraceCostFocusListener(i));
            gridbag.setConstraints(preferred_direction_trace_cost_arr[i], gridbag_constraints);
            main_panel.add(preferred_direction_trace_cost_arr[i]);
            against_preferred_direction_trace_cost_arr[i] = new javax.swing.JFormattedTextField(float_number_format);
            against_preferred_direction_trace_cost_arr[i].setColumns(TEXT_FIELD_LENGTH);
            against_preferred_direction_trace_cost_arr[i].addKeyListener(new AgainstPreferredDirectionTraceCostKeyListener(i));
            against_preferred_direction_trace_cost_arr[i].addFocusListener(new AgainstPreferredDirectionTraceCostFocusListener(i));
            gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
            gridbag.setConstraints(against_preferred_direction_trace_cost_arr[i], gridbag_constraints);
            main_panel.add(against_preferred_direction_trace_cost_arr[i]);
            preferred_direction_trace_costs_input_completed[i] = true;
            against_preferred_direction_trace_costs_input_completed[i] = true;
        }

        javax.swing.JLabel applyValuesNote = new javax.swing.JLabel("(note: you need to press Enter to apply the new values)");
        gridbag.setConstraints(applyValuesNote, gridbag_constraints);
        main_panel.add(applyValuesNote, gridbag_constraints);


        p_board_frame.set_context_sensitive_help(this, "WindowAutorouteDetailParameter");

        this.refresh();
        this.pack();
        this.setResizable(false);
    }

    /**
     * Recalculates all displayed values
     */
    public void refresh()
    {
        eu.mihosoft.freerouting.interactive.AutorouteSettings settings = this.board_handling.settings.autoroute_settings;
        eu.mihosoft.freerouting.board.LayerStructure layer_structure = this.board_handling.get_routing_board().layer_structure;
        this.via_cost_field.setValue(settings.get_via_costs());
        this.plane_via_cost_field.setValue(settings.get_plane_via_costs());
        this.start_ripup_costs.setValue(settings.get_start_ripup_costs());
        this.start_pass_no.setValue(settings.get_start_pass_no());
        for (int i = 0; i < preferred_direction_trace_cost_arr.length; ++i)
        {
            this.preferred_direction_trace_cost_arr[i].setValue(settings.get_preferred_direction_trace_costs(layer_structure.get_layer_no(i)));
        }
        for (int i = 0; i < against_preferred_direction_trace_cost_arr.length; ++i)
        {
            this.against_preferred_direction_trace_cost_arr[i].setValue(settings.get_against_preferred_direction_trace_costs(layer_structure.get_layer_no(i)));
        }
    }
    private final eu.mihosoft.freerouting.interactive.BoardHandling board_handling;
    private final javax.swing.JFormattedTextField via_cost_field;
    private final javax.swing.JFormattedTextField plane_via_cost_field;
    private final javax.swing.JFormattedTextField start_ripup_costs;
    private final javax.swing.JFormattedTextField start_pass_no;
    private final javax.swing.JComboBox speed_combo_box;
    private final String speed_fast;
    private final String speed_slow;
    private final javax.swing.JLabel[] layer_name_arr;
    private final javax.swing.JFormattedTextField[] preferred_direction_trace_cost_arr;
    private final javax.swing.JFormattedTextField[] against_preferred_direction_trace_cost_arr;
    private boolean via_cost_input_completed = true;
    private boolean plane_via_cost_input_completed = true;
    private boolean start_ripup_cost_input_completed = true;
    private final boolean[] preferred_direction_trace_costs_input_completed;
    private final boolean[] against_preferred_direction_trace_costs_input_completed;

    private class ViaCostFieldKeyListener extends java.awt.event.KeyAdapter
    {

        public void keyTyped(java.awt.event.KeyEvent p_evt)
        {
            if (p_evt.getKeyChar() == '\n')
            {
                int old_value = board_handling.settings.autoroute_settings.get_via_costs();
                Object input = via_cost_field.getValue();
                int input_value;
                if (input instanceof Number)
                {
                    input_value = ((Number) input).intValue();
                    if (input_value <= 0)
                    {
                        input_value = 1;
                        via_cost_field.setValue(input_value);
                    }
                } else
                {
                    input_value = old_value;
                    via_cost_field.setValue(old_value);
                }
                board_handling.settings.autoroute_settings.set_via_costs(input_value);
                via_cost_field.setValue(input_value);
                via_cost_input_completed = true;

            } else
            {
                via_cost_input_completed = false;
            }
        }
    }

    private class ViaCostFieldFocusListener implements java.awt.event.FocusListener
    {

        public void focusLost(java.awt.event.FocusEvent p_evt)
        {
            if (!via_cost_input_completed)
            {
                via_cost_input_completed = true;
                refresh();
            }
        }

        public void focusGained(java.awt.event.FocusEvent p_evt)
        {
        }
    }

    private class PlaneViaCostFieldKeyListener extends java.awt.event.KeyAdapter
    {

        public void keyTyped(java.awt.event.KeyEvent p_evt)
        {
            if (p_evt.getKeyChar() == '\n')
            {
                int old_value = board_handling.settings.autoroute_settings.get_plane_via_costs();
                Object input = plane_via_cost_field.getValue();
                int input_value;
                if (input instanceof Number)
                {
                    input_value = ((Number) input).intValue();
                    if (input_value <= 0)
                    {
                        input_value = 1;
                        plane_via_cost_field.setValue(input_value);
                    }
                } else
                {
                    input_value = old_value;
                    plane_via_cost_field.setValue(old_value);
                }
                board_handling.settings.autoroute_settings.set_plane_via_costs(input_value);
                plane_via_cost_field.setValue(input_value);
                plane_via_cost_input_completed = true;

            } else
            {
                plane_via_cost_input_completed = false;
            }
        }
    }

    private class PlaneViaCostFieldFocusListener implements java.awt.event.FocusListener
    {

        public void focusLost(java.awt.event.FocusEvent p_evt)
        {
            if (!plane_via_cost_input_completed)
            {
                plane_via_cost_input_completed = true;
                refresh();
            }
        }

        public void focusGained(java.awt.event.FocusEvent p_evt)
        {
        }
    }

    private class StartRipupCostFieldKeyListener extends java.awt.event.KeyAdapter
    {

        public void keyTyped(java.awt.event.KeyEvent p_evt)
        {
            if (p_evt.getKeyChar() == '\n')
            {
                int old_value = board_handling.settings.autoroute_settings.get_start_ripup_costs();
                Object input = start_ripup_costs.getValue();
                int input_value;
                if (input instanceof Number)
                {
                    input_value = ((Number) input).intValue();
                    if (input_value <= 0)
                    {
                        input_value = 1;
                    }
                } else
                {
                    input_value = old_value;
                }
                board_handling.settings.autoroute_settings.set_start_ripup_costs(input_value);
                start_ripup_costs.setValue(input_value);
                start_ripup_cost_input_completed = true;
            } else
            {
                start_ripup_cost_input_completed = false;
            }
        }
    }

    private class StartRipupCostFieldFocusListener implements java.awt.event.FocusListener
    {

        public void focusLost(java.awt.event.FocusEvent p_evt)
        {
            if (!start_ripup_cost_input_completed)
            {
                start_ripup_cost_input_completed = true;
                refresh();
            }
        }

        public void focusGained(java.awt.event.FocusEvent p_evt)
        {
        }
    }

    private class StartPassFieldKeyListener extends java.awt.event.KeyAdapter
    {

        public void keyTyped(java.awt.event.KeyEvent p_evt)
        {
            if (p_evt.getKeyChar() == '\n')
            {
                int old_value = board_handling.settings.autoroute_settings.get_start_pass_no();
                Object input = start_pass_no.getValue();
                int input_value;
                if (input instanceof Number)
                {
                    input_value = ((Number) input).intValue();
                    if (input_value < 1)
                    {
                        input_value = 1;
                    }
                    if (input_value > 99)
                    {
                        input_value = 99;
                    }
                } else
                {
                    input_value = old_value;
                }

                set_start_pass_no(input_value);
            }
        }
    }

    public void set_start_pass_no(int input_value)
    {
        board_handling.settings.autoroute_settings.set_start_pass_no(input_value);
        start_pass_no.setValue(input_value);
    }

    public void set_stop_pass_no(int input_value)
    {
        board_handling.settings.autoroute_settings.set_stop_pass_no(input_value);
    }

    private class StartPassFieldFocusListener implements java.awt.event.FocusListener
    {

        public void focusLost(java.awt.event.FocusEvent p_evt)
        {
            if (!start_ripup_cost_input_completed)
            {
                refresh();
            }
        }

        public void focusGained(java.awt.event.FocusEvent p_evt)
        {
        }
    }

    private class SpeedListener implements java.awt.event.ActionListener
    {

        public void actionPerformed(java.awt.event.ActionEvent p_evt)
        {
            boolean old_is_slow = board_handling.get_routing_board().rules.get_slow_autoroute_algorithm();
            boolean new_is_slow = speed_combo_box.getSelectedItem() == speed_slow;
            if (old_is_slow != new_is_slow)
            {
                board_handling.get_routing_board().rules.set_slow_autoroute_algorithm(new_is_slow);
                board_handling.get_routing_board().search_tree_manager.reset_compensated_trees();
            }
        }
    }

    private class PreferredDirectionTraceCostKeyListener extends java.awt.event.KeyAdapter
    {

        public PreferredDirectionTraceCostKeyListener(int p_layer_no)
        {
            this.signal_layer_no = p_layer_no;
        }

        public void keyTyped(java.awt.event.KeyEvent p_evt)
        {
            if (p_evt.getKeyChar() == '\n')
            {
                int curr_layer_no = board_handling.get_routing_board().layer_structure.get_layer_no(this.signal_layer_no);
                double old_value = board_handling.settings.autoroute_settings.get_preferred_direction_trace_costs(curr_layer_no);
                Object input = preferred_direction_trace_cost_arr[this.signal_layer_no].getValue();
                double input_value;
                if (input instanceof Number)
                {
                    input_value = ((Number) input).doubleValue();
                    if (input_value <= 0)
                    {
                        input_value = old_value;
                    }
                } else
                {
                    input_value = old_value;
                }
                board_handling.settings.autoroute_settings.set_preferred_direction_trace_costs(curr_layer_no, input_value);
                preferred_direction_trace_cost_arr[this.signal_layer_no].setValue(input_value);
                preferred_direction_trace_costs_input_completed[this.signal_layer_no] = true;

            } else
            {
                preferred_direction_trace_costs_input_completed[this.signal_layer_no] = false;
            }
        }
        private final int signal_layer_no;
    }

    private class PreferredDirectionTraceCostFocusListener implements java.awt.event.FocusListener
    {

        public PreferredDirectionTraceCostFocusListener(int p_layer_no)
        {
            this.signal_layer_no = p_layer_no;
        }

        public void focusLost(java.awt.event.FocusEvent p_evt)
        {
            if (!preferred_direction_trace_costs_input_completed[this.signal_layer_no])
            {
                start_ripup_cost_input_completed = true;
                refresh();
            }
        }

        public void focusGained(java.awt.event.FocusEvent p_evt)
        {
        }
        private final int signal_layer_no;
    }

    private class AgainstPreferredDirectionTraceCostKeyListener extends java.awt.event.KeyAdapter
    {

        public AgainstPreferredDirectionTraceCostKeyListener(int p_layer_no)
        {
            this.signal_layer_no = p_layer_no;
        }

        public void keyTyped(java.awt.event.KeyEvent p_evt)
        {
            if (p_evt.getKeyChar() == '\n')
            {
                int curr_layer_no = board_handling.get_routing_board().layer_structure.get_layer_no(this.signal_layer_no);
                double old_value = board_handling.settings.autoroute_settings.get_against_preferred_direction_trace_costs(curr_layer_no);
                Object input = against_preferred_direction_trace_cost_arr[this.signal_layer_no].getValue();
                double input_value;
                if (input instanceof Number)
                {
                    input_value = ((Number) input).doubleValue();
                    if (input_value <= 0)
                    {
                        input_value = old_value;
                    }
                } else
                {
                    input_value = old_value;
                }
                board_handling.settings.autoroute_settings.set_against_preferred_direction_trace_costs(curr_layer_no, input_value);
                against_preferred_direction_trace_cost_arr[this.signal_layer_no].setValue(input_value);
                against_preferred_direction_trace_costs_input_completed[this.signal_layer_no] = true;

            } else
            {
                against_preferred_direction_trace_costs_input_completed[this.signal_layer_no] = false;
            }
        }
        private final int signal_layer_no;
    }

    private class AgainstPreferredDirectionTraceCostFocusListener implements java.awt.event.FocusListener
    {

        public AgainstPreferredDirectionTraceCostFocusListener(int p_layer_no)
        {
            this.signal_layer_no = p_layer_no;
        }

        public void focusLost(java.awt.event.FocusEvent p_evt)
        {
            if (!against_preferred_direction_trace_costs_input_completed[this.signal_layer_no])
            {
                start_ripup_cost_input_completed = true;
                refresh();
            }
        }

        public void focusGained(java.awt.event.FocusEvent p_evt)
        {
        }
        private final int signal_layer_no;
    }
}
