/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * callbacks.c
 * Copyright (C) Administrator 2010 <administrator@>
 * 
 * GRAFFITI 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 3 of the License, or
 * (at your option) any later version.
 * 
 * GRAFFITI 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include "callbacks.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <cairo/cairo.h>
#include <cairo/cairo-pdf.h>
#include <cairo-svg.h> 

#include <gdk/gdk.h>



/*definicion de constantes */

const int MARCO = 50; //distancia que hay alrededor del area de visualizacion
const int ANCHO_PANTALLA = 500; //ancho del area de visualizacion
const int ORIGEN = 300; //origen de coordenadas
/*fin de definicion de constantes */

/*defincion de estructuras*/

//definicion de un elemento de la lista enlazada que almacena los valores 
//del zoom actual y anteriores
struct listaZoom
{
	double factorX;//factores de multimplicacion
	double factorY;
	int inicioX; //limites de coordenadas para mostrar la señal 
	int inicioY;
	int diagonalX;
	int diagonalY;
	int desplazamientoX;
	int desplazamientoY;
	struct listaZoom *siguiente;

};
/*fin de defincion de estructuras*/

/* definicion de variables globales */

gboolean rejilla=TRUE;//por defecto la rejilla esta activada
gboolean s_open[4]={TRUE,TRUE,TRUE,TRUE};//indica que señal esta visualizandose

gboolean dots=FALSE;//por defecto no esta activada la nube de puntos
gboolean invertir=FALSE;//Indica si hay que invertir los colores de fondo con el de las leyendas

int outputMode=0; //selecciona el modo de salida del dibujo
				//0: salida por pantalla, por defecto seleccinada
				//1: para guardar el dibujo en un fichero PDF
				//2: para guardar el dibujo en un fichero SVG
				//3: para guardar el dibujo en un fichero PNG



cairo_t *cr;//variable que define el entorno de dibujo

int filas; //numero de elementos de cada señal del array
int columnas;//numero de señales

double unidadX;//tamaños de cada pixel para ajustar la señal en pantalla
double unidadY;

int *coordx; //array para almacenar los puntos del grafico
int **coordy;

char *fileOpen;//fichero desde donde se leen los datos
char *fileOutput;//fichero donde se guarda la representacion de los datos

int inicioXtemporal;//almacen temporal de las coordenadas cuando se hace
int inicioYtemporal;//zoom arrastrando y soltando

int selecMaxMin;//almacena la señal que se desea mostrar max y min

struct listaZoom *cabeza=NULL;//defincion de la lista enlazada vacia



/* fin de definicion de variables globales */



//**************************************************************************
//funcion que cierra la aplicacion
//**************************************************************************
void destroy (GtkWidget *widget, gpointer data)
{
	gtk_main_quit ();
}

//**************************************************************************
//funcion que se ejecuta con el boton de señeccion de regilla on/off
//**************************************************************************
void on_checkbuttonGRIDD_toggled(GtkWidget *widget, gpointer data)
{
	//muestra la rejilla
	if (rejilla==FALSE){
		rejilla=TRUE;
		gtk_label_set_text(label_x,"Regilla ON");
	}
	else{
		rejilla=FALSE;
		gtk_label_set_text(label_x,"Regilla OFF");
	}
	draw_plot();
}

//**************************************************************************
//funciones que activan o desactivan la visualizacion de cada una
//de lasdistintas señales
//**************************************************************************
void on_checkbutton1_toggled(GtkWidget *widget, gpointer data)
{
	//muestra la señal1
	seleccionS(0);
}

void on_checkbutton2_toggled(GtkWidget *widget, gpointer data)
{
	//muestra la señal2
	seleccionS(1);
}

void on_checkbutton3_toggled(GtkWidget *widget, gpointer data)
{
	//muestra la señal3
	seleccionS(2);
}

void on_checkbutton4_toggled(GtkWidget *widget, gpointer data)
{
	//muestra la señal4
	seleccionS(3);
}

void seleccionS(int num)
{
	//muestra la señalseleccionada
	if (s_open[num]==FALSE)
	{
		s_open[num]=TRUE;
	}
	else
	{
		s_open[num]=FALSE;
	}
	draw_plot();
}

//**************************************************************************
//funcion que activan o desactivan la visualizacion en modo nube de puntos
//**************************************************************************
void on_checkbuttonDOTS_toggled(GtkWidget *widget, gpointer data)
{
//muestra solo la nube de puntos puntos de las señales
	if (dots==FALSE)
	{
		dots=TRUE;
	}
	else
	{
		dots=FALSE;
	}
	draw_plot();
}

//**************************************************************************
//funcion que activa una variable para invertir los colores de fondo y de 
//las leyendas, es util especialmente a la hora de imprimir
//**************************************************************************
void on_checkbuttonINVERTIR_toggled(GtkWidget *widget, gpointer data)
{
	if (invertir==FALSE)
	{
		invertir=TRUE;
	}
	else
	{
		invertir=FALSE;
	}
	draw_plot();
	
}

//**************************************************************************
//funcion que redibuja todos los elementos graficos
//se ejecuta despues de algun evento que necesite redibujar la pantalla
//**************************************************************************
void draw_plot(void)
{
	//se inicializan los valores iniciales del zoom si no se a hecho antes
	if (cabeza==NULL)
	{
		cabeza = (struct listaZoom *) malloc(sizeof(struct listaZoom));
		cabeza->inicioX = 0; 
		cabeza->inicioY = 500;
		cabeza->diagonalX=500;
		cabeza->diagonalY=0;
		cabeza->factorX=1.00;
		cabeza->factorY=1.00;
		cabeza->desplazamientoX=0;
		cabeza->desplazamientoY=0;
		cabeza->siguiente=NULL;
	}

	//inicializacion de elementos necesarios para dibujar
	GtkWidget *tmp;
	tmp = (GtkWidget *)(draw_area);
	cairo_surface_t *surface;

	//seleccion del modo de salida del dibujo
	switch(outputMode)
			{
			case 0://El dibujo se imprime en pantalla
					cr = gdk_cairo_create(tmp->window);
					break;
			case 1: //el dibujo se guarda como fichero pdf
					surface = cairo_pdf_surface_create(fileOutput, 600, 600);
					cr = cairo_create(surface);
					break;
			case 2: //el dibujo se guarda como fichero svg
					surface = cairo_svg_surface_create(fileOutput, 600, 600);
					cr = cairo_create(surface);

					break;
			case 3: //el dibujo se guarda como fichero png
					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,600,600);
					cr = cairo_create(surface);

					break;
			}


	//Seleccion de color de fondo
	int i=0;
	if (invertir)
	{
		cairo_set_source_rgb (cr,1, 1, 1);//Seleccion de color blanco
	}
	else
	{
		cairo_set_source_rgb (cr,0, 0, 0);//Seleccion de color negro
	}

	//dibujo del color de fondo
	cairo_rectangle (cr,0,0, ANCHO_PANTALLA+2*MARCO, ANCHO_PANTALLA+2*MARCO);
	cairo_fill (cr);

	//Seleccion de color de las rejillas y leyendas
	if (invertir)
	{
		cairo_set_source_rgb (cr,0, 0, 0);//Seleccion de color negro
	}
	else
	{
		cairo_set_source_rgb (cr,1, 1, 1);//Seleccion de color blanco
	}

	//se dibujan las rejillas
	if (rejilla==TRUE)
	{
		cairo_set_line_width(cr,1);
		static const double dashed[] = {2.0,2.0};
		static int len  = sizeof(dashed) / sizeof(dashed[0]);
		cairo_set_dash(cr, dashed, len, 0);
		int i=0;
		for(i=0;i<=10;i++)
		{
			//lineas verticales
			cairo_move_to(cr,(i+1)*MARCO,MARCO);
			cairo_line_to(cr,(i+1)*MARCO,MARCO+ANCHO_PANTALLA);
			//lineas horizontales
			cairo_move_to(cr,MARCO,(i+1)*MARCO);
			cairo_line_to(cr,MARCO+ANCHO_PANTALLA,(i+1)*MARCO);
		}
		cairo_stroke(cr);
	}

	//Se cambia de linea discontinua a continua
	static const double dashed2[] = {2.0,0};
	static int len  = sizeof(dashed2) / sizeof(dashed2[0]);
	cairo_set_dash(cr, dashed2, len, 0);

	//se aplica el factor de proporcionalidad para hacer zoom
	cairo_scale (cr, cabeza->factorX, cabeza->factorY);

	//se dibujan las señales seleccionadas
	double valorX=0;
	double valorY=0;
	int j=0;
	for (j=0;j<columnas;j++)
	{
		if (s_open[j])
		{
			//seleccion del ancho de linea
			double anchoLinea=3; 
			cairo_set_line_width(cr,anchoLinea);
			
			cairo_font_extents_t fe;
			cairo_text_extents_t te;
			cairo_font_extents (cr, &fe);
			cairo_text_extents (cr, "X", &te);

			//seleccion del color de las señales
			GdkColor color;
			switch(j)
			{
			//se establece un color distinto para cada una de las 4 señales
			case 0:
					gtk_color_button_get_color(color_S1,&color);
					cairo_set_source_rgb(cr,(double)color.red/65535,(double)color.green/65535,(double)color.blue/65535);
					//se divide entre/65535 para convertir los formatos de representacion de los colores
					break;
			case 1: 
					gtk_color_button_get_color(color_S2,&color);
					cairo_set_source_rgb(cr,(double)color.red/65535,(double)color.green/65535,(double)color.blue/65535);
					//se divide entre/65535 para convertir los formatos de representacion de los colores
					break;
			case 2: gtk_color_button_get_color(color_S3,&color);
					cairo_set_source_rgb(cr,(double)color.red/65535,(double)color.green/65535,(double)color.blue/65535);
					//se divide entre/65535 para convertir los formatos de representacion de los colores
					break;
			case 3: gtk_color_button_get_color(color_S4,&color);
					cairo_set_source_rgb(cr,(double)color.red/65535,(double)color.green/65535,(double)color.blue/65535);
					//se divide entre/65535 para convertir los formatos de representacion de los colores
					break;
			}

			
			valorX=0;
			valorY=0;
			i=0;
			while(i<(filas-1))
			{
				if ((coordx[i])>=0)
				{
					//aqui se dibujan solo puntos
					if(dots)
					{	//se desplazan las coord X para centrarlas en el punto
						valorX=
						(MARCO/cabeza->factorX)
						+ coordx[i]*unidadX
						-cabeza->desplazamientoX*unidadX;
						
						valorY=
						(MARCO/cabeza->factorY)
						+ (ANCHO_PANTALLA/cabeza->factorY )
						+ cabeza->desplazamientoY*unidadY
						- coordy[j][i]*unidadY;
						
						cairo_move_to(cr,valorX-3,valorY+3);
						cairo_show_text (cr, "X");
					}
					else
					{ //dibujo de las señales completas
						valorX = 
						(MARCO/cabeza->factorX)
						+ coordx[i]*unidadX
						-cabeza->desplazamientoX*unidadX;
						
						valorY = 
						(MARCO/cabeza->factorY)
						+ (ANCHO_PANTALLA/cabeza->factorY )
						+ cabeza->desplazamientoY*unidadY
						-coordy[j][i]*unidadY;
						
						cairo_move_to(cr,valorX,valorY);
						
						valorX = 
						(MARCO/cabeza->factorX)
						+ coordx[i+1]*unidadX
						-cabeza->desplazamientoX*unidadX;
						
						valorY=
						(MARCO/cabeza->factorY )
						+ (ANCHO_PANTALLA/cabeza->factorY) 
						+ cabeza->desplazamientoY*unidadY
						-coordy[j][i+1]*unidadY;
						
						cairo_line_to(cr,valorX,valorY);
					}
				}
				i++;
			}
			cairo_stroke(cr);
		}
	}

//se desactiva el zoom para mostrar las escalas
	cairo_scale (cr,1/cabeza->factorX, 1/cabeza->factorY);
//Seleccion de color de fondo
	if (invertir)
	{
		cairo_set_source_rgb (cr,1, 1, 1);//Seleccion de color blanco
	}
	else
	{
		cairo_set_source_rgb (cr,0, 0, 0);//Seleccion de color negro
	}
//se ocultan los bordes de la señal que no se quieren mostrar
	cairo_rectangle (cr,0,0, ANCHO_PANTALLA+2*MARCO, MARCO-2);
	cairo_rectangle (cr,0,0, MARCO-2,ANCHO_PANTALLA+2*MARCO);
	cairo_rectangle (cr,0,ANCHO_PANTALLA+MARCO+2,ANCHO_PANTALLA+2*MARCO, ANCHO_PANTALLA+2*MARCO);
	cairo_rectangle (cr,ANCHO_PANTALLA+MARCO+2,0, ANCHO_PANTALLA+2*MARCO, ANCHO_PANTALLA+2*MARCO);
	cairo_fill (cr);

//Seleccion de color de las rejillas y leyendas
	if (invertir)
	{
		cairo_set_source_rgb (cr,0, 0, 0);//Seleccion de color negro
	}
	else
	{
		cairo_set_source_rgb (cr,1, 1, 1);//Seleccion de color blanco
	}

//se imprimen las escalas y sus valores despues de la señal
	cairo_set_line_width(cr,1);
	//eje vertical
	cairo_move_to(cr,MARCO,MARCO);
	cairo_line_to(cr,MARCO,MARCO+ANCHO_PANTALLA);
	//eje horizontal 
	cairo_move_to(cr,MARCO,MARCO+ANCHO_PANTALLA);
	cairo_line_to(cr,MARCO+ANCHO_PANTALLA,MARCO+ANCHO_PANTALLA);
	//lineas de escala
	
	for(i=0;i<=10;i++)
	{
		//escala eje horizontal
		cairo_move_to(cr,(i+1)*MARCO,MARCO+ANCHO_PANTALLA);
		cairo_line_to(cr,(i+1)*MARCO,MARCO+ANCHO_PANTALLA+10);
		//escala eje vertical
		cairo_move_to(cr,40,(i+1)*MARCO);
		cairo_line_to(cr,50,(i+1)*MARCO);
	}
	//VALORES DE LAS DIVISIONES DEL EJE X E Y
	cairo_font_extents_t fe;
	cairo_text_extents_t te;
	cairo_font_extents (cr, &fe);
	int division=0;
	char cadena[10];
	
    cairo_text_extents (cr, "EJE Y", &te);
    cairo_move_to (cr,10,25);
    cairo_show_text (cr, "EJE Y");
	//valores de divisiones eje Y
	for (division=0;division<=10;division++) 
	{
		cairo_move_to (cr,10,550-50*division);
		sprintf(cadena,"%.1f",cabeza->desplazamientoY+(division*50)/(cabeza->factorY*unidadY));
		cairo_show_text (cr, cadena);
	}

	cairo_text_extents (cr, "EJE X", &te);
    cairo_move_to (cr,250,590);
    cairo_show_text (cr, "EJE X");
	//valores de divisiones eje X
	for (division=0;division<=10;division++) 
	{
		cairo_move_to (cr,45+50*division,570);
		sprintf(cadena,"%.1f",cabeza->desplazamientoX+(division*50)/(cabeza->factorX*unidadX));
		cairo_show_text (cr, cadena);
	}
	
	cairo_stroke(cr);

//seleccion del modo de salida del dibujo
	switch(outputMode)
	{
	case 0: 
		//El dibujo se imprime en pantalla
		//en este caso no se hace nada especial
		break;
	case 1: 
		//el dibujo se guarda como fichero pdf
		cairo_show_page(cr);
		cairo_surface_destroy(surface);
		outputMode=0;
		break;
	case 2:
		//el dibujo se guarda como fichero svg
		cairo_surface_destroy(surface);
		outputMode=0;
		break;
	case 3: 
		//el dibujo se guarda como fichero png
		cairo_surface_write_to_png(surface,fileOutput);
		cairo_surface_destroy(surface);
		outputMode=0;
		break;
	}
	cairo_destroy(cr);
	//se actualiza los maximos y los minimos de la señal seleccionada
	buscar_max_min(selecMaxMin);

}

//**************************************************************************
//funcion que atiende al evento que muestra la ventana y se redirecciona a
//la funcion que redibuja la pantalla
//**************************************************************************
gboolean on_drawingarea1_expose_event(GtkWidget *widget,GdkEventExpose *event,gpointer data)
{
//evento expose_event muestra el area de dibujo
 draw_plot();

return FALSE;
}

//**************************************************************************
//funcion que atiende al evento de pulsar con el boton del raton en la ventana
//**************************************************************************
gboolean on_window_button_press_event(GtkWidget *widget, GdkEventButton *event,
    gpointer user_data)
{

    if (event->button == 1) //boton izquierdo
	{
		//se almacenan temporalmente las coordenadas por si se realiza un zoom
		inicioXtemporal=(event->x);
		inicioYtemporal=(event->y);
    }

    if (event->button == 3) //boton derecho
	{
		//vuelve a una posicion anterior del zoom
		if ((cabeza->siguiente)!=NULL)//condicion para si solo hay un elemento
		{
			struct listaZoom *borrar;
			borrar = cabeza;
			cabeza =(cabeza)->siguiente;
			free(borrar);
		}
		calcular_zoom();
		draw_plot();//redibuja toda la pantalla 
    }
    return TRUE;
}

//****************************************************************************
//funcion que atiende al evento de soltar con el boton del raton en la ventana
//****************************************************************************
gboolean on_window_button_release_event(GtkWidget *widget, GdkEventButton *event,
    gpointer user_data)
{
    if (event->button == 1)
	{   //evento soltar el boton izquierdo del raton
		//se evalua si las coordenadas de inicio y diagonal son iguales
		if((inicioXtemporal!=event->x)&&(inicioYtemporal!=event->y))
		{   //si son distintas realizamos zoom
			//se inserta nuevo elemento en la listaZoom
			struct listaZoom *nuevo;
			nuevo = (struct listaZoom *) malloc(sizeof(struct listaZoom));
			nuevo->siguiente = cabeza;
			cabeza = nuevo;
			cabeza->inicioX = inicioXtemporal-50;;
			cabeza->inicioY = 575-inicioYtemporal;
			cabeza->diagonalX = (event->x)-50;
			cabeza->diagonalY = 575-(event->y);
			//estas condiciones permiten que el rectangulo se pueda hacer 
			//en cualquier sentido
			int temporal;
			if(cabeza->diagonalX<cabeza->inicioX)
			{
				temporal=cabeza->diagonalX;
				cabeza->diagonalX=cabeza->inicioX;
				cabeza->inicioX=temporal;
			}
		
			if(cabeza->inicioY<cabeza->diagonalY)
			{
				temporal=cabeza->diagonalY;
				cabeza->diagonalY=cabeza->inicioY;
				cabeza->inicioY=temporal;
			}
			//calculo de los desplazamientos parciales del fragmento de señal 
			//que se desea visualizar en pantalla
		
			cabeza->desplazamientoX=cabeza->siguiente->desplazamientoX
									+(cabeza->inicioX
									/cabeza->siguiente->factorX)/unidadX;
		    
			cabeza->desplazamientoY=cabeza->siguiente->desplazamientoY
									+(cabeza->diagonalY
									/cabeza->siguiente->factorY)/unidadY;
		}
		else
		{
			//esto se ejecuta cuando se ha pulsado y soltado en el mismo punto
			char cadena[10];
			int valorX;
			int valorY;
			
			valorX=((int)event->x-MARCO)/(cabeza->factorX*unidadX)
					+cabeza->desplazamientoX;
			
			sprintf(cadena,"%d",valorX);
			gtk_label_set_text(label_Xreal,cadena);
			
			valorY=((ANCHO_PANTALLA+MARCO*1.5-(int)event->y))
					/(cabeza->factorY*unidadY)
					+cabeza->desplazamientoY;
			sprintf(cadena,"%d",valorY);
			gtk_label_set_text(label_Yreal,cadena);
		}

			
		calcular_zoom();
		draw_plot();//redibuja toda la pantalla por si cambia el zoom
    }

    if (event->button == 3) 
	{//no se hace nada cuando se suelta el boton derecho
    }

    return TRUE;
}

//**************************************************************************
//funcion que recalcula los valores del zoom
//**************************************************************************
void calcular_zoom(void)
{
//calcula el zoom necesario para mostrar en pantalla la informacion 
//como el usuario a seleccionado
	cabeza->factorX=ANCHO_PANTALLA;
	cabeza->factorX=cabeza->factorX/(cabeza->diagonalX-cabeza->inicioX);
	cabeza->factorY=ANCHO_PANTALLA;
	cabeza->factorY=cabeza->factorY/(cabeza->inicioY-cabeza->diagonalY);
	if (cabeza->siguiente!=NULL)
	{
		cabeza->factorX=cabeza->factorX*cabeza->siguiente->factorX;
		cabeza->factorY=cabeza->factorY*cabeza->siguiente->factorY;
	}
	char cadena[10];
	sprintf(cadena,"%.2f",cabeza->factorX);
	gtk_label_set_text(label_zoom_X,cadena);
	sprintf(cadena,"%.2f",cabeza->factorY);
	gtk_label_set_text(label_zoom_Y,cadena);
}

//**************************************************************************
//Funciones que atienden a los eventos de los botones de aumentar y disminuir 
//los valores del zoom tanto en el eje x como en el y en incrementos de 0.5
//**************************************************************************
void on_button1_clicked(GtkWidget *widget,gpointer user_data)
{	//aumenta el zoom X
	if (cabeza->factorX<10)
	{
		cabeza->factorX=cabeza->factorX+0.5;
	}
	char cadena[10];
	sprintf(cadena,"%.2f",cabeza->factorX);
	gtk_label_set_text(label_zoom_X,cadena);
	draw_plot();
}
void on_button2_clicked(GtkWidget *widget,gpointer user_data)
{	//disminuir zoom x
	if (cabeza->factorX>1)
	{
		cabeza->factorX=cabeza->factorX-0.5;
	}
	char cadena[10];
	sprintf(cadena,"%.2f",cabeza->factorX);
	gtk_label_set_text(label_zoom_X,cadena);
	draw_plot();
}
void on_button3_clicked(GtkWidget *widget,gpointer user_data)
{   //aumentar zoom y
	if (cabeza->factorY<10)
	{
		cabeza->factorY=cabeza->factorY+0.5;
	}
	char cadena[10];
	sprintf(cadena,"%.2f",cabeza->factorY);
	gtk_label_set_text(label_zoom_Y,cadena);
	draw_plot();
}
void on_button4_clicked(GtkWidget *widget,gpointer user_data)
{   //"disminuir zoom y
	if (cabeza->factorY>1)
	{
		cabeza->factorY=cabeza->factorY-0.5;
	}
	char cadena[10];
	sprintf(cadena,"%.2f",cabeza->factorY);
	gtk_label_set_text(label_zoom_Y,cadena);
	draw_plot();
}

//**************************************************************************
//funciones de los botones que selecciona la señal de la cual se desea mostrar
//los maximos y los minimos
//**************************************************************************
void on_button5_clicked(GtkWidget *widget,gpointer user_data)
{
	gtk_label_set_text(label_seleccionada,"1");
	selecMaxMin=0;
	buscar_max_min(selecMaxMin);
}

void on_button6_clicked(GtkWidget *widget,gpointer user_data)
{
	gtk_label_set_text(label_seleccionada,"2");
	selecMaxMin=1;
	buscar_max_min(selecMaxMin);
}

void on_button7_clicked(GtkWidget *widget,gpointer user_data)
{
	gtk_label_set_text(label_seleccionada,"3");
	selecMaxMin=2;
	buscar_max_min(selecMaxMin);
}

void on_button8_clicked(GtkWidget *widget,gpointer user_data)
{
	gtk_label_set_text(label_seleccionada,"4");
	selecMaxMin=3;
	buscar_max_min(selecMaxMin);
}

//**************************************************************************
//funcion que calcula los valores maximos y minimos de las señales que 
//aparecen en pantalla
//**************************************************************************
void buscar_max_min(int numero)
{
	//se buscan los maximos y los minimos
	int i=0;
	int xmin=0;   //valores de X e Y max y min
	int xmax=0;
	int ymax=0;
	int ymin=0;
	if(numero<columnas)
	{
		xmin=coordx[i];
		xmax=coordx[i];
		ymin=cabeza->desplazamientoY+(cabeza->inicioY-cabeza->diagonalY);
		//ymax=coordy[numero][i];
		ymax=cabeza->desplazamientoY;
		while (i<filas)
		{
			//condicion para que los maximos y los minimos esten dentro de la
			//la parte de la ventana que se a ampliado con el zoom
			if((coordx[i]>=cabeza->desplazamientoX)&&
				(coordx[i]<=(cabeza->desplazamientoX+
				(cabeza->diagonalX-cabeza->inicioX)))&&
			    (coordy[numero][i]>=cabeza->desplazamientoY)&&
			    (coordy[numero][i]<=(cabeza->desplazamientoY+
			    (cabeza->inicioY-cabeza->diagonalY))))
			{
				//condicion para encontrar el minimo
				if (ymin>coordy[numero][i])
				{
					ymin=coordy[numero][i];
					xmin=coordx[i];
				}
				//condicion para encontrar el maximo
				if (ymax<coordy[numero][i])
				{
				    ymax=coordy[numero][i];
					xmax=coordx[i];
				}
			}
			i++;
		}
	}
	//se muestran los valores en las etiquetas
	char cadena[5];
	sprintf(cadena,"%d",xmax);
	gtk_label_set_text(label_Xmax,cadena);
	sprintf(cadena,"%d",ymax);
	gtk_label_set_text(label_Ymax,cadena);
	sprintf(cadena,"%d",xmin);
	gtk_label_set_text(label_Xmin,cadena);
	sprintf(cadena,"%d",ymin);
	gtk_label_set_text(label_Ymin,cadena);
}

//**************************************************************************
//funcion que atiende al evento del boton que resetea el zoom
//**************************************************************************
void on_RESET_ZOOM_clicked(GtkWidget *widget, gpointer data)
{
		reset_ZOOM();
		draw_plot();//redibuja toda la pantalla 

}

//funcion que resetea el zoom
//puede ser por la pulsacion del boton o por que se ha abierto una fichero nuevo
void reset_ZOOM(void)
{
		struct listaZoom *borrar;
		//vuelve a la posicion inicial del zoom
		while ((cabeza->siguiente)!=NULL)//condicion para si solo hay un elemento
		{
			borrar = cabeza;
			cabeza =(cabeza)->siguiente;
			free(borrar);
		}
		calcular_zoom();
}

//**************************************************************************
//funcion que lee los datos de un fichero seleccionado previamente
//**************************************************************************
void read_data(void)
{	
	FILE *fichero;
	
	int i=0;//indice para recorrer el array
	int j=0;
	if((fichero=fopen(fileOpen,"r"))==NULL)
	{
		gtk_label_set_text(label_x,"ERROR EN LA APERTURA DEL FICHERO. ES POSIBLE QUE NO EXISTA");
	}  
	else
	{
		gtk_label_set_text(label_x,"fichero abierto correctamente");
	}  
	char temp[5];
	
	//en la primera linea leemos las filas y las columnas del fichero
	fscanf(fichero,"%d %d",&filas,&columnas);

	//solicitud de memoria para los arrays segun lo leido antes
	coordx= (int *)malloc (filas*sizeof(int));
	
	coordy = ((int **)malloc (columnas*sizeof(int *)));
	
	for(j=0;j<columnas;j++)
		{
			coordy[j]= (int *)malloc (filas*sizeof(int ));	
		}
	i=0;
	while(!feof(fichero))
	{
		fscanf(fichero,"%d",&coordx[i]);
		for(j=0;j<columnas;j++)
		{
			fscanf(fichero,"%d",&coordy[j][i]);
		}
		i++;
	}

	sprintf(temp,"%d", filas);
	
	gtk_label_set_text(label_x,temp);
	 
	fclose(fichero);


	reset_ZOOM ();
	buscar_limites();
	draw_plot ();		
}

//**************************************************************************
//Funcion que lee los datos directamente la linea de comandos 
//usa el mismo formato que en los ficheros de datos
//**************************************************************************
void read_standar(int argc, char *argv[])
{	
	//como minimo tienes que haber 6 parametros para poder construir una señal
	if (argc>6)
	{
		int i=0;//indices para las filas
		int j=0;//indice para las columnas
		int k=0;//indice para los argumentos
		char temp[5];//cadena temporal

		filas=atoi(argv[1]);
		columnas=atoi(argv[2]);
		k=3;
		
		//solicitud de memoria para los arrays segun lo anterior
		coordx= (int *)malloc (filas*sizeof(int));
		coordy = ((int **)malloc (columnas*sizeof(int *)));
	
		for(j=0;j<columnas;j++)
		{
			coordy[j]= (int *)malloc (filas*sizeof(int ));	
		}
	
		//se capturan todos los valores de las señales	
		while(k<argc)
		{
			coordx[i]=atoi(argv[k]);
			printf("\n el valor x del parametro es: %s y convertido: %d   \n", argv[k],coordx[i]);
			k++;
		
			for(j=0;j<columnas;j++)
			{
				coordy[j][i]=atoi(argv[k]);
				printf("\n el valor y[%d] del parametro es: %s y convertido: %d   \n",j, argv[k],coordy[j][i]);
				k++;
			}
		i++;
		}
		sprintf(temp,"%d", columnas);			
		gtk_label_set_text(label_x,temp);
		
		buscar_limites();
		draw_plot ();		
	}
}

//**************************************************************************
//funcion que busca los limites max y min de x y de y de todas las señales
//para realizar los desplazamientos iniciales y ajustar las señales
//al tamaño de la ventana
//**************************************************************************
void buscar_limites(void)
{
	int i=0;
	int j=0;
	int limiteXmin=coordx[0];
	int limiteXmax=coordx[filas-1];
	int limiteYmin=0;
	int limiteYmax=0;
	
	for (j=1;j<columnas;j++)
	{
		for (i=0;i<filas;i++)
		{
			if (limiteYmin>coordy[j][i])
			{
				limiteYmin=coordy[j][i];
			}
			if (limiteYmax<coordy[j][i])
			{
			    limiteYmax=coordy[j][i];
			}
		}
	}
	cabeza->desplazamientoX=limiteXmin;
	cabeza->desplazamientoY=limiteYmin;
	//se calculan las proporciones de cada pixel para ajustar las señales
	//al tamaño de la ventana
	unidadX = ANCHO_PANTALLA;
	unidadX = unidadX/(limiteXmax-limiteXmin);
	unidadY = ANCHO_PANTALLA;
	unidadY = unidadY/(limiteYmax-limiteYmin);
}

//**************************************************************************
//funcion abre la ventana emergente para seleccion de fichero de entrada
//**************************************************************************
void on_imagemenuitem1_activate(GtkWidget *widget, gpointer data)
{
GtkWidget *dialog;
dialog = gtk_file_chooser_dialog_new ("Open File",
				      GTK_WINDOW(window),
				      GTK_FILE_CHOOSER_ACTION_OPEN,
				      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
				      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
				      NULL);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
	{  
    fileOpen = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
	//se muestra la ruta en el label de la ventana...
	gtk_label_set_text(label_x,fileOpen);

	}
gtk_widget_destroy (dialog);
	
	read_data();
}

//**************************************************************************
//funcion abre la ventana emergente para seleccion de fichero de salida
//**************************************************************************
void on_imagemenuitem2_activate(GtkWidget *widget, gpointer data)
{
	GtkWidget *dialog;
	dialog = gtk_file_chooser_dialog_new ("Save File as PNG",
				      GTK_WINDOW(window),
				      GTK_FILE_CHOOSER_ACTION_SAVE,
				      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
				      GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
				      NULL);
	
	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
	{  
		fileOutput = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
		//se muestra la ruta en el label de la ventana...
		gtk_label_set_text(label_x,fileOutput );
		outputMode=3;
		draw_plot ();
	}
	gtk_widget_destroy (dialog);
}

//**************************************************************************
//funcion abre la ventana emergente para seleccion de fichero de salida	
//**************************************************************************
void on_imagemenuitem3_activate(GtkWidget *widget, gpointer data)
{
	GtkWidget *dialog;
	dialog = gtk_file_chooser_dialog_new ("Save File as SVG",
				      GTK_WINDOW(window),
				      GTK_FILE_CHOOSER_ACTION_SAVE,
				      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
				      GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
				      NULL);
	
	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
	{  
		fileOutput  = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
		//se muestra la ruta en el label de la ventana...
		gtk_label_set_text(label_x,fileOutput );
		outputMode=2;
		draw_plot ();
	}
	gtk_widget_destroy (dialog);
}

//**************************************************************************
//funcion abre la ventana emergente para seleccion de fichero de salida
//**************************************************************************
void on_imagemenuitem4_activate(GtkWidget *widget, gpointer data)
{
	GtkWidget *dialog;
	dialog = gtk_file_chooser_dialog_new ("Save File as PDF",
				      GTK_WINDOW(window),
				      GTK_FILE_CHOOSER_ACTION_SAVE,
				      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
				      GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
				      NULL);
	
	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
	{  
	  fileOutput = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
		//se muestra la ruta en el label de la ventana...
		gtk_label_set_text(label_x,fileOutput);
		outputMode=1;
		draw_plot ();
	} 
	gtk_widget_destroy (dialog);
}

//**************************************************************************
//Funcion que se ejecuta cuando cualquiera de los selectores de los selectores
//de color ha cambiado su valor y actualiza los nuevos colores
//**************************************************************************
void on_colorbutton_color_set(GtkWidget *widget, gpointer data)
{
	draw_plot();
}

