/*
 * Created on Nov 15, 2006
 *
 * various ways of viewing EDL files
 * 
 */
package com.meapsoft.visualizer;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JPanel;

import com.meapsoft.DSP;
import com.meapsoft.EDLFile;
import com.meapsoft.FeatFile;

/**
 * @author douglas repetto
 *
 */

public class SegmentOrderRenderer extends Renderer
{		
	JCheckBox thickLines;
	JCheckBox multiLines;
	
	boolean thick = false;
	boolean multi = false;

	int currHeight = 0;
	int currWidth = 0;
	double currXMulti = 0.0;
	
	//amount of screen to use for top and bottom rows of blips
	double screenPercentage = .25;
	
	public SegmentOrderRenderer(FeatFile featFile, EDLFile eDLFile)
	{
		super(featFile, eDLFile, "SegmentOrderMapping");
	}
	
	public SegmentOrderRenderer(Renderer r)
	{
		super(r);
		
		//have to do this so we're not stuck with invalid
		//multipliers from another renderer
		updateColorMultipliers();
	}

	public void draw(Graphics graphics, int width, int height)
	{	
		int numChunks = events.size();
		
		//set up scaling factors
		ChunkVisInfo lastChunk = (ChunkVisInfo) events.elementAt(numChunks - 1);
		double xMulti = width/(lastStartTime + lastChunk.length);
		//use 1/4 of the screen for plotting blips
		double scaledHeight = height * screenPercentage;
		
		graphics.setColor(Color.white);//Color.lightGray);
		graphics.fillRect(0,0,width,height);
		
		int blipHeight = (int)(scaledHeight/numFeatures);
		
		for (int i = 0; i < numChunks; i++)
		{
			ChunkVisInfo cVI = (ChunkVisInfo) events.elementAt(i);
			
			int index = 0;
			for (int j = 0; j < numFeatures; j++)
			{
                int ndim = elementsPerFeature[j];

                // draw features in Matlab's 'axis xy' order
				// (i.e. lowest feature dimensions on the bottom)
				//for (int k = 0; k < ndim; k++)
                for (int k = ndim - 1; k >= 0; k--)
				{
                    int[] featNum = {index};
					double featureValue = cVI.getFeatures(featNum)[0];

                    featureValue -= lowestFeatureValue[j];
					/*
					if (colorMapType == SQRT)
					{
						featureValue -= lowestFeatureValue[j];
						featureValue = Math.sqrt(featureValue);
					}
					else if (colorMapType == SQUARE)
					{
						featureValue -= lowestFeatureValue[j];
						featureValue *= featureValue;
					}
					*/
                    double colorIndex = featureValue * colorMultipliers[j];
					
					//graphics.setColor(colormap.table[(int)colorIndex]);
					
					if (cVI.selected)
					{
						graphics.setColor(colormap.table[(int)colorIndex]);
					}
					else
					{
						Color c = colormap.table[(int)colorIndex].darker().darker().darker();
						graphics.setColor(c);
					}
					int x1 = (int)(cVI.startTime * xMulti);
					int blipWidth = (int)((cVI.startTime + cVI.length) * xMulti);
					blipWidth = blipWidth - x1;
                    int y = (int)(j * blipHeight + k*blipHeight/ndim);
	
					// int miniBlipHeight = blipHeight/ndim;
					// if (miniBlipHeight < 1)
                    //     miniBlipHeight = 1;
                    int miniBlipHeight = (blipHeight+ndim/2)/ndim;
						
					//draw top blip
					//if (cVI.selected)
					graphics.fillRect(x1, y, blipWidth, miniBlipHeight);

					//else
					//{
						//this is wonky, but if we always draw here then
						//multi-dimensional blips won't disappear when
						//they're deselected. Their rects are so small that
						//they just stack up and fill in all the space!
					//	if (k == 0)
					//		graphics.drawRect(x1, y, blipWidth, blipHeight);				
					//}
					
					//draw bottom blip
					if (eDLFile != null)
					{
						if (cVI.dstTime != -1.0)
						{
							int x2 = (int)(cVI.dstTime * xMulti);

							//int y2 = (height - y) - blipHeight/ndim; 
                            // draw the bottom blip in the same
                            // orientation as the top blip
                            int y2 = height - j*blipHeight - (ndim-k)*blipHeight/ndim;
							//if (cVI.selected)
								graphics.fillRect(x2, y2, blipWidth + 1, miniBlipHeight);
							//else
							//{
							//	if (k == 0)
							//		graphics.drawRect(x2, y2, blipWidth, blipHeight);
							//}							
							cVI.xEDL = x2;
							cVI.yEDL = y2;
						}
					}
					
					index++;

					cVI.xFeat = x1;
					cVI.yFeat = y;
					cVI.width = blipWidth;
					cVI.height = blipHeight;
				}
			}
		}
		
		//now do connections, if EDL file exists
		//we have to do it in its own loop, otherwise our messy chunk order
		//will result in lots of overlapping drawing!
		if (eDLFile != null)
		{
			for (int i = 0; i < numChunks; i++)
			{
				ChunkVisInfo cVI = (ChunkVisInfo) events.elementAt(i);
				
				int index = 0;
			
				for (int j = 0; j < numFeatures; j++)
				{
/*
					for (int k = 0; k < elementsPerFeature[j]; k++)
					{
						int[] featNum = {index};
						double[] values = cVI.getFeatures(featNum);
						double featureValue = values[0];
						
						if (colorMapType == SQRT)
						{
							featureValue -= lowestFeatureValue[j];
							featureValue = Math.sqrt(featureValue);
						}
						else if (colorMapType == SQUARE)
						{
							featureValue -= lowestFeatureValue[j];
							featureValue *= featureValue;
						}
						else
							featureValue -= lowestFeatureValue[j];
		
						double colorIndex = featureValue * colorMultipliers[j];
	
						graphics.setColor(colormap.table[(int)colorIndex]);
*/

                    int ndim = elementsPerFeature[j];

                    int[] featNum = DSP.irange(index, index+ndim-1);
                    double[] features = cVI.getFeatures(featNum);
                    features = DSP.minus(features, lowestFeatureValue[j]);
                    double featureValue = DSP.dot(features, features)/Math.sqrt(ndim);

                    featureValue = features[ndim-1];
                    /*
                    if (sqrtFeatureValues.isSelected())
                        featureValue = Math.sqrt(featureValue);
                    else if (squareFeatureValues.isSelected())
                        featureValue *= featureValue;
                    */
                    double colorIndex = featureValue * colorMultipliers[j];
                    
                    graphics.setColor(colormap.table[(int)colorIndex]);
					
                    int x1 = (int)(cVI.startTime * xMulti);
                    int blipWidth = (int)((cVI.startTime + cVI.length) * xMulti);
                    blipWidth = blipWidth - x1;
                    int y = (int)(j * blipHeight);
                    
                    if (cVI.dstTime != -1.0)
                    {
                        int x2 = (int)(cVI.dstTime * xMulti);
                        
                        //draw bottom blip
                        if (cVI.selected)
                        {								
                            //draw connection
                            if (multi)
                            {
                                graphics.drawLine(x1 + blipWidth/2, y + blipHeight, 
                                                  x2 + blipWidth/2, (height - y) - blipHeight);
                                if (thick)
                                    graphics.drawLine((x1 + blipWidth/2)+1, y + blipHeight, 
                                                      (x2 + blipWidth/2)+1, (height - y) - blipHeight);
                            }
                            else
                            {
                                if (j == numFeatures - 1)
                                {
                                    graphics.drawLine(x1 + blipWidth/2, y + blipHeight, 
                                                      x2 + blipWidth/2, (height - y) - blipHeight);
                                    if (thick)
                                        graphics.drawLine((x1 + blipWidth/2)+1, y + blipHeight, 
                                                          (x2 + blipWidth/2)+1, (height - y) - blipHeight);
                                }
                            }
                        }
                    }

                    index += ndim;

					graphics.setColor(Color.black);
					y = (blipHeight * j) + blipHeight;
					graphics.drawLine(0, y, width, y);
					graphics.drawLine(0, height - y, width, height - y);
				}
			}
		}

		if (dragRect != null)
		{
			//System.out.println("drawing: " + dragRect.toString());
			graphics.setColor(Color.black);
			graphics.drawRect(dragRect.x, dragRect.y, dragRect.width, dragRect.height);
		}
		
		currHeight = height;
		currWidth = width;
		currXMulti = xMulti;
	}

	public Vector getChunkVisInfosForPoint(Point p)
	{
		Vector chunks = new Vector();
		
		int whichFeature = getFeatureNumberForPoint(p);
		
		if (whichFeature != -1)
		{
			for (int i = 0; i < events.size(); i++)
			{
				ChunkVisInfo c = (ChunkVisInfo) events.elementAt(i);
				if (p.y >= 0 && p.y <= (currHeight * screenPercentage))
				{
					if (p.x >= c.xFeat && p.x <= (c.xFeat + c.width))
						chunks.add(c);
				}
				else if (p.y <= currHeight && p.y >= currHeight - (currHeight * screenPercentage))
				{
					if (p.x >= c.xEDL && p.x <= (c.xEDL + c.width))
						chunks.add(c);
				}
				
			}
		}

		return chunks;
	}
	
	public int getFeatureNumberForPoint(Point p)
	{
		int featureNumber = -1;
		
		if (featFile != null)
		{
			double scaledHeight = currHeight * screenPercentage;
			int blipHeight = (int)(scaledHeight/numFeatures);
			//this only happens when we start up if the mouse moves over display
			//before file is fully loaded/drawn
			if (blipHeight == 0)
				return featureNumber;
				
			int whichFeature = p.y/blipHeight;	

			//try top
			if (whichFeature < numFeatures && whichFeature >= 0)
			{
				featureNumber = whichFeature;
				return featureNumber;
			}
			
			//try bottom
			whichFeature = (currHeight - p.y)/blipHeight;
			if (whichFeature < numFeatures && whichFeature >= 0)
			{
				featureNumber = whichFeature;
				return featureNumber;
			}
		}
		
		return featureNumber;
	}
	
	public String getFeatureNameForPoint(Point p)
	{
		String featureName = "i don't know!";
		
		int whichFeature = getFeatureNumberForPoint(p);
		
		if (whichFeature != -1)
		{
			String fullFeatureName = (String) featFile.featureDescriptions.elementAt(whichFeature);
			//we're splitting on "." but have to use an escape sequence!
			String[] chunks = fullFeatureName.split("\\.");
			featureName = chunks[chunks.length-1];
		}
			
		return featureName;	
	}

	public double getFeatureValueForPoint(Point p)
	{
		double value = 0.0;
		
		int whichFeature = getFeatureNumberForPoint(p);
		
		if (whichFeature != -1)
		{
			for (int i = 0; i < events.size(); i++)
			{
				ChunkVisInfo cVI = (ChunkVisInfo) events.elementAt(i);
				
				if (p.y >= 0 && p.y <= (currHeight * screenPercentage))
				{
					if (p.x >= cVI.xFeat && p.x <= cVI.xFeat + cVI.width)
					{
						int[] featNum = {0};
						
						for (int j = 0; j < whichFeature; j++)
							featNum[0] += elementsPerFeature[j];
						value = cVI.getFeatures(featNum)[0];
						return value;
					}
				}
				
				else if (p.y <= currHeight && p.y >= currHeight - (currHeight/4))
				{
					if (p.x >= cVI.xEDL && p.x <= cVI.xEDL + cVI.width)
					{
						int[] featNum = {0};
						
						for (int j = 0; j < whichFeature; j++)
							featNum[0] += elementsPerFeature[j];
						value = cVI.getFeatures(featNum)[0];
						return value;
					}
				}
				
			}
		}
		
		return value;
	}
	
	public void rangeFilterSelectionChanged()
	{
	}
	
	public void setDragRect(Rectangle r, boolean dS)
	{
		dragRect = r;
		dragShift = dS;
		
		if (!dragShift)
		{
			selectNone();
		}
		
		for (int i = 0; i < events.size(); i++)
		{
			ChunkVisInfo cVI = (ChunkVisInfo)events.elementAt(i);
			Rectangle chunkRect = null;
			
			if (dragRect.y < currHeight/2)
			{
				chunkRect = new Rectangle(cVI.xFeat, cVI.yFeat, cVI.width, cVI.height);
			}
			else
			{
				chunkRect = new Rectangle(cVI.xEDL, cVI.yEDL, cVI.width, cVI.height);
			}
			if ((dragRect.x >= chunkRect.x && 
				dragRect.x <= chunkRect.x + chunkRect.width) ||
				(dragRect.x + dragRect.width >= chunkRect.x && 
				dragRect.x + dragRect.width <= chunkRect.x + chunkRect.width) ||
				(dragRect.x <= chunkRect.x && 
				dragRect.x + dragRect.width >= chunkRect.x + chunkRect.width))
				cVI.selected = true;
		}
		
		dragRect = null;
		dragShift = false;
		
		drawingPanel.repaint();	
	}
	
	public void actionPerformed(ActionEvent arg0)
	{		
		super.actionPerformed(arg0);
		
		Object source = arg0.getSource();
		
		if (source == multiLines)
		{
			JCheckBox cb = (JCheckBox)source;
			
			multi = cb.isSelected();
		}
		if (source == thickLines)
		{
			JCheckBox cb = (JCheckBox)source;
			
			thick = cb.isSelected();
		}
	}
	
	public JPanel buildGUI(Color bgColor)
	{	
		JPanel panel = super.buildGUI(bgColor);
		
		JPanel linesPanel = new JPanel();
		linesPanel.setBackground(bgColor);
		linesPanel.setLayout(new BoxLayout(linesPanel, BoxLayout.Y_AXIS));
		
		multiLines = new JCheckBox("multi lines");
		multiLines.setBackground(bgColor);
		multiLines.addActionListener(this);//dPanel);
		linesPanel.add(multiLines);
		
		thickLines = new JCheckBox("thick lines");
		thickLines.setBackground(bgColor);
		thickLines.addActionListener(this);//dPanel);
		linesPanel.add(thickLines);
		
		controlsPanel.add(linesPanel);
		
		return panel;
	}


}



