package osa.attribute.atgrammar.gui.panels.atgrammar_panels;

import java.util.*;
import java.io.*;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;


import osa.attribute.atgrammar.grammar.*;
import osa.attribute.atgrammar.grammar.symbols.*;

import osa.attribute.atgrammar.gui.file_choosers.*;
/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: </p>
 * <p>Company: </p>
 * @author not attributable
 * @version
 */

public class DictionaryPane
  extends JPanel
  {

  protected class SetEvaluatorBtnActionListener
    implements ActionListener
    {
    public void actionPerformed(ActionEvent e)
      {
      JFileChooser file_chooser=FileChoosersFactory.getClassFileChooser();
      file_chooser.showOpenDialog(ATGrammarTabPane.getInstance());
      File selected_file=file_chooser.getSelectedFile();
      current_selected_symbol.setEvaluatorClassFile(selected_file);
      }
    }

  protected class AddNewBtnActionListener
    implements ActionListener
    {
    public void actionPerformed(ActionEvent e)
      {
      String new_symbol_name=null;
      boolean is_name_invalid=true;

      while(is_name_invalid)
           {
           new_symbol_name=
           JOptionPane.showInputDialog(ATGrammarTabPane.getInstance(),
                                      "Ведите имя нового символа действия",
                                      "Ввод имени",
                                      JOptionPane.INFORMATION_MESSAGE);

           if(new_symbol_name==null)
             {
             break;
             }
           else
             {
             if(new_symbol_name.equals(""))
               {
               JOptionPane.showMessageDialog(ATGrammarTabPane.getInstance(),
                                            "Введите непустое имя, пожалуйста...",
                                            "Ошибка ввода",
                                            JOptionPane.ERROR_MESSAGE);
               continue;
               }
             else
               {
               if(dictionary_reference.putOutputSymbol(new OutputSymbol(new_symbol_name)))
                 {
                 DictionaryPane.this.outputs_lst.setModel(new SymbolsListModel(dictionary_reference.getOutputs()));
                 DictionaryPane.this.repaint();
                 is_name_invalid=false;
                 }
               else
                 {
                 JOptionPane.showMessageDialog(ATGrammarTabPane.getInstance(),
                                              "Символ действия с таким именем уже существует\n"+
                                              "Введите другое имя, пожалуйста...",
                                              "Ошибка ввода",
                                              JOptionPane.ERROR_MESSAGE);
                 continue;
                 }
               }
             }
           }
      }
    }



  protected class RemoveBtnActionListener
    implements ActionListener
    {
    public void actionPerformed(ActionEvent e)
      {
      String symbol_name=current_selected_symbol.toString();
      String symbol_original_name=current_selected_symbol.getOriginalName();
      int dialog_value;

      dialog_value=
      JOptionPane.showConfirmDialog(ATGrammarTabPane.getInstance(),
                                   "Удалить символ действия"+symbol_name+" ?",
                                   "Подтверждение удаления",
                                   JOptionPane.YES_NO_OPTION);
      if(dialog_value==JOptionPane.YES_OPTION)
        {
        dictionary_reference.removeOutputSymbol(symbol_original_name);

        current_selected_symbol=null;

        Grammar.getInstance().updateAssignmentsIndexes();
        Grammar.getInstance().updateProductions();
        Grammar.getInstance().updateAssignmentsLabels();

        update();
        updatePanel();
        repaint();
        }
      }
    }

  protected class RenameBtnActionListener
    implements ActionListener
    {
    public void actionPerformed(ActionEvent e)
      {
      String symbol_name=current_selected_symbol.toString();
      String symbol_original_name=current_selected_symbol.getOriginalName();

      String symbol_type_str;
      switch(current_selected_symbol.getType())
            {
            case Symbol.NON_TERMINAL_SYMBOL:
              symbol_type_str="нетерминального ";
              break;
            case Symbol.TERMINAL_SYMBOL:
              symbol_type_str="терминального ";
              break;
            case Symbol.OUTPUT_SYMBOL:
              symbol_type_str="выходного ";
              break;
            default:
              symbol_type_str="неизвестного :) ";
            }

      String new_symbol_name=null;
      boolean is_name_invalid=true;




      while(is_name_invalid)
           {
           new_symbol_name=
           JOptionPane.showInputDialog(ATGrammarTabPane.getInstance(),
                                      "Ведите новое имя для "+symbol_type_str+"символа "+ symbol_original_name+":",
                                      "Переименование символа",
                                      JOptionPane.INFORMATION_MESSAGE);
           if(new_symbol_name==null)
             {
             break;
             }
           else
             {
             if(new_symbol_name.equals(""))
               {
               JOptionPane.showMessageDialog(ATGrammarTabPane.getInstance(),
                                            "Введите непустое имя, пожалуйста...",
                                            "Ошибка ввода",
                                            JOptionPane.ERROR_MESSAGE);
               continue;
               }
             else
               {
               if(dictionary_reference.renameSymbol(current_selected_symbol,new_symbol_name))
                 {
                 DictionaryPane.this.outputs_lst.setModel(new SymbolsListModel(dictionary_reference.getOutputs()));

                 Grammar.getInstance().updateProductions();
                 Grammar.getInstance().updateAssignmentsLabels();
                 getATGrammarPane().getATGrammarEditorPane().update();

                 DictionaryPane.this.repaint();
                 is_name_invalid=false;
                 }
               else
                 {
                 JOptionPane.showMessageDialog(ATGrammarTabPane.getInstance(),
                                              "Символ с этим именем уже существует\n"+
                                              "Введите другое имя, пожалуйста...",
                                              "Ошибка ввода",
                                              JOptionPane.ERROR_MESSAGE);
                 continue;
                 }
               }
             }
           }
      }
    }


  protected class NonTerminalsListSelectionListener
    implements ListSelectionListener
    {
    public void valueChanged(ListSelectionEvent e)
      {
      JList source_list=(JList)e.getSource();

      int selected_index=source_list.getSelectedIndex();

      if(selected_index>-1)
        {
        current_selected_symbol=(Symbol)source_list.getSelectedValue();

        non_terminal_symbol_selected=true;

        terminals_lst.clearSelection();
        outputs_lst.clearSelection();
        updatePanel();
        }
      else
        {
        non_terminal_symbol_selected=false;
        }
      }
    }

  protected class TerminalsListSelectionListener
    implements ListSelectionListener
    {
    public void valueChanged(ListSelectionEvent e)
      {
      JList source_list=(JList)e.getSource();
      int selected_index=source_list.getSelectedIndex();
      if(selected_index>-1)
        {
        current_selected_symbol=(Symbol)source_list.getSelectedValue();

        terminal_symbol_selected=true;

        non_terminals_lst.clearSelection();
        outputs_lst.clearSelection();
        updatePanel();
        }
      else
        {
        terminal_symbol_selected=false;
        }
      }
    }

  protected class OutputsListSelectionListener
    implements ListSelectionListener
    {
    public void valueChanged(ListSelectionEvent e)
      {
      JList source_list=(JList)e.getSource();
      int selected_index=source_list.getSelectedIndex();

      if(source_list.getSelectedIndex()>-1)
        {
        current_selected_symbol=(Symbol)source_list.getSelectedValue();

        output_symbol_selected=true;

        non_terminals_lst.clearSelection();
        terminals_lst.clearSelection();
        updatePanel();
        }
      else
        {
        output_symbol_selected=false;
        }
      }
    }


  protected class NonTerminalsListFocusListener
    implements FocusListener
    {
    public void focusGained(FocusEvent e)
      {
      non_terminals_list_selected=true;
      terminals_list_selected=false;
      outputs_list_selected=false;

      terminals_lst.clearSelection();
      outputs_lst.clearSelection();
      updatePanel();
      }
    public void focusLost(FocusEvent e)
      {
      }
    }

  protected class TerminalsListFocusListener
    implements FocusListener
    {
    public void focusGained(FocusEvent e)
      {
      non_terminals_list_selected=false;
      terminals_list_selected=true;
      outputs_list_selected=false;

      non_terminals_lst.clearSelection();
      outputs_lst.clearSelection();
      updatePanel();
      }

    public void focusLost(FocusEvent e)
      {
      }
    }

  protected class OutputsListFocusListener
    implements FocusListener
    {
    public void focusGained(FocusEvent e)
      {
      non_terminals_list_selected=false;
      terminals_list_selected=false;
      outputs_list_selected=true;

      non_terminals_lst.clearSelection();
      terminals_lst.clearSelection();
      updatePanel();
      }

    public void focusLost(FocusEvent e)
      {
      }
    }

  protected class SymbolsListModel
    extends AbstractListModel
    {
    protected ArrayList list_model;

    public SymbolsListModel(Collection dictionary)
      {
      list_model=new ArrayList(dictionary);

      System.err.println("Model"+list_model.toString());
      }

    public int getSize()
      {
      return list_model.size();
      }

    public Object getElementAt(int index)
      {
      return list_model.get(index);
      }
    }

  protected class SymbolsListRenderer
    implements ListCellRenderer
    {
    public Component getListCellRendererComponent
      (
      JList list,
      Object value,
      int index,
      boolean isSelected,
      boolean cellHasFocus)
      {
      JLabel result_component=new JLabel("");

      if(isSelected)
        {
        result_component.setForeground(Color.white);
        result_component.setBackground(Color.blue);
        }
      else
        {
        result_component.setForeground(Color.BLACK);
        result_component.setBackground(Color.WHITE);
        }

      if( value!=null && value instanceof Symbol)
        {
        result_component.setText(((Symbol)value).getOriginalName());
        }

      return result_component;
      }
    }

  private Symbol current_selected_symbol=null;

  public Symbol getSelectedSymbol()
    {
    return current_selected_symbol;
    }

  // Lists
  JList non_terminals_lst = new JList();
  JList terminals_lst = new JList();
  JList outputs_lst = new JList();

  // Scroll panes
  JScrollPane non_terminals_scrlpn=new JScrollPane();
  JScrollPane terminals_scrlpn=new JScrollPane();
  JScrollPane outputs_scrlpn=new JScrollPane();

  // Buttons
  JButton add_new_btn = new JButton();
  JButton remove_btn = new JButton();
  JButton rename_btn = new JButton();
  JButton properties_btn = new JButton();
  JButton set_evaluator_btn = new JButton();

  // Labels
  JLabel non_terminals_lbl = new JLabel();
  JLabel terminals_lbl = new JLabel();
  JLabel evaluator_class_lbl = new JLabel();
  JLabel outputs_lbl = new JLabel();

  // panels
  JPanel buttons_panel = new JPanel();
  JPanel jPanel1 = new JPanel();


  // Layouts
  GridLayout gridLayout1 = new GridLayout();
  GridBagLayout gridBagLayout1 = new GridBagLayout();
  GridBagLayout gridBagLayout2 = new GridBagLayout();

  // Text fields
  JTextField evaluator_class_txfld = new JTextField();


  // panel model

  CommonDictionary dictionary_reference;


  protected boolean terminals_list_selected=false;
  protected boolean non_terminals_list_selected=false;
  protected boolean outputs_list_selected=false;

  protected boolean terminal_symbol_selected=false;
  protected boolean non_terminal_symbol_selected=false;
  protected boolean output_symbol_selected=false;



  public DictionaryPane(CommonDictionary dictionary_reference)
    {

    this.dictionary_reference=dictionary_reference;


    SymbolsListRenderer list_renderer=new SymbolsListRenderer();

    non_terminals_lst.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    terminals_lst.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    outputs_lst.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

    non_terminals_lst.addListSelectionListener(new NonTerminalsListSelectionListener());
    terminals_lst.addListSelectionListener(new TerminalsListSelectionListener());
    outputs_lst.addListSelectionListener(new OutputsListSelectionListener());

    non_terminals_lst.addFocusListener(new NonTerminalsListFocusListener());
    terminals_lst.addFocusListener(new TerminalsListFocusListener());
    outputs_lst.addFocusListener(new OutputsListFocusListener());

//    non_terminals_lst.setCellRenderer(list_renderer);
//    terminals_lst.setCellRenderer(list_renderer);
//    outputs_lst.setCellRenderer(list_renderer);

    add_new_btn.addActionListener(new AddNewBtnActionListener());
    remove_btn.addActionListener( new RemoveBtnActionListener());
    rename_btn.addActionListener( new RenameBtnActionListener());


    set_evaluator_btn.addActionListener(new SetEvaluatorBtnActionListener());

    evaluator_class_txfld.setEditable(false);

    add_new_btn.setEnabled(false);
    properties_btn.setEnabled(false);
    rename_btn.setEnabled(false);
    remove_btn.setEnabled(false);
    set_evaluator_btn.setEnabled(false);


    update();

    try
      {
      jbInit();
      }
    catch(Exception e)
      {
      e.printStackTrace();
      }
    }

  private void jbInit()
    throws Exception
    {
    this.setLayout(gridBagLayout1);
    add_new_btn.setText("Добавить");
    remove_btn.setText("Удалить");
    rename_btn.setText("Переименовать");
    properties_btn.setText("Свойства");
    non_terminals_lbl.setText("Нетерминалы:");
    terminals_lbl.setText("Терминалы:");
    outputs_lbl.setText("Выходные:");
    buttons_panel.setLayout(gridLayout1);
    gridLayout1.setColumns(4);
    gridLayout1.setHgap(5);
    gridLayout1.setRows(1);
    gridLayout1.setVgap(5);
    evaluator_class_lbl.setText("Класс-обработчик символа:");
    jPanel1.setLayout(gridBagLayout2);
    evaluator_class_txfld.setText("");
    set_evaluator_btn.setText("Задать...");

    non_terminals_scrlpn.setViewportView(non_terminals_lst);
    terminals_scrlpn.setViewportView(terminals_lst);
    outputs_scrlpn.setViewportView(outputs_lst);

    this.add(buttons_panel,     new GridBagConstraints(0, 2, 3, 1, 1.0, 0.0
            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
    buttons_panel.add(add_new_btn, null);
    buttons_panel.add(remove_btn, null);
    buttons_panel.add(rename_btn, null);
    buttons_panel.add(properties_btn, null);

    this.add(non_terminals_scrlpn,    new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0
            ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
    this.add(outputs_scrlpn,    new GridBagConstraints(2, 1, 1, 1, 1.0, 1.0
            ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
    this.add(terminals_scrlpn,     new GridBagConstraints(1, 1, 1, 1, 1.0, 1.0
            ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
    this.add(outputs_lbl,      new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
    this.add(terminals_lbl,     new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
    this.add(non_terminals_lbl,    new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
    this.add(jPanel1,        new GridBagConstraints(0, 3, 3, 1, 1.0, 0.0
            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
    jPanel1.add(evaluator_class_txfld,              new GridBagConstraints(0, 1, 1, 1, 1.0, 0.0
            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
    jPanel1.add(evaluator_class_lbl,    new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST, GridBagConstraints.VERTICAL, new Insets(5, 5, 0, 5), 0, 0));
    jPanel1.add(set_evaluator_btn, new GridBagConstraints(1, 1, 1, 1, 0.1, 0.0
            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
  }

  public void update()
    {

    non_terminals_lst.setModel(new SymbolsListModel(dictionary_reference.getNonTerminals()));
    terminals_lst.setModel(new SymbolsListModel(dictionary_reference.getTerminals()));
    outputs_lst.setModel(new SymbolsListModel(dictionary_reference.getOutputs()));
    selectCurrentSymbol();
    }

  public void selectCurrentSymbol()
    {
    if(current_selected_symbol!=null)
      {
      switch(current_selected_symbol.getType())
            {
            case Symbol.NON_TERMINAL_SYMBOL:
              non_terminals_lst.setSelectedValue(current_selected_symbol,true);
              break;
            case Symbol.TERMINAL_SYMBOL:
              terminals_lst.setSelectedValue(current_selected_symbol,true);
              break;
            case Symbol.OUTPUT_SYMBOL:
              outputs_lst.setSelectedValue(current_selected_symbol,true);
              break;
            default:
            }
      }

    }

  ATGrammarPane at_grammar_pane=null;
  protected ATGrammarPane getATGrammarPane()
    {
    if(at_grammar_pane==null)
      {
      at_grammar_pane=ATGrammarTabPane.getInstance().getATGrammarPane();
      }
    return at_grammar_pane;
    }

  protected void updateAttributesPane()
    {
    getATGrammarPane().getAttributesPane().setSymbolToView(current_selected_symbol);
    }

  protected void updatePanel()
    {
    if(non_terminals_list_selected)
      {
      add_new_btn.setEnabled(false);
      remove_btn.setEnabled(false);
      properties_btn.setEnabled(false);

      rename_btn.setEnabled(non_terminal_symbol_selected);
      set_evaluator_btn.setEnabled(non_terminal_symbol_selected);

      if(!non_terminal_symbol_selected)
        {
        current_selected_symbol=null;
        }
      }
    else
      {
      if(terminals_list_selected)
        {
        add_new_btn.setEnabled(false);
        remove_btn.setEnabled(false);

        rename_btn.setEnabled(terminal_symbol_selected);
        set_evaluator_btn.setEnabled(terminal_symbol_selected);
        properties_btn.setEnabled(terminal_symbol_selected);

        if(!terminal_symbol_selected)
          {
          current_selected_symbol=null;
          }
        }
      else
        {
        if(outputs_list_selected)
          {
          add_new_btn.setEnabled(true);
          properties_btn.setEnabled(false);

          rename_btn.setEnabled(output_symbol_selected);
          remove_btn.setEnabled(output_symbol_selected);
          set_evaluator_btn.setEnabled(output_symbol_selected);

          if(!output_symbol_selected)
            {
            current_selected_symbol=null;
            }
          }
        else
          {
          add_new_btn.setEnabled(false);
          properties_btn.setEnabled(false);
          rename_btn.setEnabled(false);
          remove_btn.setEnabled(false);
          set_evaluator_btn.setEnabled(false);

          current_selected_symbol=null;

          }
        }
      }



    non_terminals_lbl.setForeground(getLabelColor(non_terminals_list_selected));
    terminals_lbl.setForeground(getLabelColor(terminals_list_selected));
    outputs_lbl.setForeground(getLabelColor(outputs_list_selected));

    updateAttributesPane();
    repaint();
    }

  protected Color getLabelColor(boolean is_selected)
    {
    if(is_selected==true)
      {
      return Color.red;
      }
    return Color.black;
    }

  }