/* custom - stuff related to custom tracks. */

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

#include "common.h"
#include "linefile.h"
#include "hash.h"
#include "obscure.h"
#include "cheapcgi.h"
#include "cart.h"
#include "jksql.h"
#include "hdb.h"
#include "trackDb.h"
#include "grp.h"
#include "customTrack.h"

#include "hgGenome.h"


struct customTrack *theCtList = NULL;	/* List of custom tracks. */
struct slName *browserLines = NULL;	/* Browser lines in custom tracks. */

struct customTrack *getCustomTracks()
/* Get custom track list. */
{
//fprintf(stdout,"database %s in cart %s", database, cartString(cart, "db"));
cartSetString(cart, "db", database);
if (theCtList == NULL)
    theCtList = customTracksParseCart(database, cart, &browserLines, NULL);
return(theCtList);
}

void flushCustomTracks()
/* Flush custom track list. */
{
theCtList = NULL;
}

struct customTrack *newCt(char *ctName, char *ctDesc, int visNum, char *ctUrl,
			  int fields)
/* Make a new custom track record for the query results. */
{
struct customTrack *ct;
struct trackDb *tdb;
char buf[256];

AllocVar(ct);
AllocVar(tdb);
tdb->table = customTrackTableFromLabel(ctName);
tdb->track = cloneString(tdb->table);
tdb->shortLabel = ctName;
tdb->longLabel = ctDesc;
safef(buf, sizeof(buf), "bed %d .", fields);
tdb->type = cloneString(buf);
tdb->visibility = visNum;
tdb->url = ctUrl;
ct->tdb = tdb;
ct->fieldCount = fields;
ct->needsLift = FALSE;
ct->fromPsl = FALSE;
ct->wiggle = FALSE;
ct->wigAscii = (char *)NULL;
ct->wigFile = (char *)NULL;
ct->wibFile = (char *)NULL;
ctAddToSettings(ct, CT_UNPARSED, "true");
return ct;
}


struct hTableInfo *ctToHti(struct customTrack *ct)
/* Create an hTableInfo from a customTrack. */
{
struct hTableInfo *hti;

if (ct == NULL)
    return(NULL);

AllocVar(hti);
hti->rootName = cloneString(ct->tdb->table);
hti->isPos = TRUE;
hti->isSplit = FALSE;
hti->hasBin = FALSE;
hti->type = cloneString(ct->tdb->type);
if (ct->fieldCount >= 3)
    {
    strncpy(hti->chromField, "chrom", 32);
    strncpy(hti->startField, "chromStart", 32);
    strncpy(hti->endField, "chromEnd", 32);
    }
if (ct->fieldCount >= 4)
    {
    strncpy(hti->nameField, "name", 32);
    }
if (ct->fieldCount >= 5)
    {
    strncpy(hti->scoreField, "score", 32);
    }
if (ct->fieldCount >= 6)
    {
    strncpy(hti->strandField, "strand", 32);
    }
if (ct->fieldCount >= 8)
    {
    strncpy(hti->cdsStartField, "thickStart", 32);
    strncpy(hti->cdsEndField, "thickEnd", 32);
    hti->hasCDS = TRUE;
    }
if (ct->fieldCount >= 12)
    {
    strncpy(hti->countField, "blockCount", 32);
    strncpy(hti->startsField, "chromStarts", 32);
    strncpy(hti->endsSizesField, "blockSizes", 32);
    hti->hasBlocks = TRUE;
    }

return(hti);
}

struct slName *getBedFields(int fieldCount)
/* Get list of fields for bed of given size. */
{
struct slName *fieldList = NULL, *field;
if (fieldCount >= 3)
    {
    field = newSlName("chrom");
    slAddHead(&fieldList, field);
    field = newSlName("chromStart");
    slAddHead(&fieldList, field);
    field = newSlName("chromEnd");
    slAddHead(&fieldList, field);
    }
if (fieldCount >= 4)
    {
    field = newSlName("name");
    slAddHead(&fieldList, field);
    }
if (fieldCount >= 5)
    {
    field = newSlName("score");
    slAddHead(&fieldList, field);
    }
if (fieldCount >= 6)
    {
    field = newSlName("strand");
    slAddHead(&fieldList, field);
    }
if (fieldCount >= 8)
    {
    field = newSlName("thickStart");
    slAddHead(&fieldList, field);
    field = newSlName("thickEnd");
    slAddHead(&fieldList, field);
    }
if (fieldCount >= 9)
    {
    field = newSlName("itemRgb");
    slAddHead(&fieldList, field);
    }
if (fieldCount >= 12)
    {
    field = newSlName("blockCount");
    slAddHead(&fieldList, field);
    field = newSlName("blockSizes");
    slAddHead(&fieldList, field);
    field = newSlName("chromStarts");
    slAddHead(&fieldList, field);
    }
if (fieldCount >= 15)
    {
    field = newSlName("expCount");
    slAddHead(&fieldList, field);
    field = newSlName("expIds");
    slAddHead(&fieldList, field);
    field = newSlName("expScores");
    slAddHead(&fieldList, field);
    }
slReverse(&fieldList);
return fieldList;
}



void removeNamedCustom(struct customTrack **pList, char *name)
/* Remove named custom track from list if it's on there. */
{
struct customTrack *newList = NULL, *ct, *next;
for (ct = *pList; ct != NULL; ct = next)
    {
    next = ct->next;
    if (!sameString(ct->tdb->table, name))
        {
	slAddHead(&newList, ct);
	}
    }
slReverse(&newList);
*pList = newList;
}

static void customTrackBedOnChrom(
	char *chrom,	        /* chrom to get data from. */
	struct customTrack *ct, /* Custom track. */
	struct lm *lm,		/* Local memory pool. */
	struct bed **pBedList   /* Output get's appended to this list */
	)
/* Get the custom tracks passing filter on a single chrom. */
{
struct bed *bed;

if (ct->dbTrack)
    {
    int fieldCount = ct->fieldCount;
    char query[512];
    int rowOffset = 0;
    char **row;
    struct sqlConnection *conn = hAllocConn(CUSTOM_TRASH);
    struct sqlResult *sr = NULL;

    sqlSafef(query, sizeof(query), "select * from %s where chrom='%s'", ct->dbTableName, chrom);
    sr = sqlGetResult(conn, query);
    if (sameString("bin",sqlFieldName(sr)))
	++rowOffset;
    while ((row = sqlNextRow(sr)) != NULL)
	{
	bed = bedLoadN(row+rowOffset, fieldCount);
	struct bed *copy = lmCloneBed(bed, lm);
	slAddHead(pBedList, copy);
	}
    sqlFreeResult(&sr);
    hFreeConn(&conn);
    }
else
    {
    for (bed = ct->bedList; bed != NULL; bed = bed->next)
	{
	if (sameString(bed->chrom, chrom))
	    {
	    struct bed *copy = lmCloneBed(bed, lm);
	    slAddHead(pBedList, copy);
	    }
	}
    }
}



struct bed *customTrackGetBedsForChrom(char *name, char *chrom,
	struct lm *lm,	int *retFieldCount)
/* Get list of beds from custom track of given name that are
 * in given chrom. You can bedFree this when done. */
{
struct customTrack *ct = lookupCt(name);
struct bed *bedList = NULL;
int fieldCount;

if (ct == NULL)
    errAbort("Can't find custom track %s", name);

/* Figure out how to filter things. */
fieldCount = ct->fieldCount;

/* Grab beds for a chrom. */
customTrackBedOnChrom(chrom, ct, lm, &bedList);

/* Set return variables and clean up. */
slReverse(&bedList);

if (retFieldCount != NULL)
    *retFieldCount = fieldCount;
return bedList;
}

