import java.awt.*;
import java.util.*;

class SimpleGraph extends Canvas {
	Vector					m_data[];
	Image 					m_bufferImage;
	Graphics 				m_bufferGraphics;
	StringMessageHandler	m_handler;
	
	SimpleGraph(Vector data[], StringMessageHandler messageHandler) {
		m_data = data;
		m_handler = messageHandler;
	}
	
	void showData(int columns[], String labels[], Color colors[], 
										String xLabel, String yLabel) 
				throws Exception {
		int		actualWidth			= getSize().width;
		int		actualHeight		= getSize().height;
		int 	width;
		int 	height;
		int     fontWidth;					// width of biggest number
		int     fontHeight;					// height of font
		int		topMargin,
				leftMargin,
				bottomMargin,
				rightMargin;
		int		edge;						// margin on all sides
		int		numColumns			= columns.length;
		int 	smallestVal;
		int 	largestVal;
		int 	numPoints;
		float 	xUnit;
		float 	yUnit;
		Vector 	points				= new Vector();
		

		initCanvas();
				
        // check that we have valid data to work with
		if (m_data == null) return;

		if ((numColumns != labels.length) || (numColumns != colors.length))
			return;

		// find smallest and largest values this graph will represent
		Vector smallestVals = new Vector();
		Vector largestVals = new Vector();
		for (int count = 0; count < numColumns; count++) {
			int smallest = smallestInt(m_data[columns[count]]);
			smallestVals.addElement(new Integer(smallest));

			int largest = largestInt(m_data[columns[count]]);
			largestVals.addElement(new Integer(largest));
		}
		
		smallestVal 		= smallestInt(smallestVals);
		largestVal 			= largestInt(largestVals);
		
		// No neg values allowed
		
		//System.out.println("SmallestVal = "+smallestVal);
		//System.out.println("LargestVal = "+largestVal);
		
		if ((smallestVal < 0) || (largestVal < 0)) return;
		
		
		// set some dimensions and values for graphs
		fontHeight  =   m_bufferGraphics.getFontMetrics().getHeight();
		fontWidth   =   m_bufferGraphics.getFontMetrics().stringWidth(largestVal+"");
		edge		=	fontHeight/2;
		topMargin	=	fontHeight+edge;
		bottomMargin=	(2*fontHeight) +edge;
		leftMargin	=	fontWidth+edge;
		rightMargin	=	edge;
		width		= 	actualWidth - (leftMargin + rightMargin);
		height 		= 	actualHeight - (topMargin + bottomMargin);
		numPoints 	= 	m_data[columns[0]].size();
		xUnit		= 	(float)width/(float)numPoints;
		yUnit		= 	(float)height/(float)(largestVal-smallestVal);

		// draw axis and label them
		int tickSize = 1;
		int xIntervals = numPoints/10;
		if (xIntervals == 0) xIntervals = 1;
		int yIntervals = (largestVal-smallestVal)/10;
		if (yIntervals == 0) yIntervals = 1;

		m_bufferGraphics.setColor(Color.white);
		// y axis
		m_bufferGraphics.drawLine(	leftMargin, topMargin,
									leftMargin, actualHeight-bottomMargin);
		m_bufferGraphics.drawString(yLabel, edge, fontHeight);
		
		for (int count = smallestVal; count <= largestVal; count++) { // draw ticks on y axis
			tickSize = 0;
			
			if ((yIntervals/5) != 0)
				if (count % (yIntervals/5) == 0) tickSize = 1;
			if (count % yIntervals == 0) tickSize = 3;

			if (tickSize != 0) {
				m_bufferGraphics.drawLine(
						leftMargin, actualHeight-bottomMargin - (int)(yUnit*(count-smallestVal)),
						leftMargin-tickSize, actualHeight-bottomMargin - (int)(yUnit*(count-smallestVal)));
										
				if (tickSize == 3)
					m_bufferGraphics.drawString(""+count,
										0,
										actualHeight-bottomMargin -
										(int)(yUnit*(count-smallestVal)) + (fontHeight/2));
			}
		}
		
		// x axis
		m_bufferGraphics.drawLine(	leftMargin,	actualHeight-(bottomMargin),
									actualWidth-(rightMargin),
													actualHeight-(bottomMargin));
		m_bufferGraphics.drawString(xLabel,
							actualWidth - m_bufferGraphics.getFontMetrics().stringWidth(xLabel),
							actualHeight - (fontHeight/2));

		for (int count = 0; count <= numPoints; count++) {	// draw ticks on x axis
			tickSize = 0;
			if ((xIntervals/5) != 0)
				if (count % (xIntervals/5) == 0) tickSize = 1;
			if (count % xIntervals == 0) tickSize = 3;

			if (tickSize != 0) {
				m_bufferGraphics.drawLine(
						(int)(count*xUnit) + leftMargin,
										actualHeight-(bottomMargin),
						(int)(count*xUnit) + leftMargin,
										actualHeight-(bottomMargin)+tickSize);
										
				if (tickSize == 3)
					m_bufferGraphics.drawString(""+count,
										(int)(count*xUnit) + leftMargin - 5,
										actualHeight-bottomMargin+fontHeight);
			}
		}
		
		Point prevPoint = null;

		// plot all the graphs (data sets)
		int legendX = actualWidth;
		for (int colNum = 0; colNum < numColumns; colNum++) {
			m_bufferGraphics.setColor(colors[colNum]);
			
			legendX -= m_bufferGraphics.getFontMetrics().stringWidth(labels[colNum]) + 20;
			m_bufferGraphics.drawString(labels[colNum], legendX, fontHeight);
			
			// draw this graph
			for (int count = 0; count < numPoints; count++) {
				Point newPoint = null;
				int value = ((Integer)m_data[columns[colNum]].elementAt(count)).intValue();
				
				if (value != -1) {
					newPoint = new Point();
					newPoint.x = (int)(count*xUnit);
					newPoint.y = height - (int)((float)(value - smallestVal)*yUnit);
	            }
				
				points.addElement(newPoint);

				if (prevPoint == null) {
					if (newPoint != null) {
						m_bufferGraphics.drawLine(	newPoint.x + leftMargin,
													newPoint.y + topMargin,
													newPoint.x + leftMargin,
													newPoint.y + topMargin);
					}
				}
				else {
					if (newPoint != null) {
						m_bufferGraphics.drawLine(	prevPoint.x + leftMargin, 
													prevPoint.y + topMargin,
													newPoint.x + leftMargin, 
													newPoint.y + topMargin);
					}
				}
				
				prevPoint = newPoint;
			}
		}
		
		repaint();
	}

	// finds largest integer in a given integer Vector
	int largestInt(Vector column) {
		int size = column.size();

		int index = 0;
		for (int count = 1; count < size; count++) {
			if (((Integer)column.elementAt(count)).intValue() >
							((Integer)column.elementAt(index)).intValue()) {
				index = count;
			}
		}

		return ((Integer)column.elementAt(index)).intValue();
	}

	int smallestInt(Vector column) {
		int size = column.size();
		int index = -1;
		int smallest, current;
		
		smallest = -1;
		for (int count = 0; count < size; count++) {
			current = ((Integer)column.elementAt(count)).intValue();
			if ((smallest == -1) && (current >= 0)) {
				index = count;
				smallest = current;
				continue;
			}
			
			if ((current < smallest) && (current >= 0)) {
				index = count;
				smallest = current;
			}
		}
		
		return smallest;
	}

	protected void initCanvas() {
		m_bufferImage = createImage(getSize().width, getSize().height);
		m_bufferGraphics = m_bufferImage.getGraphics();
		
		m_bufferGraphics.setColor(Color.black);
		m_bufferGraphics.fillRect(0, 0, getSize().width, getSize().height);
	}
	
	public void update(Graphics g) {
		paint(g);
	}
	
	public void paint(Graphics g) {
		if (m_bufferImage == null) initCanvas();
		g.drawImage(m_bufferImage, 0, 0, this);
	}
	
}