package primitive;

import java.awt.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;


public class PianoXY extends Canvas
{

	// distanza dell'origine degli assi dal bordo del canvas
	static final int OFFSET_ASSE_X = 40;
	static final int OFFSET_ASSE_Y = 40;
	// distanza delle etichette dagli assi
	static final int OFFSET_LABEL_ASSE_X = 20;
	static final int OFFSET_LABEL_ASSE_Y = 30;
	
	private AsseX asseX;
	private AsseY asseY;

	public PianoXY(String f)
	{
		this.setBackground(Color.green);
		caricaDati(f);
	}
	
	public void paint(Graphics g)
	{
		// metodo paint che viene invocato ogni qualvolta sai necessario
		// aggiornare le componenti grafiche dell'oggetto
		disegnaAssi();
		disegnaEtichette();
		disegnaValori();
	}

	// questo metodo si occupa di riportare la serie di dati sull'area del grafico
	// collegendo i punti con delle spezzate di diverso colore
	private void disegnaValori()
	{
		int stepX, stepY;
		int totale;
		int lenX, lenY;
		Graphics g = this.getGraphics();
		
		// intervello dei valori sull'asse X
		totale = asseX.max - asseX.min;
		// lunghezza utile dell'asse X in pixel
		lenX = getWidth() - OFFSET_ASSE_X * 2;
		// step tra un valore e l'altro sull'asse X
		stepX = (int) Math.floor(lenX / totale);
		// lunghezza utile dell'asse Y in pixel
		lenY = getHeight() - OFFSET_ASSE_Y * 2;

		// devo normalizzare il valore presente nella serie 
		// (nel range [asseY.Min - asseY.Max) nell'intervello dell'asse Y
		// nel sistema di riferimento dell'area del grafico (ovvero nel
		// range [0 - lenY] (Sarà un valore in numero di pixel)
		int shift = 0;
		if (asseY.min < 0) shift = Math.abs(asseY.min);
		int valMax = asseY.max + shift;
		int v = 0;
		Point p = null;
		
		Point origineAssi = new Point(OFFSET_ASSE_X, OFFSET_ASSE_Y);
		
		// coordinate del punto analizzato al passo precedente
		Point prevP = null;
		
		// per ciascun valore della serie di dati determino le sue coordinate
		// relative al sistema di riferimento del canvas e lo disegno
		// rappresentato da un puntino rosso di 5x5 pixel
		for (int i=0; i<asseX.serie.length; i++)
		{
			v = (int) normalizza(lenY, valMax, asseY.serie[i] + shift);
			// memorizzo le coordinate del punto precedente
			if (p != null) prevP = p;
			p = convertiPlot2Canvas(stepX * (i), v, origineAssi);
			g.setColor(Color.red);
			g.fillOval(p.x, p.y, 5,5);
			
			// collego ciascun punto con una spezzata di color blu
			if (prevP != null) 
			{
				g.setColor(Color.blue);
				g.drawLine(prevP.x, prevP.y, p.x, p.y);
			}
		}
	}
	
	private void disegnaEtichette()
	{
		int stepX, stepY;
		int totale;
		int lenX, lenY;
		double stepVal;
		Graphics g = this.getGraphics();
		
		// numero di etichette sull'asseY
		final double ASSEY_LABELS = 10.0;
		
		// intervello dei valori sull'asse X
		totale = asseX.max - asseX.min;
		// lunghezza utile dell'asse X in pixel
		lenX = getWidth() - OFFSET_ASSE_X * 2;
		// step tra un valore e l'altro sull'asse X
		stepX = (int) Math.floor(lenX / totale);
		
		// lunghezza utile dell'asse Y in pixel
		lenY = getHeight() - OFFSET_ASSE_Y * 2;
		// step in pixel tra una etichetta e l'altra sull'asse Y
		stepY = (int) Math.floor(lenY / ASSEY_LABELS);

		totale = asseY.max - asseY.min;
		// incremento tra un valore e l'altro sull'asseY
		stepVal = totale / ASSEY_LABELS;
		
		// coordinate dell'origine degli assi nel sistema di riferimento del canvas
		Point origineAssi = new Point(OFFSET_ASSE_X, getHeight() - OFFSET_ASSE_Y);
		Point p;
		
		// disegno le etichette dei valori sotto l'asse X
		for (int i=0; i<asseX.serie.length; i++)
		{
			p = new Point(origineAssi.x + stepX * (i), origineAssi.y + OFFSET_LABEL_ASSE_X);
			g.drawString(Integer.toString(asseX.serie[i]) , p.x, p.y);
		}

		double v;
		// disegno le etichette dei valori a sinistra dell'asse Y
		for (int i=0; i<11; i++)
		{
			p = new Point(origineAssi.x - OFFSET_LABEL_ASSE_Y, origineAssi.y - stepY * i);
			// calcolo il valore dell'etichetta a intervalli regolari da partire dal valore minimo
			v = asseY.min +  stepVal * i;
			g.drawString(Double.toString(v) , p.x, p.y);
		}
		
	}
	
	private void disegnaAssi()
	{
		Point origineAssi = new Point(OFFSET_ASSE_X, OFFSET_ASSE_Y);

		Graphics g = this.getGraphics();
		// lunghezza utile in pixel degli assi
		// (data dalla larghezza dell'area grafica meno lo spostamento
		// degli assi stessi dal bordo della finestra
		int XMAX = getWidth() - OFFSET_ASSE_X * 2;
		int YMAX = getHeight() - OFFSET_ASSE_Y * 2;

		// definisco i due punti alle estremità del segmento dell'asse X
		Point p1 = convertiPlot2Canvas(0,0, origineAssi);
		Point p2 = convertiPlot2Canvas(0, YMAX, origineAssi);
		// disegno l'asse X
		g.drawLine(p1.x, p1.y, p2.x, p2.y);

		// definisco i due punti alle estremità del segmento dell'asse X
		p1 = convertiPlot2Canvas(0,0, origineAssi);
		p2 = convertiPlot2Canvas(XMAX, 0, origineAssi);
		// disegno l'asseY
		g.drawLine(p1.x, p1.y, p2.x, p2.y);
				
	}

	public void caricaDati(String fileDati)
	{
		String s;
		String a[];
		int minX = 0, maxX = 0;
		int minY = 0, maxY = 0;
		boolean primaIter = true;
		int conta = 0;
		
		int col1, col2;
		
		try
		{
			FileReader in = new FileReader(fileDati);
			BufferedReader reader = new BufferedReader(in);
			
			// con una prima scansione determino il range dei dati
			// da visualizzare (Serve per dimensionare gli assi X e Y)
			while (reader.ready())
			{
				s = reader.readLine();
				if (s.length() > 0 && s.charAt(0) != '#')
				{
					// la funzione split suddivide la stringa s in
					// sottostringhe riconoscibili da un delimitatore
					// (in questo caso una tabulazione)
					a = s.split("\t");
					// conto il numero di record nel file
					conta++;
					// col1 = giorno, col2 = temperatura
					col1 = Integer.parseInt(a[0]); col2 = Integer.parseInt(a[1]);
					if (primaIter) 
					{
						// inizializzo alcune variabili per determinare i valori min e max
						maxX = col1; minX = col1;
						maxY = col2; minY = col2;
						primaIter = false;
					}
					else
					{					
						if (col1 > maxX ) maxX = col1;
						if (col1 < minX) minX = col1;
						if (col2 > maxY) maxY = col2;
						if (col2 < minY) minY = col2;
					}
				}
			}
			reader.close();
			in.close();
			
			// con una seconda passata carico i dati per elaborarli
			in = new FileReader(fileDati);
			reader = new BufferedReader(in);

			// inizializzo l'array dei dati
			
			int[] mySerieX = new int[conta];
			int[] mySerieY = new int[conta];
			int i = 0;
			
			while (reader.ready())
			{
				s = reader.readLine();
				if (s.length() > 0 && s.charAt(0) != '#')
				{
					// la funzione split suddivide la stringa s in
					// sottostringhe riconoscibili da un delimitatore
					// (in questo caso una tabulazione)
					a = s.split("\t");
					mySerieX[i] = Integer.parseInt(a[0]);
					mySerieY[i] = Integer.parseInt(a[1]);
					i++;
				}
			}
			
			reader.close();
			in.close();

			// imposto il range dei valori degli assi e la relativa serie di dati
			asseX = new AsseX(maxX, minX, mySerieX);
			asseY = new AsseY(maxY, minY, mySerieY);
		}
		catch (IOException ioe)
		{
			System.out.println(ioe.getMessage());
		}
	}
	
	// converte le coordinate di un Punto p(x,y), relativo all'area del grafico,
	// nel sistema di coordinate di awt tenendo conto dell'origine del sistema
	// di riferimento del punto dato in input
	private Point convertiPlot2Canvas(Point p, Point o)
	{
		int x = p.x + o.x;
		int y = this.getHeight() - (p.y + o.y);
		
		return new Point(x,y);
	}
	private Point convertiPlot2Canvas(int x, int y, int xo, int yo)
	{
		int xx = x + xo;
		int yy = getHeight() - (y + yo);
		return new Point(xx, yy);
	}
	private Point convertiPlot2Canvas(int x, int y, Point o)
	{
		int xx = x + o.x;
		int yy = this.getHeight() - (y + o.y);
		
		return new Point(xx,yy);
	}
	
	// normalizza il valore v (compreso tra 0 e valueMax) nell'intervallo
	// [0 : rangeMax]
	// Per valori negativi operare uno shift degli stessi nell'intervallo di partenza
	// [0 : valueMax + shift]
	private double normalizza(double rangeMax, double valueMax, double v)
	{
		return v * (rangeMax/valueMax);
	}

}
