/*
 * Created on May 14, 2005
 *
 */
package com.kellegous.mas864.clusterss;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.font.TextLayout;
import java.awt.image.BufferedImage;
import java.util.Iterator;

import javax.swing.JPanel;

import Jama.Matrix;

/**
 * @author knorton
 * Copyright (C) 2005 MIT Media Lab, All Right Reserved.
 */
public class KernelViewPanel extends JPanel implements MouseMotionListener, MouseListener {
    private static Color[]	COLOURS;
    
	private BufferedImage		kernelImg = null;
	private int				minSize = 300;
	private Matrix			kernelMat = null;
	private int[]			clusterMp = null;
    private String            value = null;
	
	
	static {
	    final int th = 60;
	    final int st = 360/th;
	    COLOURS = new Color[st<<1];
	    for (int i=0;i<st;i++) {
	        COLOURS[i]=Color.getHSBColor((i*th)/360f,.8f,.8f);
	        COLOURS[i+st]=Color.getHSBColor((i*th)/360f,.4f,.8f);
	    }
	}
	
	public KernelViewPanel() {
	    this.setBackground(Color.GREEN);
		this.setPreferredSize(new Dimension(200,200));
		this.addMouseMotionListener(this);
		this.addMouseListener(this);
	}
	
    public void reset() {
    	    this.kernelImg=null;
    	    this.kernelMat=null;
    	    this.clusterMp=null;
    }
    
	private void renderKernel() {
        
	    Matrix kernel = this.kernelMat;
	    int sz = Math.max(
	            kernel.getRowDimension(),
	            minSize);
	    this.setSize(sz,sz);
	    this.setPreferredSize(
	            new Dimension(sz,sz));
	    
		this.setBackground(Color.WHITE);
		BufferedImage bi = new BufferedImage(
				kernel.getRowDimension(),
				kernel.getColumnDimension(),
				BufferedImage.TYPE_3BYTE_BGR);
		
		double max = Double.MIN_VALUE;
		double min = Double.MAX_VALUE;
		
		for (int i=0;i<kernel.getRowDimension();i++) {
			for (int j=0;j<kernel.getColumnDimension();j++) {
				double v = kernel.get(i,j);
				if (v>max)
					max = v;
				if (v<min)
					min = v;
			}
		}
		int[] 	cm = this.clusterMp;
		float[]	cl = new float[3];
		for (int i=0;i<kernel.getRowDimension();i++) {
			for (int j=0;j<kernel.getColumnDimension();j++) {
	            float a = (float)((kernel.get(i,j)-min)/(max-min));			    
			    if (cm != null) {
			        cl = COLOURS[cm[j]%COLOURS.length].getRGBColorComponents(cl);
			        cl[0]=cl[0]*a+(1f-a);
			        cl[1]=cl[1]*a+(1f-a);
			        cl[2]=cl[2]*a+(1f-a);
			        bi.setRGB(j,i,new Color(cl[0],cl[1],cl[2]).getRGB());
			    }
			    else {
			        int v = (int)(255f*a);
			        bi.setRGB(j,i,(v<<16)+(v<<8)+v);
			    }
			}
		}
		this.kernelImg = bi;
		this.repaint();
	    
	}
	
	public void setClusters(Cluster[] clusters) {
	    if (this.kernelMat==null)
	        return;
	    int[] cm = new int[this.kernelMat.getRowDimension()];
	    for (int i=0;i<clusters.length;i++)
	        for (Iterator it=clusters[i].iterator();it.hasNext();)
	            cm[((Integer)it.next()).intValue()]=i;
	    this.clusterMp = cm;
	    this.renderKernel();
	}
	
	public void setKernelMatrix(Matrix kernel) {
	    this.kernelMat = kernel;
	    this.renderKernel();
	}
	
    public void mouseDragged(MouseEvent e) {
    }
    
    public void mouseMoved(MouseEvent e) {
        if (this.kernelImg==null || this.kernelMat==null)
            return;
        
        int n = this.kernelMat.getColumnDimension();
        int x = e.getX();
        int y = e.getY();
        
        if (n<minSize) {
            x -= (this.getWidth()>>1)-(minSize>>1);
            y -= (this.getHeight()>>1)-(minSize>>1);
            x = (n*x)/minSize;
            y = (n*y)/minSize;
        }
        else {
            x -= (this.getWidth()>>1)-(this.kernelImg.getWidth()>>1);
            y -= (this.getHeight()>>1)-(this.kernelImg.getHeight()>>1);            
        }
      
        if (x>=0 && x<n && y>=0 && y<n) {
            value = "("+x+","+y+") "+this.kernelMat.get(x,y);
        }
        else {
        	    value = null;
        }
        this.repaint();        
    }
    
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D gg = (Graphics2D)g;
		gg.setColor(Color.WHITE);
		gg.fillRect(0,0,this.getWidth(),this.getHeight());	
		if (this.kernelImg != null) {
		    boolean sc = (this.kernelImg.getWidth()<this.minSize);
		    int 
		    		sx=(sc)?minSize:this.kernelImg.getWidth(),
		    		sy=(sc)?minSize:this.kernelImg.getHeight();
		    int ox=(sx<this.getWidth())
		    			?(this.getWidth()>>1)-(sx>>1)
		    			:0;
		    int oy=(sy<this.getHeight())
		    			?(this.getHeight()>>1)-(sy>>1)
		    			:0;
		    			
		    if (sc) {
		        gg.drawImage(
		                this.kernelImg,
		                ox,oy,ox+sx,oy+sy,
		                0,0,this.kernelImg.getWidth(),this.kernelImg.getHeight(),
		                this);
		    }
		    else {
		        gg.drawImage(
		                this.kernelImg,
		                ox,oy,this);
		    }
		    
		    gg.setColor(Color.BLACK);
		    gg.drawRect(ox,oy,sx,sy);
            
            if (value != null) {
            	    TextLayout tl = new TextLayout(
                    this.value,
                    this.getFont(),
                    gg.getFontRenderContext());
            	    gg.setColor(Color.BLACK);
            	    tl.draw(gg,ox+5,oy+this.getVisibleRect().y+(float)tl.getBounds().getHeight()+5);
            }
            
		}
	}

	public void mouseClicked(MouseEvent arg0) {
	}
    
	public void mouseEntered(MouseEvent arg0) {
	}
    
	public void mouseExited(MouseEvent arg0) {
        this.value = null;
	}
    
	public void mousePressed(MouseEvent arg0) {
	}
    
	public void mouseReleased(MouseEvent arg0) {
	}
}
