package org.seqcode.projects.seqview.paintable;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.*;
import org.seqcode.genome.location.Gene;
import org.seqcode.genome.location.Region;
import org.seqcode.gseutils.*;
import org.seqcode.projects.seqview.model.RegionExpanderModel;
import org.seqcode.viz.DynamicAttribute;
public class GenePainter extends RegionPaintable {
private RegionExpanderModel<Gene> model;
private NonOverlappingLayout<Gene> layout;
private DynamicAttribute attrib;
private double htRat, wdRat;
private Vector<Gene> genes;
private GeneProperties props;
public GenePainter(RegionExpanderModel<Gene> model) {
super();
layout = new NonOverlappingLayout<Gene>();
this.model = model;
attrib = DynamicAttribute.getGlobalAttributes();
htRat = .03;
wdRat = .03;
model.addEventListener(this);
props = new GeneProperties();
initLabels();
}
public GeneProperties getProperties () {return props;}
public void setProperties(GeneProperties p) {props = p;}
public void clickedOnItem(ActionEvent e) {
System.err.println(e);
String geneName = e.getActionCommand();
}
public void cleanup() {
super.cleanup();
model.removeEventListener(this);
}
public void removeEventListener(Listener<EventObject> l) {
super.removeEventListener(l);
if (!hasListeners()) {
model.removeEventListener(this);
}
}
public synchronized void eventRegistered(EventObject e) {
if (e.getSource() == model &&
model.isReady()) {
System.out.println(this.getLabel());
setCanPaint(true);
setWantsPaint(true);
genes = null;
setLayoutGenes();
notifyListeners();
}
}
public int getMaxVertSpace() {
int numTracks = layout.getNumTracks();
return Math.min(Math.max(40,numTracks * 12),120);
}
public int getMinVertSpace() {
int numTracks = layout.getNumTracks();
return Math.min(Math.max(40,numTracks * 12),120);
}
private void setLayoutGenes() {
if (canPaint() && genes == null) {
Iterator<Gene> itr = model.getResults();
genes = new Vector<Gene>();
while(itr.hasNext()) { genes.add(itr.next()); }
layout.setRegions(genes);
}
}
public int getNumTracks() { return layout.getNumTracks(); }
public void paintItem(Graphics2D g,
int x1, int y1,
int x2, int y2) {
if (!canPaint()) {
return;
}
int w = x2 - x1, h = y2 - y1;
int my = y1 + (h / 2);
int numTracks = layout.getNumTracks();
int trackHeight = h;
if(numTracks > 1) {
trackHeight = (int)Math.floor((double)h / (double)numTracks);
}
int geneHeight = Math.max(2, (int)Math.floor((double)trackHeight * 0.80));
int halfHeight = trackHeight / 2;
int halfGeneHeight = geneHeight / 2;
for(int track=0; track<numTracks; track++) {
g.setColor(Color.black);
my = y1 + (halfHeight + (track * trackHeight));
g.drawLine(x1, my, x2, my);
}
Region region = model.getRegion();
int rs = region.getStart(), re = region.getEnd();
int rw = re - rs + 1;
Font oldFont = g.getFont();
g.setFont(attrib.getRegionLabelFont(w,h));
FontMetrics fontmetrics = g.getFontMetrics();
//--------------------------------------------------
double xScale = (double)w / (double)rw;
clearLabels();
boolean drewAnything = false;
for(Gene gene : genes) {
int gs = gene.getStart(), ge = gene.getEnd();
int track = 0;
if(!layout.hasTrack(gene)) {
System.err.println("No track assigned to gene: " + gene.getName());
} else {
track = layout.getTrack(gene);
}
char strand = gene.getStrand();
my = y1 + (halfHeight + (track * trackHeight));
int gx1 = x1 + (int)Math.round((double)(gs - rs) * xScale);
int gx2 = x1 + (int)Math.round((double)(ge - rs) * xScale);
int gxw = gx2 - gx1;
int depth = Math.min(halfGeneHeight, gxw/3);
int gleft = Math.max(gx1, x1), gright = Math.min(gx2, x2);
int gtop = my - (halfGeneHeight/2), gbottom = gtop + (geneHeight/2);
//g.setColor(Color.white);
//g.fillRect(gx1, my - (halfGeneHeight / 2), gxw, geneHeight / 2);
g.setColor(Color.GRAY);
int rectwidth = gright - gleft;
int rectheight = gbottom - gtop;
g.fillRect(gleft, gtop, rectwidth, gbottom - gtop);
drewAnything = true;
g.setColor(Color.black);
//g.drawRect(gx1, my - (halfGeneHeight / 2), gxw, geneHeight / 2);
g.drawLine(gleft, gtop, gright, gtop);
g.drawLine(gleft, gbottom, gright, gbottom);
if(gx1 >= x1) { g.drawLine(gx1, gtop, gx1, gbottom); }
if(gx2 <= x2) { g.drawLine(gx2, gtop, gx2, gbottom); }
// Somewhat prettier gene-name output
//g.drawString(gene.getName(), gx1 + (gxw/3), my);
int nx = Math.max(x1 + 3, gx1 + 3); // gotta do the Math.max(), to make sure the name is on the screen.
int ny = my + (halfGeneHeight / 2) - 2;
int fontsize = g.getFont().getSize();
ArrayList<String> aliases = new ArrayList<String>();
aliases.add(gene.getID());
aliases.add(gene.getName());
aliases.addAll(gene.getAliases());
String first = aliases.remove(0);
String todraw = null;
addLabel(gleft,gtop,rectwidth,gbottom-gtop,first);
if (first.length() * fontsize < rectwidth) {
todraw = first;
}
for (String s : aliases) {
String newtodraw = todraw + ", " + s;
if (props.DrawAllGeneNames && todraw != null &&
fontmetrics.charsWidth((newtodraw).toCharArray(),0,newtodraw.length()) < rectwidth) {
todraw = newtodraw;
}
addLabel(gleft,gtop,rectwidth,gbottom-gtop,s);
}
if (todraw != null && props.DrawGeneNames) {
g.drawString(todraw, nx, ny);
}
// arrows go here
//double arrowHt = htRat * h;
//double arrowWd = wdRat * w;
double arrowHt = htRat * geneHeight;
double arrowWd = wdRat * gxw;
if(arrowWd > arrowHt) { arrowWd = arrowHt; }
int a[];
// forward arrow
if(strand == '+') {
// original arrows
//g.drawLine(gx1, my-halfHeight, gx1 + depth, my);
//g.drawLine(gx1 + depth, my, gx1, my+halfHeight);
int startX = gx1 - 5;
//
int a1 = startX; //(int) Math.round(gx1 / (gx1+depth));
//int a2 = (int) Math.round(startX + (arrowWd * 6)); //(int) Math.round((gx1 + 25) / (gx1+depth));
//int a3 = (int) Math.round(startX + (arrowWd * 8)); //(int) Math.round((gx1 + 35) / (gx1+depth));
int a2 = (int) Math.round(startX + (arrowWd * 8));
int a3 = (int) Math.round(startX + (arrowWd * 12));
int[] t = {a1, a1, a2, a2, a3, a2, a2};
a = t;
}
// backward arrow
else {
// original arrows
//g.drawLine(gx2, my-halfHeight, gx2-depth, my);
//g.drawLine(gx2-depth, my, gx2, my+halfHeight);
int startX = gx2 + 5;
int a1 = startX; //(int) Math.round(gx1 / (gx1+depth));
//int a2 = (int) Math.round(startX - (arrowWd * 6)); //(int) Math.round((gx1 + 25) / (gx1+depth));
//int a3 = (int) Math.round(startX - (arrowWd * 8)); //(int) Math.round((gx1 + 35) / (gx1+depth));
int a2 = (int) Math.round(startX - (arrowWd * 8));
int a3 = (int) Math.round(startX - (arrowWd * 12));
int[] t = {a1, a1, a2, a2, a3, a2, a2};
a = t;
}
/*
int b1 = (int) Math.round(my);
int b2 = (int) Math.round(my - (arrowHt * 13));
int b3 = (int) Math.round(my - (arrowHt * 10));
int b4 = (int) Math.round(my - (arrowHt * 16));
*/
int b1 = (int) Math.round(my);
int b2 = (int) Math.round(my - (arrowHt * 13));
int b3 = (int) Math.round(my - (arrowHt * 10));
int b4 = (int) Math.round(my - (arrowHt * 16));
int[] b = {b1, b2, b2, b3, b2, b4, b2};
g.drawPolyline(a, b, 7);
}
if (drewAnything && props.DrawTrackLabel) {
g.setColor(Color.BLACK);
g.setFont(attrib.getLargeLabelFont(w,h));
g.drawString(getLabel(),x1,y2);
}
g.setFont(oldFont);
}
}