/*
 *  Pitches Setup.java
 * 
 *  Copyright (c) 2008, Tom Dinchak & John Fisher
 * 
 *  This file is part of Pages.
 *
 *  Pages 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  Pages 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 for more details.
 *  You should have received a copy of the GNU General Public License
 *  along with Pages; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

package org.monome.pages;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.Receiver;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import org.apache.commons.lang.StringEscapeUtils;

/**
 * Pitches setup page
 *
 */
public class PitchesSetupPage implements Page, ActionListener {

	/**
	 * The MonomeConfiguration this page belongs to
	 */
	private MonomeConfiguration monome;

	/**
	 * This page's index (page number) 
	 */
	private int index;

	/**
	 * This page's GUI / configuration panel 
	 */
	/* ***********************************GUI Variables ******************/
	private JPanel panel;
	

	JLabel label = new JLabel("Page " + (this.index + 1) + ": Pitches Setup");
	JLabel equalTempXLabel = new JLabel("Equal Temp X Axis interval");
	JLabel equalTempYLabel = new JLabel("Equal Temp Y Axis interval");
	JLabel jLatticeXLabel = new JLabel("JI Lattice X axis ratio");
	JLabel jLatticeYLabel = new JLabel("JI Lattice Y axis ratio");
	JLabel etTetLabel = new JLabel("Equal Temperament Divisions");
	JLabel centerXLabel = new JLabel("Lattice Center X");
	JLabel centerYLabel = new JLabel("Lattice Center Y");
	JLabel minNumeratorLabel = new JLabel("minimum numerator for Just Intonation Grid");
	JLabel minDenominatorLabel = new JLabel("minimum denominator for Just Intonation Grid");
	JLabel baseFrequencyLabel = new JLabel("Base Frequency");
	JLabel gridWidthLabel = new JLabel("Grid Width");
	JLabel gridHeightLabel = new JLabel("Grid Height");
	
	JTextField baseFrequency = new JTextField(Integer.toString((int)Configuration.mainPitches.getBaseFrequency()));
	JTextField equalTempX = new JTextField(Integer.toString(Configuration.mainPitches.getXInterval()));
	JTextField equalTempY = new JTextField(Integer.toString(Configuration.mainPitches.getYInterval()));
	JTextField jLatticeX = new JTextField("");
	JTextField jLatticeY = new JTextField("");
	JTextField gridWidth = new JTextField(Integer.toString(Configuration.mainPitches.getGridWidth()));
	JTextField gridHeight = new JTextField(Integer.toString(Configuration.mainPitches.getGridHeight()));
	JTextField etTet = new JTextField(Integer.toString(Configuration.mainPitches.getETtet()));
	JTextField minNumerator = new JTextField(Integer.toString(Configuration.mainPitches.getMinNumerator()));
	JTextField minDenominator = new JTextField(Integer.toString(Configuration.mainPitches.getMinDenominator()));
	JTextField centerX = new JTextField(Integer.toString(Configuration.mainPitches.getCenterX()));
	JTextField centerY = new JTextField(Integer.toString(Configuration.mainPitches.getCenterY()));

	
	/* ***********************************END GUI Vars *******************/
	
	/**
	 * The selected MIDI output device
	 */
	@SuppressWarnings("unused")
	private Receiver recv;

	/**
	 * The name of the selected MIDI output device 
	 */
	private String midiDeviceName;
	
	
	private int[][] ledStates = new int[8][8];
	
	// private JustPitchSet thePitchSet = Configuration.mainPitches;

	/**
	 * @param monome The MonomeConfiguration this page belongs to
	 * @param index The index of this page (the page number)
	 */
	public PitchesSetupPage(MonomeConfiguration monome, int index) { //constructor -------------------
		this.monome = monome;
		this.index = index;
		
		String theRatioX = makeRatioString(Configuration.mainPitches.jLatticeRatios[0][0], 
				Configuration.mainPitches.jLatticeRatios[0][1]);
		String theRatioY = makeRatioString(Configuration.mainPitches.jLatticeRatios[1][0], 
				Configuration.mainPitches.jLatticeRatios[1][1]);
		jLatticeX.setText(theRatioX);
		jLatticeY.setText(theRatioY);
		
		
	}

	/* ******************** ACTION LISTENER ************************************** 
	 * @see org.monome.pages.Page#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent e) {

		if (e.getActionCommand().equals("Update Preferences")) {
			/* set base frequency */
			float pitchesText = stringToFloat(baseFrequency.getText());
				Configuration.mainPitches.setBaseFrequency(pitchesText);
			
			/* set Center Position */
			int cX = stringToInt(centerX.getText());
			int cY = stringToInt(centerY.getText());
			Configuration.mainPitches.setJICenter(cX, cY);
				
			/*set the equal temp intervals */
			int etX = stringToInt(equalTempX.getText());
			int etY = stringToInt(equalTempY.getText());
			Configuration.mainPitches.setBothET(etX, etY);
			
			/* set the ratio intervals */
			int[] theRatioX;
			int[] theRatioY;
			theRatioX = ratioToIntArray(jLatticeX.getText());
			theRatioY = ratioToIntArray(jLatticeY.getText());
			Configuration.mainPitches.setRatioArray(theRatioX[0], theRatioX[1], theRatioY[0], theRatioY[1]);
			
			/* set Grid size */
			int theGridWidth = stringToInt(gridWidth.getText());
			int theGridHeight = stringToInt(gridWidth.getText());
			Configuration.mainPitches.setGridSize(theGridWidth, theGridHeight);
			
			/*set Equal Temperament Divisions */
			int theETTet = stringToInt(etTet.getText());
			Configuration.mainPitches.setETtet(theETTet);
			
			/*set Minimums */
			int minX = stringToInt(minNumerator.getText());
			int minY = stringToInt(minDenominator.getText());
			Configuration.mainPitches.setBothMinimums(minX, minY);
			
			Configuration.mainPitches.printAllVars();

		}
		else if (e.getActionCommand().equals("Rotate Clockwise")){
			Configuration.mainPitches.rotateETCW(Configuration.mainPitches.etGrid);
			Configuration.mainPitches.rotateJICW(Configuration.mainPitches.rGrid);
			Configuration.mainPitches.rotateJICW(Configuration.mainPitches.rLattice);
			System.out.println("Grids all rotated Clockwise");
		}
		else if (e.getActionCommand().equals("Rotate Counter-Clockwise")){
			Configuration.mainPitches.rotateETCCW(Configuration.mainPitches.etGrid);
			Configuration.mainPitches.rotateJICCW(Configuration.mainPitches.rGrid);
			Configuration.mainPitches.rotateJICCW(Configuration.mainPitches.rLattice);
			System.out.println("Grids all rotated Counter-Clockwise");
		}
		else if (e.getActionCommand().equals("Flip Horizontal")){
			Configuration.mainPitches.flipETHorizontal(Configuration.mainPitches.etGrid);
			Configuration.mainPitches.flipJIHorizontal(Configuration.mainPitches.rGrid);
			Configuration.mainPitches.flipJIHorizontal(Configuration.mainPitches.rLattice);
			System.out.println("Grids all Flipped Horizontally");
		}
		else if (e.getActionCommand().equals("Flip Vertical")){
			Configuration.mainPitches.flipETVertical(Configuration.mainPitches.etGrid);
			Configuration.mainPitches.flipJIVertical(Configuration.mainPitches.rGrid);
			Configuration.mainPitches.flipJIVertical(Configuration.mainPitches.rLattice);
			System.out.println("Grids all Flipped Vertical");
		}
		
		return;
	}

	/* ****************** END ACTION LISTENER ***********************************/
	
	/* (non-Javadoc)
	 * @see org.monome.pages.Page#addMidiOutDevice(java.lang.String)
	 */
	public void addMidiOutDevice(String deviceName) {
		this.recv = this.monome.getMidiReceiver(deviceName);
		this.midiDeviceName = deviceName;
	}

	/* (non-Javadoc)
	 * @see org.monome.pages.Page#getName()
	 */
	public String getName() {
		return "Pitches Setup";
	}

	/* ********************************GUI STUFF ****************************** * * *
	 * @see org.monome.pages.Page#getPanel()
	 */
	public JPanel getPanel() {
		if (this.panel != null) {
			return this.panel;
		}
		
		JButton updatePrefsButton = new JButton();
		updatePrefsButton.setText("Update Preferences");
		updatePrefsButton.addActionListener(this);

		JButton rotateCWButton = new JButton();
		rotateCWButton.setText("Rotate Clockwise");
		rotateCWButton.addActionListener(this);
		
		JButton rotateCCWButton = new JButton();
		rotateCCWButton.setText("Rotate Counter-Clockwise");
		rotateCCWButton.addActionListener(this);
		
		JButton flipVerticalButton = new JButton();
		flipVerticalButton.setText("Flip Horizontal");
		flipVerticalButton.addActionListener(this);
		
		JButton flipHorizontalButton = new JButton();
		flipHorizontalButton.setText("Flip Vertical");
		flipHorizontalButton.addActionListener(this);
		

		JPanel panel = new JPanel();
		panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
		panel.setPreferredSize(new java.awt.Dimension(300, 650));
		
		panel.add(label);
		panel.add(baseFrequencyLabel);
		panel.add(baseFrequency);
		panel.add(equalTempXLabel);
		panel.add(equalTempX);
		panel.add(equalTempYLabel);	
		panel.add(equalTempY);
		panel.add(jLatticeXLabel);
		panel.add(jLatticeX);
		panel.add(jLatticeYLabel);
		panel.add(jLatticeY);
		panel.add(gridWidthLabel);
		panel.add(gridWidth);
		panel.add(gridHeightLabel);
		panel.add(gridHeight);
		panel.add(etTetLabel);
		panel.add(etTet);
		panel.add(minNumeratorLabel);
		panel.add(minNumerator);
		panel.add(minDenominatorLabel);
		panel.add(minDenominator);
		panel.add(centerXLabel);
		panel.add(centerX);
		panel.add(centerYLabel);
		panel.add(centerY);
		//buttons
		panel.add(updatePrefsButton);
		panel.add(rotateCWButton);
		panel.add(rotateCCWButton);
		panel.add(flipVerticalButton);
		panel.add(flipHorizontalButton);
		

		this.panel = panel;
		return panel;
	}
	
	/* ****************************************** END GUI STUFF ********************************** * * *

	/* (non-Javadoc)
	 * @see org.monome.pages.Page#handlePress(int, int, int)
	 */
	public void handlePress(int x, int y, int value) {
		printButtonPress(x,y,value);		
	}

	/* (non-Javadoc)
	 * @see org.monome.pages.Page#handleReset()
	 */
	public void handleReset() {
		// TODO add code to handle a reset position message from the midi clock source (stop button twice generally)
	}

	/* (non-Javadoc)
	 * @see org.monome.pages.Page#handleTick()
	 */
	public void handleTick() {
		// TODO add code to handle a 'tick' from the midi clock source (every 1/96th of a bar)
	}

	/* (non-Javadoc)
	 * This just clears all LEDs
	 */
	public void redrawMonome() {
		for (int i=0; i<this.monome.sizeX ; i++){
			for(int j = 0; j<this.monome.sizeY; j++){
				this.monome.led(i, j, ledStates[i][j], this.index);
			}
		}
	}

	/* (non-Javadoc)
	 * @see org.monome.pages.Page#send(javax.sound.midi.MidiMessage, long)
	 */
	public void send(MidiMessage message, long timeStamp) {
		// TODO add code to handle midi input from midi clock source (can be any type of input)
	}

	/* (non-Javadoc)
	 * @see org.monome.pages.Page#toXml()
	 */
	public String toXml() {
		String xml = "";
		xml += "    <page>\n";
		xml += "      <name>Pitches Setup</name>\n";
		xml += "      <selectedmidioutport>" + StringEscapeUtils.escapeXml(this.midiDeviceName) + "</selectedmidioutport>\n";
		xml += "    </page>\n";
		return xml;
	}

	/* (non-Javadoc)
	 * @see org.monome.pages.Page#getCacheDisabled()
	 */
	public boolean getCacheDisabled() {
		return false;
	}

	/* (non-Javadoc)
	 * @see org.monome.pages.Page#destroyPage()
	 */
	public void destroyPage() {
		return;
	}
	
	
	
	/* ****************** non "Page" methods ************************** */
	
	private void sendReaktorFreq(int x, int y){
		
	}
	
	/*
	 * function to simply print the state of the monome button presses, 
	 * sent from the 'handlepress' method
	 */
	private void printButtonPress(int x, int y, int value){
		System.out.print("");
		System.out.print("x: " + x + " y: " + y + " state: ");
		if(value==1){
			System.out.print("press");
		}
		else if (value ==0){
			System.out.print("release");
		}
		System.out.println("");
	}
	
	//converts a string to a float value
	private float stringToFloat(String s){
		float f = 0;
		try {
		         f = Float.valueOf(s.trim()).floatValue();
		      } catch (NumberFormatException nfe) {
		         System.out.println("NumberFormatException: " + nfe.getMessage());
		      }
		      return f;
	}
	
	//converts a string to an int value
	private int stringToInt(String s){
		int i = 0;
	      try {
	           i = Integer.parseInt(s.trim());
	        } catch (NumberFormatException nfe) {
	           System.out.println("NumberFormatException: " + nfe.getMessage());
	        }
		      return i;
	}
	
	//converts a ratio formatted as x/y into an array, int[2] {x,y}
	private int[] ratioToIntArray(String textBox){
		String text = textBox.trim();
		String temp[] = null;
		int tempInt[] = new int[2];
		temp = text.split("/");
		tempInt[0] = stringToInt(temp[0]);
		tempInt[1] = stringToInt(temp[1]);
		
		return tempInt;
	}
	
	//converts two values, numerator and denominator into a string, "numerator/denominator"
	private String makeRatioString(int numerator, int denominator){
		String theRatio = numerator + "/" + denominator;
		return theRatio;
	}
	
	
//end class	
}

