//=====================================================================
// File:    BarGraph.java
// Class:   BarGraph
// Package: AFLPgui
//
// Author:  James J. Benham
// Date:    August 11, 1998
// Contact: james_benham@hmc.edu
//
// Genographer v1.0 - Computer assisted scoring of gels.
// Copyright (C) 1998  Montana State University
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// The GNU General Public License is distributed in the file GPL
//=====================================================================

package AFLPgui;

import java.awt.Color;
import java.awt.Graphics;
import AFLPcore.DataList;
import AFLPcore.Lane;
import AFLPcore.Peak;

/**
 * This class will draw a graph given a set of lanes and an area in those
 * lanes. The graph will be a bar graph, with one bar for every lane.
 * The height of the bar will be equal to the height of the heighest peak
 * in the lane in the specified region. (The region is defined by a 
 * minimum size in base pairs and a maximum size.) If the lane contains more
 * than one peak, it will be drawn in a color different from those that
 * contain only one peak. The graph can be of any width.
 *
 * @see Graph
 *
 * @author James J. Benham
 * @version 1.0.0
 * @date August 11, 1998
 */

public class BarGraph extends Graph
{
  private static int LABEL_WIDTH = 10;

  private Color singlePeak;
  private Color multiPeak;

  /**
   * Create a new BarGraph. Lanes with a single peak will be drawn 
   * in blue and lanes with multiple peaks wll be black.
   */
  public BarGraph()
  {
    this(Color.blue, Color.black);
  }

  /**
   * Create a new BarGraph with the specified colors.
   *
   * @param singlePeak  the color for the bar of a lane with only one peak.
   * @param multiPeak   the color for the bar of a lane with multiple peaks.
   */
  public BarGraph(Color singlePeak, Color multiPeak)
  {
    this.singlePeak = singlePeak;
    this.multiPeak = multiPeak;
  }

  /**
   * Draws the graph described in the class description. 
   *
   * @param g     the graphics to draw on
   * @param x     the x coordinate of the upper left corner of the graph
   *              area. (The position of the vertical axis)
   * @param y     the y coordinate of the upper left corner of the graph
   * @param width the width of the graph area.
   * @param height the height of the graph
   * @param scale  the scale of the graph, pixel = intensity*scale
   * @param minSize  the minimum size, in bp, that the graph should include
   * @param maxSize  the maximum size, in bp, that the graph should include
   * @param lanes  the lanes to include in the graph.
   */
  public void drawGraph(Graphics g, int x, int y, int width, 
				 int height, int bottom_border,
				 double scale, double minSize, double maxSize,
				 DataList lanes)
  {
    int numLanes = lanes.size();
    double barWidth = width/numLanes;

    Lane ln;
    DataList peaks;
    double intensity;
    for(int i=0; i < numLanes; i++)
      {
	ln = (Lane) lanes.dataAt(i);
	peaks = ln.getPeaksInRange(minSize, maxSize);
	if(!peaks.isEmpty())
	  {
	    // Find the height and color
	    if(peaks.size() == 1)
	      {
		intensity = ((Peak) peaks.dataAt(0)).getHeight();
		g.setColor(singlePeak);
	      }
	    else
	      {
		intensity = findMax(peaks);
		g.setColor(multiPeak);
	      }

	    // the actual bar
	    g.fillRect(x + (int)(barWidth*i) + 1, 
		       y + height - (int)(scale*intensity),
		       (int) barWidth,
		       (int)(scale*intensity));
	  }
      }

    // add labels if we can
    g.setColor(Color.black);
    if(barWidth > LABEL_WIDTH)
      for(int i=0; i < numLanes; i++)
	{
	  ln = (Lane) lanes.dataAt(i);
	  g.drawString("" + ln.getLaneNumber(),
		       x + (int)(barWidth * i) + 2,
		       y + height + bottom_border - 1);
	}
  }

  /**
   * Give the ideal width for this graph, which is -1. This is a signal that
   * the graph really doesn't care how wide it is. It will adjust
   * itself automatically. However, if it is to narrow, then the labels
   * for the bars will not be drawn, and it should probably leave at least
   * one pixel per lane.
   *
   * @return the width requested by the graph, which is -1.
   */
  public int getPreferredWidth()
  {
    return -1;
  }

  /**
   * Finds the maximum height in a list of peaks.
   *
   * @param peakList  the peaks to find the maximum of.
   *
   * @return the maximum height from all of the peaks.
   */
  protected double findMax(DataList peakList)
  {
    double max = 0;
    double temp;

    for(int i=0; i < peakList.size(); i++)
      {
	temp = ((Peak) peakList.dataAt(i)).getHeight();
	if(temp > max)
	  max = temp;
      }

    return max;
  }
}
