/* BEGIN_HEADER                                              Java TreeView
 *
 * $Author: alokito $
 * $RCSfile: InvertedTreeDrawer.java,v $
 * $Revision: 1.2 $
 * $Date: 2008-03-09 21:06:34 $
 * $Name:  $
 *
 * This file is part of Java TreeView
 * Copyright (C) 2001-2014 Alok Saldanha, All Rights Reserved. Modifications Copyright (C) Lawrence Berkeley Lab.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * END_HEADER 
 */
package edu.stanford.genetics.treeview.plugin.dendroview;

import edu.stanford.genetics.treeview.*;

import java.awt.*;
import java.util.Stack;
/**
 * Class for drawing ATR-style inverted trees
 *
 * @author Alok Saldanha <alok@genome.stanford.edu>
 * @version Alpha
 */

class InvertedTreeDrawer extends TreeDrawer {
    public void paint(Graphics graphics, LinearTransformation xScaleEq, 
		      LinearTransformation yScaleEq, Rectangle dest, 
		      TreeDrawerNode selected) {	
	if ((getRootNode() == null) || (getRootNode().isLeaf() == true))
	    System.out.println("Root node is null or leaf!");
	else {
	    // recursively drawtree...
	    NodeDrawer nd = new NodeDrawer(graphics, xScaleEq, yScaleEq, 
					   selected, dest);
	    nd.draw(getRootNode());
	}
    }

	public void paintSubtree(Graphics graphics, LinearTransformation xScaleEq, 
	LinearTransformation yScaleEq, Rectangle dest, 
	TreeDrawerNode root, boolean isSelected) {	
	  if ((root == null) || (root.isLeaf() == true) || 
			  (xScaleEq == null) || (yScaleEq == null))
		return;
		else {
		  // recursively drawtree...
		  NodeDrawer nd = new NodeDrawer(
		  graphics, xScaleEq, yScaleEq, 
		  null, dest);
		  nd.isSelected = isSelected;
		  nd.draw(root);
		}
	}

	public void paintSubtree(Graphics graphics, LinearTransformation xScaleEq, 
		      LinearTransformation yScaleEq, Rectangle dest, 
		      TreeDrawerNode root, 
			  TreeDrawerNode selected) {	
		if ((root == null) || (root.isLeaf() == true))
		  return;
		else {
		  // recursively drawtree...
		  NodeDrawer nd = new NodeDrawer(
			graphics, xScaleEq, yScaleEq, 
			selected, dest);
			nd.draw(root);
		}
    }

    public void paintSingle(Graphics graphics, LinearTransformation xScaleEq, 
		      LinearTransformation yScaleEq, Rectangle dest, 
		      TreeDrawerNode root, boolean isSelected) {	
		if ((root == null) || (root.isLeaf() == true))
		  return;
		else {
		  // just draw single..
		  NodeDrawer nd = new NodeDrawer(
			graphics, xScaleEq, yScaleEq, 
			null, dest);
			nd.isSelected = isSelected;
			if (root.isLeaf() == false)
			  nd.drawSingle(root);
			else
			  System.err.println("Root was leaf?");
		}
    }

	
	
    /**
     * this is an internal helper class which does a sort of recursive drawing
     * @author Alok Saldanha <alok@genome.stanford.edu>
     * @version Alpha
     */
    class NodeDrawer {
	/**
	 * The constructor sets the variables
	 *
	 * @param g         The graphics object to print to

	 * @param xScaleEq The equation to be applied to scale the
	 * index of the nodes to graphics object

	 * @param yScaleEq The equation to be applied to scale the
	 * correlation of the nodes to the graphics object

	 * maybe foreground color, selection color and node color should be options?
	 */
	public NodeDrawer(Graphics g, LinearTransformation xScaleEq, 
			  LinearTransformation yScaleEq, TreeDrawerNode sel,
			  Rectangle d) {
	    graphics = g;
	    selected = sel;
	    xT = xScaleEq;
	    yT = yScaleEq;
	    dest = d;
	    minInd = (int) xScaleEq.inverseTransform(dest.x);
	    maxInd = (int) xScaleEq.inverseTransform(dest.x + dest.width) + 
		1;
	}

	/** 
	 * the draw method actually does the drawing
	 */
	public void draw(TreeDrawerNode startNode) {
		Stack remaining = new Stack();
		remaining.push(startNode);
		while (remaining.empty() == false) {
			TreeDrawerNode node = (TreeDrawerNode) remaining.pop();

			// just return if no subkids visible.
			if ((node.getMaxIndex() < minInd) ||
					(node.getMinIndex() > maxInd))
				continue;
			// handle selection...
			if (node == selected) {
				if (isSelected == false) {
					isSelected = true;
					// push onto stack, so we know when we're finished with the selected subtree..
					remaining.push(selected);
				} else {
					// isSelected is true, so we're pulling the selected node off the second time.
					isSelected = false;
					continue;
				}
			}
			// lots of stack allocation...
			TreeDrawerNode left = node.getLeft();
			TreeDrawerNode right = node.getRight();
			if (left.isLeaf() == false) remaining.push(left);
			if (right.isLeaf() == false) remaining.push(right);
			// finally draw
			drawSingle(node);
		}
	}
/*
	    // just return if no subkids visible.
	    if ((node.getMaxIndex() < minInd) ||
		(node.getMinIndex() > maxInd))
		return;

	    // lots of stack allocation...
	    TreeDrawerNode left = node.getLeft();
	    TreeDrawerNode right = node.getRight();
	    
	    int ry = (int) yT.transform(right.getCorr());
	    int ly = (int) yT.transform(left.getCorr());
	    int ty = (int) yT.transform(node.getCorr());
	    
	    int rx = (int) xT.transform(right.getIndex() + .5);
	    int lx = (int) xT.transform(left.getIndex() + .5);
	    int tx = (int) xT.transform(node.getIndex() + .5);
	    Color t = graphics.getColor();
	    
	    isSelected = (node == selected);
	    //	System.out.println("rx = " + rx + ", ry = " + ry + ", lx = " + lx + ", ly = " + ly);
	    
	    // oval first?...
//	    graphics.setColor(node_color);
//	    graphics.drawOval(tx - 1,ty - 1,2,2);

	    //draw our (flipped) polyline...
	    if (isSelected) 
		graphics.setColor(sel_color);
	    else
		graphics.setColor(t);

	    graphics.drawPolyline(new int[] {rx, rx, lx, lx},
			   new int[] {ry, ty, ty, ly}, 4);
	    if (left.isLeaf() == false) draw(left); 
	    if (right.isLeaf() == false) draw(right);	    
	    if (isSelected)  graphics.setColor(t);
	} */
	private void drawSingle(TreeDrawerNode node) {
	    TreeDrawerNode left = node.getLeft();
	    TreeDrawerNode right = node.getRight();
		if (xT == null) 
		  System.err.println("xt was null");
		if (right == null)
		  System.err.println("right was null");

		int ry = (int) yT.transform(right.getCorr());
	    int ly = (int) yT.transform(left.getCorr());
	    int ty = (int) yT.transform(node.getCorr());
	    
	    int rx = (int) xT.transform(right.getIndex() + .5);
	    int lx = (int) xT.transform(left.getIndex() + .5);
	    //int tx = (int) xT.transform(node.getIndex() + .5);


	    //draw our (flipped) polyline...
	    if (isSelected) 
		graphics.setColor(sel_color);
	    else
		graphics.setColor(node.getColor());
	    graphics.drawPolyline(new int[] {rx, rx, lx, lx},
				  new int[] {ry, ty, ty, ly}, 4);

//	    graphics.setColor(t);
	}

	boolean isSelected = false;
	private Color sel_color = Color.red;
	private Graphics graphics;
	private TreeDrawerNode selected;
	private LinearTransformation xT, yT;

	private double minInd, maxInd;
	private Rectangle dest;
    }
}

