/* Copyright (C) 2014 The Regents of the University of California 
 * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */

#include "common.h"
#include "psl.h"
#include "cutter.h"
#include "hgTracks.h"
#include "hdb.h"
#include "cutterTrack.h"

#define MAX_CUTTER_WINSIZE 250000

void cuttersDrawAt(struct track *tg, void *item,
	struct hvGfx *hvg, int xOff, int y, double scale,
	MgFont *font, Color color, enum trackVisibility vis)
/* Draw the restriction enzyme at position. */
{
struct bed *bed = item;
int heightPer, x1, x2, w;
if (!zoomedToBaseLevel)
    bedDrawSimpleAt(tg, item, hvg, xOff, y, scale, font, color, vis);
else
    {
    heightPer = tg->heightPer;
    x1 = round((double)((int)bed->chromStart-winStart)*scale) + xOff;
    x2 = round((double)((int)bed->chromEnd-winStart)*scale) + xOff;
    color = hvGfxFindColorIx(hvg, 0,0,0);
    w = x2-x1;
    if (w < 1)
	w = 1;
    y += (heightPer >> 1) - 1;
    if (color)
	{
	struct sqlConnection *conn = hAllocConn("hgFixed");
	struct cutter *cut;
	char query[80];
	char strand = bed->strand[0];
	char *s = bed->name;
	int letterWidth, cuts[4];
	int tickHeight = (heightPer>>1) - 1, tickWidth = 2;
	int i, xH;
	Color baseHighlight = getBlueColor();

	baseHighlight = lighterColor(hvg, baseHighlight);
	sqlSafef(query, sizeof(query), "select * from cutters where name=\'%s\'", s);
	cut = cutterLoadByQuery(conn, query);
	letterWidth = round(((double)w)/cut->size);
	cuts[0] = x1 + cut->cut * letterWidth;
	cuts[1] = cuts[0] + cut->overhang * letterWidth;
	cuts[2] = x2 - (cut->cut * letterWidth);
	cuts[3] = cuts[2] - cut->overhang * letterWidth;
	for (i = 0; i < 4; i++)
	    {
	    if (cuts[i] < x1)
		cuts[i] = x1;
	    else if (cuts[i] >= x2)
		cuts[i] = x2 - tickWidth;
	    }
	if (strand == '+')
	    {
	    hvGfxBox(hvg, cuts[0], y - tickHeight, tickWidth, tickHeight, color);
	    hvGfxBox(hvg, cuts[1], y + 2, tickWidth, tickHeight, color);
	    }
	else if (strand == '-')
	    {
	    hvGfxBox(hvg, cuts[2], y - tickHeight, tickWidth, tickHeight, color);
	    hvGfxBox(hvg, cuts[3], y + 2, tickWidth, tickHeight, color);
	    }
	hvGfxBox(hvg, x1, y, w, 2, color);
	/* Draw highlight of non-N bases. */
	xH = x1;
	for (i = 0; i < strlen(cut->seq); i++)
	    {
	    char c = (strand == '+') ? cut->seq[i] : cut->seq[strlen(cut->seq)-i-1];
	    if ((c != 'A') && (c != 'C') && (c != 'G') && (c != 'T'))
		hvGfxBox(hvg, xH, y, letterWidth, 2, baseHighlight);
	    xH += letterWidth;
	    }
	if (tg->drawName && vis != tvSquish)
	    {
	    /* Clip here so that text will tend to be more visible... */
	    w = x2-x1;
	    if (w > mgFontStringWidth(font, s))
		{
		Color textColor = hvGfxContrastingColor(hvg, color);
		hvGfxTextCentered(hvg, x1, y, w, heightPer, textColor, font, s);
		}
	    mapBoxHc(hvg, bed->chromStart, bed->chromEnd, x1, y, x2 - x1, heightPer,
		     tg->track, tg->mapItemName(tg, bed), NULL);
	    }
	hFreeConn(&conn);
	cutterFree(&cut);
	}
    }
}

void cuttersLoad(struct track *tg)
{
struct sqlConnection *conn;
struct cutter *cutters;
struct dnaSeq *windowDna = NULL;
struct bed *bedList = NULL;
int winSize = winEnd - winStart;

conn = hAllocConn("hgFixed");
char query[1024];
sqlSafef(query, sizeof query, "select * from cutters");
cutters = cutterLoadByQuery(conn, query);
windowDna = hDnaFromSeq(database, chromName, winStart, winEnd, dnaUpper);

/* Do different things based on window size. */

if (winSize < MAX_CUTTER_WINSIZE)
    {
    char *enz = cartUsualString(cart, cutterVar, cutterDefault);
    struct slName *cartCutters = NULL;

    if (enz && (strlen(enz) > 0))
	{
	eraseWhiteSpace(enz);
	cartCutters = slNameListFromComma(enz);
	}

    if (cartCutters)
	cullCutters(&cutters, TRUE, cartCutters, 0);
    else
	{
	if (zoomedToBaseLevel)
	    cullCutters(&cutters, FALSE, NULL, 0);
	else if (winSize >= 20000 && winSize < MAX_CUTTER_WINSIZE)
	    {
	    struct slName *popularCutters = slNameListFromComma(CUTTERS_POPULAR);
	    cullCutters(&cutters, TRUE, popularCutters, 0);
	    }
	else if (winSize < 3000)
	    {
	    cullCutters(&cutters, FALSE, NULL, 5);
	    }
	else
	    cullCutters(&cutters, FALSE, NULL, 6);
	}
    bedList = matchEnzymes(cutters, windowDna, winStart);
    if (bedList)
	tg->items = bedList;
    }
cutterFreeList(&cutters);
freeDnaSeq(&windowDna);
hFreeConn(&conn);
}

struct track *cuttersTg()
/* Track group for the restriction enzymes. */
{
struct track *tg = trackNew();
struct trackDb *tdb;
char buf[32];

bedMethods(tg);
AllocVar(tdb);
tg->track = CUTTERS_TRACK_NAME;
tg->table = CUTTERS_TRACK_NAME;
tg->canPack = TRUE;
tg->visibility = tvHide;
tg->hasUi = TRUE;
tg->shortLabel = cloneString(CUTTERS_TRACK_LABEL);
tg->longLabel = cloneString(CUTTERS_TRACK_LONGLABEL);
tg->loadItems = cuttersLoad;
tg->drawItemAt = cuttersDrawAt;
tg->priority = CUTTERS_TRACK_PRIORITY;
tg->defaultPriority = tg->priority;
tg->groupName = cloneString("map");
tg->defaultGroupName = cloneString("map");
tdb->track = cloneString(CUTTERS_TRACK_NAME);
tdb->canPack = tg->canPack;
tdb->table = cloneString(CUTTERS_TRACK_NAME);
tdb->shortLabel = cloneString(tg->shortLabel);
tdb->longLabel = cloneString(tg->longLabel);
tdb->grp = cloneString(tg->groupName);
tdb->priority = tg->priority;
safef(buf, sizeof(buf), "%d", MAX_CUTTER_WINSIZE);
trackDbAddSetting(tdb, "maxWindowToDraw", buf);
trackDbPolish(tdb);
tg->tdb = tdb;
return tg;
}
