/*
 * BaseVisualization.java
 *
 * Created on April 27, 2006, 6:29 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package cz.pcland.gavisualization;

import cz.pcland.ga.GAConfiguration;
import cz.pcland.ga.GenerationInfo;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.awt.geom.*;
import java.awt.font.*;

/**
 *
 * @author petr
 */
public class BaseVisualization extends JPanel{
    Vector GAInfo;
    
    int xPoints;
    int yPoints;
    
    int bottomGap;
    int topGap;
    int leftGap;
    int rightGap;
    
    int drawAreaWidth;
    int drawAreaHeight;
    
    double vKoef;
    double hKoef;
    
    double maxValue;
    double minValue;
    
    double graphWidth;
    
    int yAxesLength;
    int xAxesLength;
    double xPointDistance;
    double yPointDistance;
    
    double lastXPoint = 0;
    double lastXDistribution = 0;
    
    String label = null;
    
    
    public void setParams(){
        yAxesLength  = getHeight() - (topGap + bottomGap);
        xAxesLength  = getWidth() - (leftGap + rightGap);
        
        xPointDistance = xAxesLength/xPoints;
        yPointDistance = (yAxesLength+1)/yPoints;
        
        /* correction*/
        xAxesLength = (int)(xPoints*xPointDistance);
        yAxesLength = (int)(yPoints*yPointDistance);
        
        
        /* in case we dont have enought generations, we draw only part of axes*/
        int xPointsLocal;
        if(((GenerationInfo)GAInfo.get(0)).getGenNum() < xPoints) {
            xPointsLocal = (int)((GenerationInfo)GAInfo.get(0)).getGenNum();
        }else xPointsLocal = xPoints;
        lastXPoint = xPointDistance*xPointsLocal;
    }
    
    
    public void drawXPoints(Graphics2D g2) {
        int xPointsLocal;
        if(((GenerationInfo)GAInfo.get(0)).getGenNum() < xPoints) {
            xPointsLocal = (int)((GenerationInfo)GAInfo.get(0)).getGenNum();
        }else xPointsLocal = xPoints;
        
        double value = 1;
        double interval = ((((GenerationInfo)GAInfo.get(0)).getGenNum())/xPointsLocal);
        //System.out.println(interval);
        for(double i=1;i<=xPointsLocal;i++) {
            g2.setColor(Color.black);
            g2.draw(new Line2D.Double(leftGap + xPointDistance*i, topGap + yAxesLength - 2, leftGap + xPointDistance*i, topGap + yAxesLength + 2));
            
            if(i == xPointsLocal) value = ((GenerationInfo)GAInfo.get(0)).getGenNum();
            g2.setColor(Color.blue);
            
            g2.drawString( String.valueOf( (int)value ), leftGap + (int)(xPointDistance*i) - 5, topGap + yAxesLength + 18);
            value += interval;
        }
    }
    
    public void drawYPoints(Graphics2D g2) {
        double interval = (double)Math.abs((double)maxValue-(double)minValue)/(double)yPoints;
        
        for(double i=0;i<=this.yPoints;i++) {
            g2.setColor(Color.black);
            if(i!=yPoints) g2.draw(new Line2D.Double(leftGap - 2, topGap + i*yPointDistance , leftGap + 2, topGap + i*yPointDistance));
            
 
            g2.setColor(Color.blue);
            double value = maxValue - (double)i*interval;
            g2.drawString( String.valueOf( (double)((int)(value*100))/100 ), 5, leftGap + (int)(i*yPointDistance)-16);
            
        }
    }
    
    public void drawAxes(Graphics2D g2){
        //y axes
        g2.draw(new Line2D.Float(leftGap, topGap, leftGap, topGap + yAxesLength));
        
        //x axes
        g2.draw(new Line2D.Float(leftGap, topGap + yAxesLength, leftGap + xAxesLength, topGap + yAxesLength));
        
        
        if(this.GAInfo == null || this.GAInfo.isEmpty()) return;
        
        drawXPoints(g2);
        drawYPoints(g2);
        
    }
    
    
    public void drawValue(Graphics2D g2, int genNum, double max, double avg, double min) {
        int xCoordinate = (int)(((double)this.lastXPoint/(double)((GenerationInfo)GAInfo.get(0)).getGenNum())*(double)genNum  +  this.leftGap);
        
        int yCoordinateMax = (int)( (double)yAxesLength - (  (double)(Math.abs(max - minValue)/(double)Math.abs(maxValue - minValue))  *  (double)this.yAxesLength ) + (double)this.topGap - 2.0d) ;
        int yCoordinateAvg = (int)( (double)yAxesLength - (  (double)(Math.abs(avg - minValue)/(double)Math.abs(maxValue - minValue))  *  (double)this.yAxesLength ) + (double)this.topGap - 2.0d) ;
        int yCoordinateMin = (int)( (double)yAxesLength - (  (double)(Math.abs(min - minValue)/(double)Math.abs(maxValue - minValue))  *  (double)this.yAxesLength ) + (double)this.topGap - 2.0d) ;


         
        if(xCoordinate < 0) xCoordinate = 0;
        if(yCoordinateMax < 0) yCoordinateMax = 0;
        if(yCoordinateAvg < 0) yCoordinateAvg = 0;
        if(yCoordinateMin < 0) yCoordinateMin = 0;
        

        
        g2.setColor(Color.ORANGE);
        Ellipse2D.Double point = new Ellipse2D.Double(xCoordinate,yCoordinateMax,3,3);
        g2.fill(point);
        
        g2.setColor(Color.green);
        point = new Ellipse2D.Double(xCoordinate,yCoordinateAvg,3,3);
        g2.fill(point);
        
        g2.setColor(Color.red);
        point = new Ellipse2D.Double(xCoordinate,yCoordinateMin,3,3);
        g2.fill(point);
    }
    
    
    public void drawDistribution(Graphics2D g2, double[] distribution ,int genIndex, double best, double lowest){
        
        double rectWidth = 0;
        
        
        double generations = ((GenerationInfo)(GAInfo.get(0))).getGenNum();
        double genNum = ((GenerationInfo)(GAInfo.get(genIndex))).getGenNum();
        double nextGenNum = 0;
        
        if(genIndex-1 >= 0) {
            nextGenNum = ((GenerationInfo)(GAInfo.get(genIndex-1))).getGenNum();
        }
        
        if(genNum == generations){ //last gen.
            
            
            rectWidth = this.lastXPoint + this.leftGap - lastXDistribution;
            
            
        }else if(genNum == 1){ //first gen.
            
            rectWidth =  (nextGenNum - genNum)/generations;
            rectWidth *= this.lastXPoint;
            //rectWidth /= 2;
            lastXDistribution = 0.0d + this.leftGap;
        } else { //gen. between 1st and last
            
            rectWidth =  (nextGenNum - genNum)/generations;
            rectWidth *= this.lastXPoint;
            
        }
        
        
        double x = lastXDistribution;
       

        
        double rectHeight =(((double)this.yAxesLength) * (Math.abs(lowest - best)/Math.abs(this.maxValue - this.minValue))  )/(double)GAConfiguration.distributionDensity;
        double y = (((double)this.yAxesLength) * (Math.abs(best - lowest)/Math.abs(this.maxValue - this.minValue) ) ) +  ( ((double)this.yAxesLength) - (Math.abs(best - this.minValue)/Math.abs(this.maxValue - this.minValue)) * ((double)this.yAxesLength) ) + this.topGap - rectHeight;
        
        for(int i=0;i<GAConfiguration.distributionDensity;i++){
            g2.setPaint(Color.getHSBColor(0.0f,0.0f,1.0f-(float)distribution[i]));
            g2.fill(new Rectangle2D.Double(x, y, rectWidth, rectHeight));
            
            y -= rectHeight;
        }
        lastXDistribution += rectWidth;
    }
    
    
    
    
    public void updateGraph(Vector data) {
        this.GAInfo = data;
        repaint();
    }
    
    /** Creates a new instance of BaseVisualization */
    public BaseVisualization(int xPoints, int yPoints, String label) {
        this.label = label;
        this.xPoints = xPoints;
        this.yPoints = yPoints;
        bottomGap = 35;
        topGap = 35;
        leftGap = 55;
        rightGap = 35;
    }
    
}
