package main;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import javax.swing.JPanel;
import java.awt.geom.Rectangle2D;

public class Note extends JPanel{
	
	int noTimesClicked = 0;
	double x;
	double y;
	int n;
	int d;
	int v;
	int p;
	double pitch;
	int clefChoice;
	int octavaAndBassoChoice;
	int spellingChoice;
	int ratioChoice;
	int noteHeadChoice = 0;
	String[] clefs = {"\uf03f", "\uf042", "\uf042", "\uf026"};
	String[] octavasAndBassos = {"15", "8", " ", "8", "15"};
	String[] acc = {"\uf062","\uf06e", "\uf023"};
	
	float clickAndPlayX1;
	float clickAndPlayX2;
	
	Color color = Color.BLACK;
	
	boolean isListening = false;
	
	public Note(double x, double y, double p, int v, int pP){
		this.x = x;
		this.y = y;
		n = (int) (Rise.FIRST_NUM+v-pP);
		d = (int) (Rise.FIRST_NUM-pP);
		this.pitch = p + Rise.TRANSPOSE_SCORE * 100.;
		this.v = v;
		this.p = pP;
		this.setOpaque(false);
		this.setBackground(Color.WHITE);
		this.setBounds((int) 0, (int) 0,(int) (Rise.PAGE_WIDTH*Rise.ZOOM), (int) (Rise.PAGE_HEIGHT*Rise.ZOOM));
		initializeChoices();
	}
	
	public void paint(Graphics g){
		g.setColor(color);
		Graphics2D g2 = (Graphics2D) g;
		this.setBounds((int) 0, (int) 0,(int) (Rise.PAGE_WIDTH*Rise.ZOOM), (int) (Rise.PAGE_HEIGHT*Rise.ZOOM));
		g2.translate(Rise.PAGE_MARGIN*Rise.ZOOM, Rise.PAGE_MARGIN*Rise.ZOOM);
		g2.scale(Rise.ZOOM, Rise.ZOOM);
		
		FontRenderContext frc = g2.getFontRenderContext();
		Font fontMusic = new Font("Maestro", Font.PLAIN, (int) Rise.FONT);
		fontMusic.deriveFont(Rise.FONT);
		Font fontNumbers = new Font("Liberation Serif", Font.PLAIN, (int) Math.round(Rise.FONT/1.714));
		Font fontOBSigns = new Font("Liberation Serif", Font.PLAIN, (int) Math.round(Rise.FONT/2.4));
		TextLayout note = new TextLayout("\uf0cf", fontMusic, frc);
		TextLayout staff = new TextLayout("\uf03d\uf03d", fontMusic, frc);
		TextLayout ledgerLine = new TextLayout("\uf02d", fontMusic, frc);
		g2.setFont(fontMusic);
		FontMetrics fontMetrics = g2.getFontMetrics();
		double noteWidth = fontMetrics.stringWidth("\uf0cf");
		double staffWidth = fontMetrics.stringWidth("\uf03d");
		double ledgerWidth = fontMetrics.stringWidth("\uf02d");
		double staffSpace = Rise.FONT/8.;
		float noteX = (float) (x*Rise.IMAGE_WIDTH - noteWidth/2. /*- ((1./(Rise.VOICES-1))*(p-v)/p)*Rise.IMAGE_WIDTH*Rise.X_DIV*/);
		float noteY = (float) y*Rise.IMAGE_HEIGHT;
		
		float toneX1 = (float) (x*Rise.IMAGE_WIDTH - ((1./(Rise.VOICES-1))*(p-v)/p)*Rise.IMAGE_WIDTH*Rise.X_DIV);
		float toneX2;
		if (p != Rise.VOICES-1) {
			toneX2 = (float) (x*Rise.IMAGE_WIDTH + ((1./(Rise.VOICES-1))*v/(p+1))*Rise.IMAGE_WIDTH*Rise.X_DIV);
		}
		else {
			toneX2 = (float) (x*Rise.IMAGE_WIDTH + ((1./(Rise.VOICES-1))*.25)*Rise.IMAGE_WIDTH*Rise.X_DIV);
		}
		float toneY1 = (float) (noteY - note.getBounds().getMaxY()/3);
		float toneY2 = (float) (noteY - note.getBounds().getMinY()/3);
		
		//System.out.println("notes " + ((1./(Rise.VOICES-1))*(p-v)/p) + " " + ((1./(Rise.VOICES-1))*v/(p+1)));
		
		g2.setColor(new Color(200, 200, 200));
		g2.fill(new Rectangle2D.Float(toneX1, toneY1, toneX2-toneX1, toneY2-toneY1));
		g2.setColor(color);
		
		clickAndPlayX1 = toneX1;
		clickAndPlayX2 = toneX2;
		
		note.draw(g2,noteX,noteY);
		
		double accWidth = fontMetrics.stringWidth(acc[getAcc((int) (Math.round(pitch/100.)%12))]);
		TextLayout accidental = new TextLayout(acc[getAcc((int) (Math.round(pitch/100.)%12))], fontMusic, frc);
		accidental.draw(g2,(float) (noteX-accWidth-2),(float) y*Rise.IMAGE_HEIGHT);
		
		int notePosition = getNotePosition((int) (Math.round(pitch/100.)%12));
		
		int centDeviation = (int) Math.round((pitch/100. - Math.round(pitch/100.))*100.);
		TextLayout centDeviationText;
		if (centDeviation >= 0) {
			centDeviationText = new TextLayout("+" + String.valueOf(centDeviation), fontNumbers, frc);
		}
		else {
			centDeviationText = new TextLayout(String.valueOf(centDeviation), fontNumbers, frc);
		}
		
		for (int i = d; i > 0; i--) {
			if (Math.round((float) d/i) == (float) d/i
					&& Math.round((float) n/i) == (float) n/i) {
				n = n/i;
				d = d/i;
			}
		}
		TextLayout ratioText = new TextLayout(String.valueOf(n) + "/" + String.valueOf(d), fontNumbers, frc);

		int stepsToLowestC = 0;
		int addOctaves = 0;
		int stepsToClef = 0;
		
		if (clefChoice == 0){
			stepsToLowestC = -11;
			stepsToClef = 6;
		}
		else if (clefChoice == 1){
			stepsToLowestC = -15;
			stepsToClef = 6;
		}
		else if (clefChoice == 2){
			stepsToLowestC = -17;
			stepsToClef = 4;
		}
		else if (clefChoice == 3){
			stepsToLowestC = -23;
			stepsToClef = 2;
		}
		
		if (octavaAndBassoChoice == 0){
			stepsToLowestC = stepsToLowestC+14;
		}
		else if (octavaAndBassoChoice == 1){
			stepsToLowestC = stepsToLowestC+7;
		}
		else if (octavaAndBassoChoice == 2){
		}
		else if (octavaAndBassoChoice == 3){
			stepsToLowestC = stepsToLowestC-7;
		}
		else if (octavaAndBassoChoice == 4){
			stepsToLowestC = stepsToLowestC-14;
		}
		
		addOctaves = (int) (Math.round(pitch/100.)/12)*7;
		float staffX = (float) (x*Rise.IMAGE_WIDTH - 1.5*staffWidth /*- ((1./(Rise.VOICES-1))*(p-v)/p)*Rise.IMAGE_WIDTH*Rise.X_DIV*noteHeadChoice*/);
		float staffY = (float) (y*Rise.IMAGE_HEIGHT+(stepsToLowestC+notePosition+addOctaves)*staffSpace);
		staff.draw(g2, staffX, staffY);
		float clefX = (float) (x*Rise.IMAGE_WIDTH - 1.5*staffWidth /*- ((1./(Rise.VOICES-1))*(p-v)/p)*Rise.IMAGE_WIDTH*Rise.X_DIV*noteHeadChoice*/);
		float clefY = (float) (y*Rise.IMAGE_HEIGHT+((stepsToLowestC-stepsToClef)+notePosition+addOctaves)*staffSpace);
		TextLayout clef = new TextLayout(clefs[clefChoice], fontMusic, frc);
		clef.draw(g2, clefX, clefY);
		TextLayout octavaAndBasso = new TextLayout(octavasAndBassos[octavaAndBassoChoice], fontOBSigns, frc);
		if (octavaAndBassoChoice < 2){
			octavaAndBasso.draw(g2,(float) (clefX+clef.getVisibleAdvance()/2.-octavaAndBasso.getAdvance()/2),(float) (clefY+clef.getBounds().getMaxY()-octavaAndBasso.getBounds().getMinY()));
		}
		else if (octavaAndBassoChoice < 3){
		}
		else if(octavaAndBassoChoice < 5){
			if (clefChoice == 3 && octavaAndBassoChoice == 3) {
				octavaAndBasso.draw(g2,(float) (clefX+clef.getVisibleAdvance()/2.-octavaAndBasso.getAdvance()/16.),(float) (clefY+clef.getBounds().getMinY()));
			}
			else if (clefChoice == 3 && octavaAndBassoChoice == 4) {
				octavaAndBasso.draw(g2,(float) (clefX+clef.getVisibleAdvance()/2.-octavaAndBasso.getAdvance()/4.),(float) (clefY+clef.getBounds().getMinY()));
			}
			else {
				octavaAndBasso.draw(g2,(float) (clefX+clef.getVisibleAdvance()/2.-octavaAndBasso.getAdvance()/2),(float) (clefY+clef.getBounds().getMinY()));
			}
		}
		
		if (noteY-staffY >= staffSpace*2){
			float ledgerLineX = (float) (x*Rise.IMAGE_WIDTH - ledgerWidth/2.);
			float ledgerLineY = (float) (staffY+staffSpace*2);
			while (ledgerLineY <= noteY){
				ledgerLine.draw(g2, ledgerLineX, ledgerLineY);
				ledgerLineY = (float) (ledgerLineY+staffSpace*2);
			}
		}
		if (staffY-noteY >= staffSpace*10){
			float ledgerLineX = (float) (x*Rise.IMAGE_WIDTH - ledgerWidth/2.);
			float ledgerLineY = (float) (staffY-staffSpace*10);
			while (ledgerLineY >= noteY){
				ledgerLine.draw(g2, ledgerLineX, ledgerLineY);
				ledgerLineY = (float) (ledgerLineY-staffSpace*2);
			}
		}
		
		if (noteY >= staffY-staffSpace*6){
			centDeviationText.draw(g2, (float) (noteX-centDeviationText.getAdvance()/4.), (float) (staffY-staffSpace*9));
		}
		else {
			centDeviationText.draw(g2, (float) (noteX-centDeviationText.getAdvance()/4.), (float) (noteY-staffSpace*3));
		}
		
		if (ratioChoice == 0) {
			if (noteY <= staffY-staffSpace*2){
				ratioText.draw(g2, (float) (noteX-ratioText.getAdvance()/4.), (float) (staffY+staffSpace*1+ratioText.getAscent()));
			}
			else {
				ratioText.draw(g2, (float) (noteX-ratioText.getAdvance()/4.), (float) (noteY+staffSpace*3+ratioText.getAscent()));
			}
		}
	}
	
	public int getNotePosition(int mN) {
		int notePosition = 0;
		if (spellingChoice == 0) {
			int modNote = mN;
			switch(modNote) {
			case 0 : notePosition = 0; break;
			case 1 : notePosition = 0; break;
			case 2 : notePosition = 1; break;
			case 3 : notePosition = 1; break;
			case 4 : notePosition = 2; break;
			case 5 : notePosition = 3; break;
			case 6 : notePosition = 3; break;
			case 7 : notePosition = 4; break;
			case 8 : notePosition = 4; break;
			case 9 : notePosition = 5; break;
			case 10 : notePosition = 5; break;
			case 11: notePosition = 6; break;
			case 12: notePosition = 7; break;
			}
		}
		else if (spellingChoice == 1){
			int modNote = mN;
			switch(modNote) {
			case 0 : notePosition = 0; break;
			case 1 : notePosition = 1; break;
			case 2 : notePosition = 1; break;
			case 3 : notePosition = 2; break;
			case 4 : notePosition = 2; break;
			case 5 : notePosition = 3; break;
			case 6 : notePosition = 4; break;
			case 7 : notePosition = 4; break;
			case 8 : notePosition = 5; break;
			case 9 : notePosition = 5; break;
			case 10 : notePosition = 6; break;
			case 11: notePosition = 6; break;
			case 12: notePosition = 7; break;
			}
		}
		return notePosition;
	}
	
	public int getAcc(int mN) {
		int accidental = 1;
		if (spellingChoice == 0){
			int modNote = mN;
			switch(modNote) {
			case 0 : accidental = 1; break;
			case 1 : accidental = 2; break;
			case 2 : accidental = 1; break;
			case 3 : accidental = 2; break;
			case 4 : accidental = 1; break;
			case 5 : accidental = 1; break;
			case 6 : accidental = 2; break;
			case 7 : accidental = 1; break;
			case 8 : accidental = 2; break;
			case 9 : accidental = 1; break;
			case 10 : accidental = 2; break;
			case 11: accidental = 1; break;
			case 12: accidental = 1; break;
			}
		}
		if (spellingChoice == 1){
			int modNote = mN;
			switch(modNote) {
			case 0 : accidental = 1; break;
			case 1 : accidental = 0; break;
			case 2 : accidental = 1; break;
			case 3 : accidental = 0; break;
			case 4 : accidental = 1; break;
			case 5 : accidental = 1; break;
			case 6 : accidental = 0; break;
			case 7 : accidental = 1; break;
			case 8 : accidental = 0; break;
			case 9 : accidental = 1; break;
			case 10 : accidental = 0; break;
			case 11: accidental = 1; break;
			case 12: accidental = 1; break;
			}
		}
		return accidental;
	}
	
	public void initializeChoices(){
		
		spellingChoice = 1;
		ratioChoice = 0;
		
		int stepsToLowestC = 0;
		int addOctaves = 0;
		double staffSpace = Rise.FONT/8.;
		float noteY = (float) y*Rise.IMAGE_HEIGHT;
		int notePosition = getNotePosition((int) (Math.round(pitch/100.)%12));

		float min = 500000;
		for (int c = 0; c < 4; c++){
			int oBStart = 0;
			int oBMax = 0;
			if (c == 0) {
				oBStart = 0;
				oBMax = 3;
			}
			else if (c < 3) {
				oBStart = 2;
				oBMax = 3;
			}
			else if (c < 4) {
				oBStart = 2;
				oBMax = 5;
			}
			
			for (int oB = oBStart; oB < oBMax; oB++){
				
				if (c == 0){
					stepsToLowestC = -11;
				}
				else if (c == 1){
					stepsToLowestC = -15;
				}
				else if (c == 2){
					stepsToLowestC = -17;
				}
				else if (c == 3){
					stepsToLowestC = -23;
				}
				
				if (oB == 0){
					stepsToLowestC = stepsToLowestC+14;
				}
				else if (oB == 1){
					stepsToLowestC = stepsToLowestC+7;
				}
				else if (oB == 2){
				}
				else if (oB == 3){
					stepsToLowestC = stepsToLowestC-7;
				}
				else if (oB == 4){
					stepsToLowestC = stepsToLowestC-14;
				}
				
				addOctaves = (int) (Math.round(pitch/100.)/12)*7;
				float staffY = (float) (y*Rise.IMAGE_HEIGHT+(stepsToLowestC+notePosition+addOctaves)*staffSpace);
				if (Math.abs((staffY-4*staffSpace)-noteY) < min){
					clefChoice = c;
					octavaAndBassoChoice = oB;
					min = (float) Math.abs((staffY-4*staffSpace)-noteY);
				}
			}
		}
	}
	
	public int testSelect(float x1, float y1, float x2, float y2){
		if ((float) (Rise.PAGE_MARGIN*Rise.ZOOM+x*Rise.IMAGE_WIDTH*Rise.ZOOM) > x1
				&& (float) (Rise.PAGE_MARGIN*Rise.ZOOM+x*Rise.IMAGE_WIDTH*Rise.ZOOM) < x2
				&& (float) (Rise.PAGE_MARGIN*Rise.ZOOM+y*Rise.IMAGE_HEIGHT*Rise.ZOOM) > y1
				&& (float) (Rise.PAGE_MARGIN*Rise.ZOOM+y*Rise.IMAGE_HEIGHT*Rise.ZOOM) < y2){
			color = Color.BLUE;
			isListening = true;
			return 1;
		}
		else {
			color = Color.BLACK;
			isListening = false;
			return 0;
		}
	}
	
	
	public int testSelectClickAndPlay(float xMouse, float yMouse){
		if ((Rise.PAGE_MARGIN*Rise.ZOOM + clickAndPlayX1*Rise.ZOOM) < xMouse
				&& (Rise.PAGE_MARGIN*Rise.ZOOM + clickAndPlayX2*Rise.ZOOM) > xMouse
				&& (float) (Rise.PAGE_MARGIN*Rise.ZOOM+(y)*Rise.IMAGE_HEIGHT*Rise.ZOOM + 10*Rise.ZOOM) > yMouse
				&& (float) (Rise.PAGE_MARGIN*Rise.ZOOM+(y)*Rise.IMAGE_HEIGHT*Rise.ZOOM - 10*Rise.ZOOM) < yMouse){
			color = Color.BLUE;
			isListening = true;
			//double toReturn = (xMouse - Rise.PAGE_MARGIN*Rise.ZOOM)/(Rise.IMAGE_WIDTH*Rise.ZOOM);
			//System.out.println((xMouse) + " " + (clickAndPlayX1*Rise.ZOOM) + " " + (clickAndPlayX2*Rise.ZOOM) + " " + yMouse + " " + (Rise.PAGE_MARGIN*Rise.ZOOM+y*Rise.IMAGE_HEIGHT*Rise.ZOOM));
			//System.out.println(toReturn);
			return 1;
		}
		else {
			color = Color.BLACK;
			isListening = false;
			return 0;
		}
	}
}
