package edu.byu.cs.roots.opg.chart.presetvertical;
import java.awt.Color;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Rectangle2D.Double;
import java.util.ArrayList;
import edu.byu.cs.roots.opg.chart.cmds.DrawCmdFillRect;
import edu.byu.cs.roots.opg.chart.cmds.DrawCmdMoveTo;
import edu.byu.cs.roots.opg.chart.cmds.DrawCmdRelLineTo;
import edu.byu.cs.roots.opg.chart.cmds.DrawCmdRoundRect;
import edu.byu.cs.roots.opg.model.Individual;
/**
* Represents a box in an ancestry chart.
* Contains spacing information and a reference to its formating.
*
*/
public class AncesBox extends Box
{
//tree structure variables
protected AncesBox father;
protected AncesBox mother;
double hPos,vPos;
static double scaler;
double subTreeHeight; //the minimum height for the current configuration of the tree
boolean expand; //false if box is duplicated, true otherwise
double fatherVOffset;
double motherVOffset;
Rectangle2D.Double boxInfo = new Rectangle2D.Double();
static ArrayList<Double> genBoxHeights; //box heights of generations
public AncesBox(Individual indi)
{
super(indi);
father = null;
mother = null;
expand = true;
}
public double setHeight(double newHeight)
{
//set the scaler so that chart will be the right height
double curHeight = upperSubTreeOffset - lowerSubTreeOffset;
//curHeight = Math.
if (curHeight < subTreeHeight)
throw new IllegalArgumentException ("Cannot scale chart smaller than minimum");
scaler = newHeight/subTreeHeight;
return scaler;
}
//-----------------------------------------------------------------------
void setScaler(double newScaler)
{
if (newScaler < 0.99)
throw new IllegalArgumentException ("Cannot scale chart smaller than minimum");
else
scaler = newScaler;
}
protected void drawSubTree(ChartMargins chart, VerticalChartOptions options, double x, double y)
{
if (gen.getGenNum() >= 0)
drawBox(chart, chart.xOffset(x), chart.yOffset(y));
if (options.getAncesGens() > gen.getGenNum())
{
if (father != null)
{
AncesBox f = (AncesBox) father;
drawParentConnector(chart,x,y,fatherVOffset);
f.drawSubTree(chart, options, x + gen.getWidth(), y + fatherVOffset);
}
if (mother != null)
{
AncesBox m = (AncesBox) mother;
drawParentConnector(chart,x,y,motherVOffset);
m.drawSubTree(chart, options, x + gen.getWidth(), y + motherVOffset);
}
}
}
protected void drawBox (ChartMargins chart, double x, double y)
{
String dupLabel = (dupIndex != 0)? (" <" + dupIndex + ">") : "";
VerticalChartOptions options = chart.getOptions();
double height = boxFormat.getHeight();
double width = boxFormat.getWidth();
//Draw a boarder, if they select they want one, and whether it has rounded corners or not.
double lineWidth = (options.isBoxBorder())? boxFormat.getLineWidth() : 0;
if (options.isRoundedCorners())
chart.addDrawCommand(new DrawCmdRoundRect(x, y-height/2.0, width ,height, lineWidth, boxFormat.getRoundnessOfCorners(), Color.BLACK, options.getAncesScheme().getColor(indi.id), boxInfo));
else
chart.addDrawCommand(new DrawCmdFillRect(x, y-height/2.0, width ,height, lineWidth, Color.BLACK, options.getAncesScheme().getColor(indi.id), boxInfo));
// draw content of the box
BoxDrawer drawer = new BoxDrawer(chart.getChart(), boxFormat, indi, x, y, dupLabel);
drawer.drawBox();
//These draw the boxFormat number assigned to the box being drawn on the chart
//(The number is assigned in the FormatSelector)
//drawBox.drawTextBox(chart, x, y, dupLabel);
//chart.addDrawCommand(new DrawCmdMoveTo(x-20,y));
//chart.addDrawCommand(new DrawCmdText(boxFormat.boxIndex+""));
}
/**
* Draws the connector line to a boxes parents.
* @param chart chart to draw the lines on
* @param x x coordinate of left-middle of the box
* @param y y coordinate of left-middle of the box
* @param offset y offset to the parent (father > 0 and mother < 0).
*/
protected void drawParentConnector(ChartMargins chart, double x, double y, double offset) {
if(genGap() > 0) {
chart.addDrawCommand(new DrawCmdMoveTo(chart.xOffset(x + getWidth()), chart.yOffset(y)));
chart.addDrawCommand(new DrawCmdRelLineTo(connectorLength(),0.0,boxFormat.getLineWidth(), Color.BLACK));
chart.addDrawCommand(new DrawCmdRelLineTo(0.0,offset,boxFormat.getLineWidth(), Color.BLACK));
chart.addDrawCommand(new DrawCmdRelLineTo(connectorLength(),0,boxFormat.getLineWidth(), Color.BLACK));
}
//intrusion
else {
double boxOffset = 0;
//adjust offsets to make line come from top/bottom of the box
if(offset < 0) { //bottom (mother)
offset += getHeight()/2;
boxOffset = -getHeight()/2;
}
//top (father)
else {
offset -= getHeight()/2;
boxOffset = getHeight()/2;
}
chart.addDrawCommand(new DrawCmdMoveTo(chart.xOffset(x + gen.getWidth() - connectorLength()),
chart.yOffset(y) + boxOffset));
chart.addDrawCommand(new DrawCmdRelLineTo(0.0,offset,boxFormat.getLineWidth(), Color.BLACK));
chart.addDrawCommand(new DrawCmdRelLineTo(connectorLength(),0,boxFormat.getLineWidth(), Color.BLACK));
}
}
/**
* Length of the line that just out of the box
*/
private double connectorLength() {
return (getWidth()*.1)/2;
}
/**
* Gap between generations. Value is negative if there is intrusion.
*/
protected double genGap() {
return (gen.getWidth() - getWidth());
}
public void setFather(AncesBox father) {
this.father = father;
}
public Box getFather() {
return father;
}
public void setMother(AncesBox mother) {
this.mother = mother;
}
public Box getMother() {
return mother;
}
public String toString() {
return "AncesBox: "+ indi.toString();
}
public void setParentOffsets(double fatherOffset, double motherOffset) {
fatherVOffset = fatherOffset;
motherVOffset = motherOffset;
updateSubTreeOffsets();
}
private void updateSubTreeOffsets() {
double usth = 0;
double lsth = 0;
if(father != null){
usth = fatherVOffset + father.upperSubTreeOffset;
lsth = fatherVOffset + father.lowerSubTreeOffset;
}
if(mother != null) {
usth = Math.max(usth, motherVOffset + mother.upperSubTreeOffset);
lsth = Math.min(lsth, motherVOffset + mother.lowerSubTreeOffset);
}
upperSubTreeOffset = Math.max(usth, upperSubTreeOffset);
lowerSubTreeOffset = Math.min(lsth, lowerSubTreeOffset);
}
}