package com.FitBank.web.servlet;

import com.FitBank.web.util.EjecutarEventos;
import com.FitBank.xml.Mensaje.DatoGeneral;
import com.FitBank.xml.Mensaje.MensajeXml;

import de.progra.charting.*;
import de.progra.charting.model.*;
import de.progra.charting.render.*;

import java.awt.*;

import java.text.DecimalFormat;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Vector;

/**
 * Servlet que muestra un gráfico basado en los parametros que se le envian
 * Usa JOpenChart para graficar.
 */
public class Graficador extends BaseServlets {
  private static final String CONTENT_TYPE = "image/png";

  protected void inicializar() {
    aceptarGet();
    aceptarPost();
    verificarSesion();
  }

  protected void procesarPedido() {
    respuesta.setContentType(CONTENT_TYPE);
    //System.out.println("procesando pedido");
    // Obtener los datos para el grafico del pedido
    String[] titulos = pedido.getParameter("titulo").split(",");
    String[] tipos = pedido.getParameter("tipos").split(",");
    
    
    String[] nombres = pedido.getParameter("nombres").split(",");
    String[] datosTotal;
    String[] leyendas;
    
    String metodoGrafico = pedido.getParameter("metodo");

    if (metodoGrafico.equalsIgnoreCase("post"))
    {      
      String[] datosTemp = pedido.getParameter("datos").split(",");
      String tempLeyendas = pedido.getParameter("leyendas");
      leyendas = pedido.getParameterValues(tempLeyendas);      
      String[] values = pedido.getParameterValues(datosTemp[0]);
      datosTotal = new String[datosTemp.length];
      for (int i=0;i<datosTemp.length;i++){
        values = pedido.getParameterValues(datosTemp[i]);
        String temp= "";
        for (int j=0;j<values.length;j++){
          if (j!=values.length-1)
            temp += values[j]+","; 
          else
            temp += values[j];
        }
        datosTotal[i] = temp;
      }
    }
    else if(metodoGrafico.equalsIgnoreCase("con"))
    {
      String[] datosTemp = pedido.getParameter("datos").split(",");
      String valoresX = pedido.getParameter("leyendas");
      EjecutarEventos eventoGraf = new EjecutarEventos();
      Vector cabe    = (Vector)evento.procesoXml.getXmlMensaje().encabezado;
      eventoGraf.procesoXml.setXmlMensaje(new MensajeXml());
      for(int i = 0; i < cabe.size(); i++)
          eventoGraf.procesoXml.getXmlMensaje().encabezado.add(cabe.elementAt(i));
      eventoGraf.ejecutarConsultaGrafico(valoresX,datosTemp,pedido);
      LinkedHashMap map = eventoGraf.procesoXml.cargarCampos(1);
      Object[] leyendaObj  = ((Vector)map.get(valoresX)).toArray();
      leyendas =  new String[leyendaObj.length];
      for(int i=0;i<leyendaObj.length;i++)
        leyendas[i]=(String)leyendaObj[i];
      datosTotal = new String[datosTemp.length]; 
      for (int i=0;i<datosTemp.length;i++){
        Object[] valuesObj = (Object[])((Vector)map.get(datosTemp[i])).toArray();
        String temp= "";
        for (int j=0;j<valuesObj.length;j++){
          if (j!=valuesObj.length-1)
            temp += (String)(valuesObj[j])+","; 
          else
            temp += (String)valuesObj[j];
        }
        datosTotal[i] = temp;
      }      
    }
    else
    {
      leyendas = pedido.getParameter("leyendas").split(",");
      datosTotal = pedido.getParameter("datos").split(";");
    }
    
    int width = pedido.getParameterMap().containsKey("w") ?
                Integer.parseInt(pedido.getParameter("w")) : 640;
    int height = pedido.getParameterMap().containsKey("h") ?
                 Integer.parseInt(pedido.getParameter("h")) : 480;

    // dividir los datos y crear un array de dos dimensiones
    int largo = datosTotal[0].split(",").length;
    double[][] datos = new double[datosTotal.length][largo];
    
    for(int a = 0; a < datosTotal.length; a++) {
      String[] datosParcial = datosTotal[a].split(",");
      for(int b = 0; b < largo; b++){
        //System.out.println(leyendas[b]+ " , " +datosParcial[b]);
        datos[a][b] = Double.parseDouble(datosParcial[b]);
      }
    }
    
    /////////////////////////////////////////////////////////////////////////
    // Crear un modelo para los datos
    AbstractChartDataModel data;
    
    try {
      // Este codigo permite valores en el eje X no uniformes
      double[] leyendasDouble = new double[leyendas.length];
      double minX = Double.parseDouble(leyendas[0]);
      double maxX = Double.parseDouble(leyendas[0]);
       
      for(int a = 0; a < leyendas.length; a++) {
        leyendasDouble[a] = Double.parseDouble(leyendas[a]);
        minX = Math.min(leyendasDouble[a], minX);
        maxX = Math.max(leyendasDouble[a], maxX);
      }

      if(tipos[0].equalsIgnoreCase("barras") ||
         tipos[0].equalsIgnoreCase("barras2")) {
        data = new ObjectChartDataModel(datos, leyendas, nombres);

      } else {
        data = new DefaultChartDataModel(datos, leyendasDouble, nombres);
        data.setMinimumColumnValue(minX);
        data.setMaximumColumnValue(maxX);

      }

    } catch (Exception e) {
      // en caso de que no sean numeros tratarlos como etiquetas
      data = new ObjectChartDataModel(datos, leyendas, nombres);

    }

    // Establecer los limites en el eje Y
    // tener cuidado con los limites por que no se pueden usar si se usa valores
    // no uniformes para el eje X si no se limita el eje X (ver mas arriba)
    String mini = pedido.getParameterMap().containsKey("min") ? pedido.getParameter("min") : "0";
    String maxi = pedido.getParameterMap().containsKey("max") ? pedido.getParameter("max") : "0";
   
    double min = pedido.getParameterMap().containsKey("min") ?
                   Double.parseDouble(pedido.getParameter("min")) : datos[0][0];
    double max = pedido.getParameterMap().containsKey("max") ?
                   Double.parseDouble(pedido.getParameter("max")) : datos[0][0];

    if(tipos[0].equalsIgnoreCase("barras2")) {
      for(int b = 0; b < datos[0].length; b++) {
        double totalPos = 0;
        double totalNeg = 0;
        for(int a = 0; a < datos.length; a++) {
          if(datos[a][b] > 0) totalPos += datos[a][b];
          else                totalNeg += datos[a][b];
        }

        min = Math.min(totalPos, min);
        max = Math.max(totalPos, max);
        min = Math.min(totalNeg, min);
        max = Math.max(totalNeg, max);

      }

    } else {
      for(int a = 0; a < datos.length; a++) {
        for(int b = 0; b < datos[a].length; b++) {
          min = Math.min(datos[a][b], min);
          max = Math.max(datos[a][b], max);
        }
      }

    }

    // ajustar limites linealmente
    if(min == 0 && max == 0) {
      min -= 10;
      max += 10;

    } else if(min == max) {
      min -= Math.abs(min * 0.05);
      max += Math.abs(max * 0.05);

    } else {
      if(min != 0) min -= (max - min) * 0.05;
      if(max != 0) max += (max - min) * 0.05;

    }
    
    int pow = (int)Math.pow(10, Math.floor(Math.log(max - min) /
                                           Math.log(10)));

    min = Math.floor(min / pow) * pow;
    max = Math.ceil(max / pow) * pow;

    // setear minimos y máximos
    if(!mini.equals("0")) min = Double.parseDouble(mini);
    if(!maxi.equals("0")) max = Double.parseDouble(maxi);
    if(min==max) { if(max==0) max=10; else max+=0.1*max; }
    else if(min>max) {
      double aux=min;
      min=max;
      max=aux;
    }
    data.setMinimumValue(new Double(min));
    data.setMaximumValue(new Double(max));
    data.setManualScale(true);

    DefaultChart c = new DefaultChart(data, titulos[0],
                                      DefaultChart.LINEAR_X_LINEAR_Y);

    CoordSystem coord = new CoordSystem(data, new DecimalFormat(), true,
                                        false, tipos.length < 2);
    coord.setXAxisUnit(titulos[1]);
    coord.setYAxisUnit(titulos[2]);
    c.setCoordSystem(coord);

    // Seleccionar el tipo de grafico
    if(tipos[0].equalsIgnoreCase("barras2")) {
      c.addChartRenderer(new StackedBarChartRenderer(c.getCoordSystem(), data,
                                                     0.9f),
                         1);

    } else if(tipos[0].equalsIgnoreCase("barras")) {
      c.addChartRenderer(new BarChartRenderer(c.getCoordSystem(), data,
                                              null, null, 0.9f),
                         1);

    } else if(tipos[0].equalsIgnoreCase("lineas2")) {
      c.addChartRenderer(new PlotChartRenderer(c.getCoordSystem(), data), 1);
      c.addChartRenderer(new InterpolationChartRenderer(c.getCoordSystem(),
                                                        data), 2);

    } else /* tipos[0] == "lineas" */ {
      c.addChartRenderer(new PlotChartRenderer(c.getCoordSystem(), data), 1);
      c.addChartRenderer(new LineChartRenderer(c.getCoordSystem(), data), 2);

    }
    
    // Darle un tamaño
    c.setBounds(new Rectangle(0, 0, width, height));
    
    // Imprimir al navegador
    try {
      ChartEncoder.createEncodedImage(respuesta.getOutputStream(), c, "png");

    } catch(Exception e) {
      e.printStackTrace();

    }

  }

}