/* Copyright (C) 2011 The Regents of the University of California 
 * See README in this or parent directory for licensing information. */

/* winCounts.h was originally generated by the autoSql program, which also 
 * generated winCounts.c  It was extensively modified to meet the needs of
 * this program.
 *
 * Hand modifications:
 *  - added winCountsNew
 *  - added winCountsReset
 *  - added winCountsSum
 *  - added winCountsIncrCount
 *  - added winCountsGetCount
 *  - added firstCountPos and lastCountPos
 *  - Modified so that array of counts is saved as seperate columns.
 *  - dropped support for comma seperated files.
 */

#include "common.h"
#include "linefile.h"
#include "dystring.h"
#include "jksql.h"
#include "winCounts.h"


/*
 * Table used to translate (A, C, G, T) to (0, 1, 2, 3), and invalid letters
 * to -1.
 */
static int baseMap[256];
static boolean baseMapInitialized = FALSE;

static void initBaseMap()
/* Initialize the base map for the first time */
{
int i;
for (i = 0; i < 256; i++)
    baseMap[i] = -1;
/* alpabetical ordering */
baseMap['A'] = baseMap['a'] = 0;
baseMap['C'] = baseMap['c'] = 1;
baseMap['G'] = baseMap['g'] = 2;
baseMap['T'] = baseMap['t'] = 3;
baseMap['U'] = baseMap['u'] = 3;
baseMapInitialized = TRUE;
}


struct winCounts *winCountsNew(char *chrom)
/* Allocate a new winCounts object. */
{
struct winCounts *ret;
AllocVar(ret);
ret->chrom = cloneString(chrom);
return ret;
}

void winCountsFree(struct winCounts **pEl)
/* Free a single dynamically allocated winCounts such as created
 * with winCountsLoad(). */
{
struct winCounts *el;

if ((el = *pEl) == NULL) return;
freeMem(el->chrom);
freez(pEl);
}

void winCountsFreeList(struct winCounts **pList)
/* Free a list of dynamically allocated winCounts's */
{
struct winCounts *el, *next;

for (el = *pList; el != NULL; el = next)
    {
    next = el->next;
    winCountsFree(&el);
    }
*pList = NULL;
}

void winCountsReset(struct winCounts *el)
/* Reset counts in a winCounts object. */
{
int i;
el->numCounts = 0;
el->firstCountPos = 0;
el->lastCountPos = 0;
for (i = 0; i < 16; i++)
    el->baseCounts[i] = 0;
}

void winCountsIncrCount(struct winCounts *el, char base0, char base1, unsigned pos)
/* Increment the count of occurances of base1 aligned to base0 */
{
int idx0, idx1;
if (!baseMapInitialized)
    initBaseMap();
idx0 = baseMap[(int)base0];
idx1 = baseMap[(int)base1];
if ((idx0 >= 0) && (idx1 >= 0))
    {
    if (el->numCounts == 0)
        el->firstCountPos = pos;
    el->lastCountPos = pos;
    el->baseCounts[((idx0*4)+idx1)]++;
    el->numCounts++;
    }
}

int winCountsGetCount(struct winCounts *el, char base0, char base1)
/* Get the count of occurances of base1 aligned to base0 */
{
int idx0, idx1;
if (!baseMapInitialized)
    initBaseMap();
idx0 = baseMap[(int)base0];
idx1 = baseMap[(int)base1];
if ((idx0 >= 0) && (idx1 >= 0))
    return el->baseCounts[((idx0*4)+idx1)];
else
    return 0;
}

void winCountsSum(struct winCounts *dest, struct winCounts *src)
/* Sum src counts with dest counts, storing in dest counts. */
{
int i;
if (dest->numCounts == 0)
    dest->firstCountPos = src->firstCountPos;
dest->lastCountPos = src->lastCountPos;

dest->numCounts += src->numCounts;
for (i = 0; i < 16; i++)
    dest->baseCounts[i] += src->baseCounts[i];
}

void winCountsStaticLoad(char **row, struct winCounts *ret)
/* Load a row from winCounts table into ret.  The contents of ret will
 * be replaced at the next call to this function. */
{
int i;
ret->chrom = row[0];
ret->chromStart = sqlUnsigned(row[1]);
ret->chromEnd = sqlUnsigned(row[2]);
ret->numCounts = sqlUnsigned(row[3]);
for (i = 0; i < 16; i++)
    ret->baseCounts[i] = sqlUnsigned(row[i+4]);
}

struct winCounts *winCountsLoad(char **row)
/* Load a winCounts from row fetched with select * from winCounts
 * from database.  Dispose of this with winCountsFree(). */
{
struct winCounts *ret;
int i;

AllocVar(ret);
ret->chrom = cloneString(row[0]);
ret->chromStart = sqlUnsigned(row[1]);
ret->chromEnd = sqlUnsigned(row[2]);
ret->numCounts = sqlUnsigned(row[3]);
for (i = 0; i < 16; i++)
    ret->baseCounts[i] = sqlUnsigned(row[i+4]);
return ret;
}

struct winCounts *winCountsLoadAll(char *fileName) 
/* Load all winCounts from a tab-separated file.
 * Dispose of this with winCountsFreeList(). */
{
struct winCounts *list = NULL, *el;
struct lineFile *lf = lineFileOpen(fileName, TRUE);
char *row[5];

while (lineFileRow(lf, row))
    {
    el = winCountsLoad(row);
    slAddHead(&list, el);
    }
lineFileClose(&lf);
slReverse(&list);
return list;
}

void winCountsTabHeaderOut(FILE *f)
/* Print out header for tab-separated file. */
{
    fprintf(f,"#chrom\tchromStart\tchromEnd\tcounts\tAA\tAC\tAG\tAT\tCA\tCC\tCG\tCT\tGA\tGC\tGG\tGT\tTA\tTC\tTG\tTT\tvalue\n");
}

void winCountsTabOut(struct winCounts *el, FILE *f, boolean tightCoords, char *winVal)
/* Print out winCounts as a line in a tab-separated file.
 * If tight coords is true, output start/end of counts rather than windows. */
/*Append a value to the end of each count line if winVal != NULL.*/
{
int i;
fprintf(f, "%s\t", el->chrom);
if (tightCoords)
    { 
        fprintf(f, "%u\t", el->firstCountPos);
        fprintf(f, "%u\t", el->lastCountPos+1);
    }
else
    {
        fprintf(f, "%u\t", el->chromStart);
        fprintf(f, "%u\t", el->chromEnd);
    }
fprintf(f, "%u", el->numCounts);
for (i=0; i<16; ++i)
    {
    fprintf(f, "\t%u", el->baseCounts[i]);
    }
if( winVal != NULL )
    fprintf( f, "\t%s", winVal );
fputc('\n',f);
}

