package edu.byu.cs.roots.opg.chart.presetvertical;
import java.awt.Color;
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import edu.byu.cs.roots.opg.chart.ChartDrawInfo;
import edu.byu.cs.roots.opg.chart.cmds.DrawCmdMoveTo;
import edu.byu.cs.roots.opg.chart.cmds.DrawCmdSetFont;
import edu.byu.cs.roots.opg.chart.cmds.DrawCmdText;
import edu.byu.cs.roots.opg.chart.cmds.DrawCommand;
import edu.byu.cs.roots.opg.fonts.OpgFont;
import edu.byu.cs.roots.opg.model.Individual;
import edu.byu.cs.roots.opg.util.NameAbbreviator;
/**
* Represents the chart margins and titles
*
*/
//TODO: make font size of titles variable
public class ChartMargins {
private ChartDrawInfo chart;
double xOrig;
double yOrig;
double width;
double height;
private VerticalChartOptions ops;
double marginSize = 72;//one-inch margins
double headerSize = 0;//size (in points) of title(s) at top of chart
double titleSize = 0;//size of chart title (to be implemented later)
float labelFontSize = 12;//font size of generation labels at top of chart
double whiteSpace;
float MAX_GEN_WIDTH = 800;
public ChartMargins(ChartDrawInfo chart, VerticalChartOptions ops)
{
this.chart = chart;
this.setOptions(ops);
xOrig = marginSize;
yOrig = marginSize;
width = chart.getXExtent() - (marginSize*2);
height = chart.getYExtent() - (marginSize*2) - titleSize;
}
public ChartDrawInfo getChart(){
return chart;
}
public void setChart(ChartDrawInfo c) {
chart = c;
}
public void addDrawCommand(DrawCommand cmd)
{
//relies on draw command to offset by correct amount
chart.addDrawCommand(cmd);
}
public double getXExtent(){
return width;
}
public double getYExtent(){
return height;
}
public double xOffset(double x){
return x + xOrig;
}
public double yOffset(double y){
return y + yOrig;
}
//this returns an appropriate label for the generation - gen - 0 = self, 1 = parents, -1 = children, etc.
protected String getGenerationLabel(int gen)
{
switch (gen)
{
case 0:
//return root.givenName + " " + root.middleName + " " + root.surname;//
Font font = OpgFont.getDefaultSansSerifFont(Font.BOLD, labelFontSize);
Individual root = getOptions().getRoot();
NameAbbreviator.nameFit(root.namePrefix.trim(), root.givenName.trim(), root.surname, root.nameSuffix, MAX_GEN_WIDTH, font);
return NameAbbreviator.getName();
case 1:
return "Parents";
case 2:
return "Grandparents";
case 3:
return "Great-Grandparents";
case -1:
return "Children";
case -2:
return "Grandchildren";
case -3:
return "Great-Grandchildren";
default:
if (gen > 0)
return gen-2 + getOrdinalSuffix(gen-2) + " Great-Grandparents";
else
return (-gen)-2 + getOrdinalSuffix((-gen)-2) + " Great-Grandchildren";
}
}
protected static String getOrdinalSuffix(int gen)
{
if (11 <= (gen%100) && 13 >= (gen%100))
return "th";
switch (gen%10)
{
case 1:
return "st";
case 2:
return "nd";
case 3:
return "rd";
default:
return "th";
}
}
protected void findLabelFontSize()
{
//find width of longest label
FontRenderContext frc = NameAbbreviator.frc;
float testFontSize = 72;
Font font = OpgFont.getDefaultSansSerifFont(Font.BOLD, testFontSize);
headerSize = 72;
double longestWidth = 0;
for(int gen = -getOptions().getDescGens(); gen <= getOptions().getAncesGens(); ++gen)
{
//if (gen == 0) continue;
double width = font.getStringBounds(getGenerationLabel(gen), frc).getWidth();
if (width > longestWidth)
longestWidth = width;
}
//set font size so that longest label barely fits over box
labelFontSize = (float)(testFontSize * (MAX_GEN_WIDTH / longestWidth));
final float MAXLABELFONTSIZE = 80;
if(labelFontSize > MAXLABELFONTSIZE)
labelFontSize=MAXLABELFONTSIZE;
LineMetrics lm = font.deriveFont(labelFontSize).getLineMetrics("gjpqyjCAPSQJbdfhkl", frc);
if (getOptions().isDrawTitles())
headerSize = titleSize + lm.getHeight() + lm.getLeading();
else
headerSize = titleSize;
}
protected void drawTitles(AncesTree atree, DescTree dtree)
{
// new way to print the generation labels
FontRenderContext frc = NameAbbreviator.frc;
//start at the grandparents
Font font = OpgFont.getDefaultSansSerifFont(Font.BOLD, (float) 10);
LineMetrics lm = font.getLineMetrics("gjpqyjCAPSQJbdfhkl", frc);
//move the position over to the start of the grandparents.
double horizPos = moveHorizontallyToGen(2, atree, dtree);
double vertPos = getOptions().paperHeight();
vertPos += -marginSize - headerSize + (2*lm.getLeading()) + lm.getDescent();
//draw ancestor labels
chart.addDrawCommand(new DrawCmdSetFont(font, Color.RED));
for(int gen = 2; gen <= getOptions().getAncesGens(); gen++) {
if (gen % 2 == 0) {
chart.addDrawCommand(new DrawCmdMoveTo(horizPos, vertPos));
chart.addDrawCommand(new DrawCmdText(getGenerationLabel(gen)));
}
horizPos = addGenerationToHoriz(gen, horizPos, atree);
}
/*
for(int gen = -getOptions().getDescGens(); gen <= getOptions().getAncesGens(); ++gen)
{
double width = font.getStringBounds(getGenerationLabel(gen), frc).getWidth();
//draw label centered above boxes for generation
System.out.println("gen: " + gen);
if (gen == -1)
continue;
chart.addDrawCommand(new DrawCmdMoveTo(horizPos + (atree.getGeneration(gen).getWidth() - width)/2.0, vertPos ));
chart.addDrawCommand(new DrawCmdText(getGenerationLabel(gen)));
//draw spouse's name beneath root's name if root only has one spouse
if (gen == 0 && getOptions().isIncludeSpouses() && root.fams.size() == 1)
{
double spouseVertPos = vertPos;
spouseVertPos -= lm.getHeight();
width = font.getStringBounds("and", frc).getWidth();
chart.addDrawCommand(new DrawCmdMoveTo(horizPos + (atree.getGeneration(gen).getWidth() - width)/2.0, spouseVertPos ));
chart.addDrawCommand(new DrawCmdText("and"));
spouseVertPos -= lm.getHeight();
Individual spouse = (root.gender == Gender.MALE)? root.fams.get(0).wife : root.fams.get(0).husband;
NameAbbreviator.nameFit(spouse.namePrefix.trim(), spouse.givenName.trim(), spouse.surname, spouse.nameSuffix, (float)AncesBox.boxWidth, font);
String spouseName = NameAbbreviator.getName();
width = font.getStringBounds(spouseName, frc).getWidth();
chart.addDrawCommand(new DrawCmdMoveTo(horizPos + (atree.getGeneration(gen).getWidth() - width)/2.0, spouseVertPos ));
chart.addDrawCommand(new DrawCmdText(spouseName));
}
horizPos += atree.getGeneration(gen).getWidth() * 11.0/10.0;
}*/
}
private double moveHorizontallyToGen(int gen, AncesTree atree, DescTree dtree) {
double totalHorizontal = marginSize;
//add the descendants
/*
* Because Decendants were never completed, the widths of each generation are
* not recorded. thus, we cannot grab the width of a descendant generation, and so
* the labels will not match up with the graph if a descendant is also pictured on
* the chart. It must be removed to have them aligned.
*/
for (int y = -getOptions().getDescGens(); y < 0; y++) {
totalHorizontal += dtree.getGeneration(-y).getWidth();
}
//add the ancestors
for (int i = 0; i < gen; i++) {
totalHorizontal = addGenerationToHoriz(i, totalHorizontal, atree);
}
return totalHorizontal;
}
private double addGenerationToHoriz(int gen, double HorizPos, AncesTree atree) {
HorizPos += atree.getGeneration(gen).getWidth();
return HorizPos;
}
public void updateWhiteSpace()
{
if (getOptions().isDrawTitles())
findLabelFontSize();
whiteSpace = marginSize*2 + headerSize;
}
public double getWhiteSpace() {
updateWhiteSpace();
return whiteSpace;
}
public void drawLogo()
{
chart.addDrawCommand(new DrawCmdMoveTo(marginSize+chart.getXExtent()-275, marginSize-12));
chart.addDrawCommand(new DrawCmdSetFont(OpgFont.getDefaultSerifFont(Font.PLAIN, 12),Color.LIGHT_GRAY));
chart.addDrawCommand(new DrawCmdText("www.OnePageGenealogy.com"));
}
public double totalMargins() {
return marginSize*2;
}
public void setOptions(VerticalChartOptions ops) {
this.ops = ops;
}
public VerticalChartOptions getOptions() {
return ops;
}
}