import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import Jama.*;

public class InputPanel extends JPanel {

  private JTextField accuracyField = new JTextField(5);
  private JTextField matrixXoCols = new JTextField(3);
  private JTextField matrixXoRows = new JTextField(3);
  private JTextField matrixACols = new JTextField(3);
  private JTextField matrixARows = new JTextField(3);
  private JTextField matrixBCols = new JTextField(3);
  private JTextField matrixBRows = new JTextField(3);
  private JTextField tempTextField = new JTextField(3);
  private JTextArea matrixInput = new JTextArea(100,50);
  private JButton calculateButton = new JButton("Calculate"); 
  private JButton applyButton = new JButton("Apply");
  private JButton resetButton = new JButton("Reset");
  private JButton randomButton = new JButton("Random 10x10");
  private JTable matrixXo;
  private JTable matrixA;
  private JTable matrixB;
  private JPanel matrixXoInputPanel = new JPanel();
  private JPanel matrixAInputPanel = new JPanel();
  private JPanel matrixBInputPanel = new JPanel();
  private JPanel matrixInputPanel = new JPanel();
  private JScrollPane sPane;
  private JTextField[][] matrixXoArray1;
  private JTextField[][] matrixAArray1;
  private JTextField[][] matrixBArray1;
  private static double[][] matrixXoArray;
  private static double[][] matrixAArray;
  private static double[][] matrixBArray;
  private static int accuracy;
  
  public InputPanel() {

    JPanel accuracyPanel = new JPanel();
      accuracyPanel.setLayout(new FlowLayout());
      accuracyPanel.add(new JLabel("Accuracy: 10^"));
      accuracyPanel.add(accuracyField);
    
    JPanel matrixPanelXo = new JPanel();
      matrixPanelXo.setLayout(new GridLayout(2,2));
      matrixPanelXo.setBorder (BorderFactory.createTitledBorder ("Matrix Xo"));
      matrixPanelXo.add (new JLabel ("Rows:"));
      matrixPanelXo.add (matrixXoRows);
      matrixPanelXo.add (new JLabel ("Cols:"));
      matrixPanelXo.add (matrixXoCols);
        
    JPanel matrixPanelA = new JPanel();
      matrixPanelA.setLayout(new GridLayout(2,2));
      matrixPanelA.setBorder (BorderFactory.createTitledBorder ("Matrix A"));
      matrixPanelA.add (new JLabel ("Rows:"));
      matrixPanelA.add (matrixARows);
      matrixPanelA.add (new JLabel ("Cols:"));
      matrixPanelA.add (matrixACols);
      
    JPanel matrixPanelB = new JPanel();
      matrixPanelB.setLayout(new GridLayout(2,2));
      matrixPanelB.setBorder (BorderFactory.createTitledBorder ("Matrix b"));
      matrixPanelB.add (new JLabel ("Rows:"));
      matrixPanelB.add (matrixBRows);
      matrixPanelB.add (new JLabel ("Cols:"));
      matrixPanelB.add (matrixBCols);
    
    JPanel buttonsPanel1 = new JPanel();
       buttonsPanel1.setLayout(new FlowLayout());
       buttonsPanel1.add(applyButton);
       buttonsPanel1.add(resetButton);
       applyButton.addActionListener(new ApplyButtonListener());
       resetButton.addActionListener(new ResetButtonListener());
       applyButton.setToolTipText("Build empty matrix with current Dimensions");
       resetButton.setToolTipText("Reset dimensions and matrix values");
       
    JPanel buttonsPanel2 = new JPanel();
       buttonsPanel2.setLayout(new FlowLayout());
       buttonsPanel2.add(randomButton);
       randomButton.addActionListener(new RandomButtonListener());
       randomButton.setToolTipText("Forces a 10x10 matrix of random integers");
       randomButton.setMnemonic(KeyEvent.VK_A);
       
    JPanel inputs = new JPanel();
      inputs.setLayout(new GridLayout(6,1));
      inputs.add(accuracyPanel);
      inputs.add(matrixPanelXo);
      inputs.add(matrixPanelA);
      inputs.add(matrixPanelB);
      inputs.add(buttonsPanel2);
      inputs.add(buttonsPanel1);

    sPane = new JScrollPane(matrixInputPanel);
    setLayout(new BorderLayout());
    add(sPane, BorderLayout.CENTER);
    add(calculateButton, BorderLayout.SOUTH);
    add(inputs, BorderLayout.WEST);
    calculateButton.setMnemonic(KeyEvent.VK_C);
    calculateButton.addActionListener(new CalculateButtonListener());
    calculateButton.setToolTipText("Calculate Steepest Descent");
    calculateButton.setEnabled(false);
  }

  private class ApplyButtonListener implements ActionListener {
    public void actionPerformed (ActionEvent e){
      int matrixXoRowsNum = Integer.parseInt(matrixXoRows.getText());
      int matrixXoColsNum = Integer.parseInt(matrixXoCols.getText());
      int matrixARowsNum = Integer.parseInt(matrixARows.getText());
      int matrixAColsNum = Integer.parseInt(matrixACols.getText());
      int matrixBRowsNum = Integer.parseInt(matrixBRows.getText());
      int matrixBColsNum = Integer.parseInt(matrixBCols.getText());
      accuracy = Integer.parseInt(accuracyField.getText());
      
      if (matrixAColsNum != matrixXoRowsNum){ 
        matrixInput.setText("Error: Matrix Mismatch");
      } else if (matrixAColsNum != matrixBRowsNum){
        matrixInput.setText("Error: Matrix Mismatch");
      } else if (matrixBRowsNum != matrixXoRowsNum || matrixBColsNum != matrixXoColsNum){ 
        matrixInput.setText("Error Matrix B and Xo must be alike");
      } else if ((accuracyField.getText()).length() < 1) {
        JOptionPane.showMessageDialog(null, "Error 2:\n\tMissing Accuracy Definition", "Error 2", JOptionPane.ERROR_MESSAGE);
        accuracyField.requestFocus();
      } else {
        matrixXoInputPanel.setBorder (BorderFactory.createTitledBorder ("Matrix xo"));
        matrixXoInputPanel.setLayout (new GridLayout(matrixXoRowsNum, matrixXoColsNum));
        matrixXoArray1 = new JTextField[matrixXoRowsNum][matrixXoColsNum];
        for (int row=0; row < matrixXoRowsNum; row++){
          for (int col=0; col < matrixXoColsNum; col++){
            matrixXoArray1[row][col] = new JTextField();
            matrixXoInputPanel.add(matrixXoArray1[row][col]);
          }
        }
        
        matrixAInputPanel.setBorder (BorderFactory.createTitledBorder ("Matrix A"));
        matrixAInputPanel.setLayout (new GridLayout(matrixARowsNum,matrixAColsNum)); 
        matrixAArray1 = new JTextField[matrixARowsNum][matrixAColsNum];
        for (int row=0; row < matrixARowsNum; row++){
          for (int col=0; col < matrixAColsNum; col++){
            matrixAArray1[row][col] = new JTextField();
            matrixAInputPanel.add(matrixAArray1[row][col]);
          }
        }

        matrixBInputPanel.setBorder (BorderFactory.createTitledBorder ("Matrix b"));
        matrixBInputPanel.setLayout (new GridLayout(matrixBRowsNum,matrixBColsNum)); 
        matrixBArray1 = new JTextField[matrixBRowsNum][matrixBColsNum];
        for (int row=0; row < matrixBRowsNum; row++){
          for (int col=0; col < matrixBColsNum; col++){
            matrixBArray1[row][col] = new JTextField();
            matrixBInputPanel.add(matrixBArray1[row][col]);
          }
        }
        
        matrixInputPanel.setLayout(new GridLayout(3,1));
        matrixInputPanel.add(matrixXoInputPanel);
        matrixInputPanel.add(matrixAInputPanel);
        matrixInputPanel.add(matrixBInputPanel);

        calculateButton.setEnabled(true);
        applyButton.setEnabled(false);
        sPane.validate();
        sPane.repaint();
      }
    }
  }
  
  private class ResetButtonListener implements ActionListener {
    public void actionPerformed (ActionEvent e){
      accuracyField.setText(null); 
      matrixXoRows.setText(null);
      matrixXoCols.setText(null);
      matrixARows.setText(null);
      matrixACols.setText(null);
      matrixBRows.setText(null);
      matrixBCols.setText(null);
      matrixInput.setText(null);
      matrixInput.setEditable(false);
      matrixXoRows.setEditable(true);
      matrixXoCols.setEditable(true);
      matrixARows.setEditable(true);
      matrixACols.setEditable(true);
      matrixBRows.setEditable(true);
      matrixBCols.setEditable(true);
      
      matrixXoInputPanel.removeAll();
      matrixAInputPanel.removeAll();
      matrixBInputPanel.removeAll();
      
      sPane.revalidate();
      sPane.repaint();
      
      calculateButton.setEnabled(false);
      applyButton.setEnabled(true);

    }    
  }

  private class RandomButtonListener implements ActionListener {
    public void actionPerformed (ActionEvent e){
      accuracy = Integer.parseInt(accuracyField.getText());
      matrixXoRows.setText("10");
      matrixXoCols.setText("1");
      matrixARows.setText("10");
      matrixACols.setText("10");
      matrixBRows.setText("10");
      matrixBCols.setText("1");
      matrixInput.setEditable(true);
      matrixXoRows.setEditable(false);
      matrixXoCols.setEditable(false);
      matrixARows.setEditable(false);
      matrixACols.setEditable(false);
      matrixBRows.setEditable(false);
      matrixBCols.setEditable(false);
      matrixInputPanel.setCursor((Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)));
      SteepestDescent.setTab(1);
      Algorithm.calculate(Builder.randomMatrixA(),Builder.randomMatrixB(), Builder.randomMatrixXo(), Math.pow(10, accuracy));
      
      calculateButton.setEnabled(false);
     
    }
  }
  
  private class CalculateButtonListener implements ActionListener {
    public void actionPerformed (ActionEvent e){

        int matrixXoRowsNum = Integer.parseInt(matrixXoRows.getText());
        int matrixXoColsNum = Integer.parseInt(matrixXoCols.getText());
        int matrixARowsNum = Integer.parseInt(matrixARows.getText());
        int matrixAColsNum = Integer.parseInt(matrixACols.getText());
        int matrixBRowsNum = Integer.parseInt(matrixBRows.getText());
        int matrixBColsNum = Integer.parseInt(matrixBCols.getText());
        
        matrixXoArray = new double[matrixXoRowsNum][matrixXoColsNum];
        
        for (int row=0; row < matrixXoRowsNum; row++){
          for (int col=0; col < matrixXoColsNum; col++){
            matrixXoArray[row][col] = Double.parseDouble(matrixXoArray1[row][col].getText());
          }
        }
        matrixAArray = new double[matrixARowsNum][matrixAColsNum];
        
        for (int row=0; row < matrixARowsNum; row++){
          for (int col=0; col < matrixAColsNum; col++){
            matrixAArray[row][col] = Double.parseDouble(matrixAArray1[row][col].getText());
          }
        }
        
        matrixBArray = new double[matrixBRowsNum][matrixBColsNum];
        
        for (int row=0; row < matrixBRowsNum; row++){
          for (int col=0; col < matrixBColsNum; col++){
            matrixBArray[row][col] = Double.parseDouble(matrixBArray1[row][col].getText());            
          }
        }
        
        setWaitCursor();
        Algorithm.calculate(matrixAArray, matrixBArray, matrixXoArray, Math.pow(10, accuracy));
        SteepestDescent.setTab(1);
        
      } 
  }

  public void setWaitCursor(){
    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
  }
}
