/* altGraph.c was originally generated by the autoSql program, which also 
 * generated altGraph.h and altGraph.sql.  This module links the database and
 * the RAM representation of objects. */

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

#include "common.h"
#include "linefile.h"
#include "dystring.h"
#include "jksql.h"
#include "altGraph.h"
#include "geneGraph.h"


struct altGraph *altGraphLoad(char **row)
/* Load a altGraph from row fetched with select * from altGraph
 * from database.  Dispose of this with altGraphFree(). */
{
struct altGraph *ret;
int sizeOne;

AllocVar(ret);
ret->vertexCount = sqlUnsigned(row[5]);
ret->edgeCount = sqlUnsigned(row[8]);
ret->mrnaRefCount = sqlSigned(row[11]);
ret->id = sqlUnsigned(row[0]);
ret->tName = cloneString(row[1]);
ret->tStart = sqlSigned(row[2]);
ret->tEnd = sqlSigned(row[3]);
strcpy(ret->strand, row[4]);
sqlUbyteDynamicArray(row[6], &ret->vTypes, &sizeOne);
assert(sizeOne == ret->vertexCount);
sqlSignedDynamicArray(row[7], &ret->vPositions, &sizeOne);
assert(sizeOne == ret->vertexCount);
sqlSignedDynamicArray(row[9], &ret->edgeStarts, &sizeOne);
assert(sizeOne == ret->edgeCount);
sqlSignedDynamicArray(row[10], &ret->edgeEnds, &sizeOne);
assert(sizeOne == ret->edgeCount);
sqlStringDynamicArray(row[12], &ret->mrnaRefs, &sizeOne);
assert(sizeOne == ret->mrnaRefCount);
return ret;
}

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

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

struct altGraph *altGraphLoadByQuery(struct sqlConnection *conn, char *query)
/* Load all altGraph from table that satisfy the query given.  
 * Where query is of the form 'select * from example where something=something'
 * or 'select example.* from example, anotherTable where example.something = 
 * anotherTable.something'.
 * Dispose of this with altGraphFreeList(). */
{
struct altGraph *list = NULL, *el;
struct sqlResult *sr;
char **row;

sr = sqlGetResult(conn, query);
while ((row = sqlNextRow(sr)) != NULL)
    {
    el = altGraphLoad(row);
    slAddHead(&list, el);
    }
slReverse(&list);
sqlFreeResult(&sr);
return list;
}

void altGraphSaveToDb(struct sqlConnection *conn, struct altGraph *el, char *tableName, int updateSize)
/* Save altGraph as a row to the table specified by tableName. 
 * As blob fields may be arbitrary size updateSize specifies the approx size
 * of a string that would contain the entire query. Arrays of native types are
 * converted to comma separated strings and loaded as such, User defined types are
 * inserted as NULL. Strings are automatically escaped to allow insertion into the database. */
{
struct dyString *update = newDyString(updateSize);
char  *vTypesArray, *vPositionsArray, *edgeStartsArray, *edgeEndsArray, *mrnaRefsArray;
vTypesArray = sqlUbyteArrayToString(el->vTypes, el->vertexCount);
vPositionsArray = sqlSignedArrayToString(el->vPositions, el->vertexCount);
edgeStartsArray = sqlSignedArrayToString(el->edgeStarts, el->edgeCount);
edgeEndsArray = sqlSignedArrayToString(el->edgeEnds, el->edgeCount);
mrnaRefsArray = sqlStringArrayToString(el->mrnaRefs, el->mrnaRefCount);
sqlDyStringPrintf(update, "insert into %s values ( %u,'%s',%d,%d,'%s',%u,'%s','%s',%u,'%s','%s',%d,'%s')", 
	tableName,  el->id,  el->tName,  el->tStart,  el->tEnd,  el->strand,  el->vertexCount,  vTypesArray ,  vPositionsArray ,  el->edgeCount,  edgeStartsArray ,  edgeEndsArray ,  el->mrnaRefCount,  mrnaRefsArray );
sqlUpdate(conn, update->string);
freeDyString(&update);
freez(&vTypesArray);
freez(&vPositionsArray);
freez(&edgeStartsArray);
freez(&edgeEndsArray);
freez(&mrnaRefsArray);
}


struct altGraph *altGraphCommaIn(char **pS, struct altGraph *ret)
/* Create a altGraph out of a comma separated string. 
 * This will fill in ret if non-null, otherwise will
 * return a new altGraph */
{
char *s = *pS;
int i;

if (ret == NULL)
    AllocVar(ret);
ret->id = sqlUnsignedComma(&s);
ret->tName = sqlStringComma(&s);
ret->tStart = sqlSignedComma(&s);
ret->tEnd = sqlSignedComma(&s);
sqlFixedStringComma(&s, ret->strand, sizeof(ret->strand));
ret->vertexCount = sqlUnsignedComma(&s);
s = sqlEatChar(s, '{');
AllocArray(ret->vTypes, ret->vertexCount);
for (i=0; i<ret->vertexCount; ++i)
    {
    ret->vTypes[i] = sqlUnsignedComma(&s);
    }
s = sqlEatChar(s, '}');
s = sqlEatChar(s, ',');
s = sqlEatChar(s, '{');
AllocArray(ret->vPositions, ret->vertexCount);
for (i=0; i<ret->vertexCount; ++i)
    {
    ret->vPositions[i] = sqlSignedComma(&s);
    }
s = sqlEatChar(s, '}');
s = sqlEatChar(s, ',');
ret->edgeCount = sqlUnsignedComma(&s);
s = sqlEatChar(s, '{');
AllocArray(ret->edgeStarts, ret->edgeCount);
for (i=0; i<ret->edgeCount; ++i)
    {
    ret->edgeStarts[i] = sqlSignedComma(&s);
    }
s = sqlEatChar(s, '}');
s = sqlEatChar(s, ',');
s = sqlEatChar(s, '{');
AllocArray(ret->edgeEnds, ret->edgeCount);
for (i=0; i<ret->edgeCount; ++i)
    {
    ret->edgeEnds[i] = sqlSignedComma(&s);
    }
s = sqlEatChar(s, '}');
s = sqlEatChar(s, ',');
ret->mrnaRefCount = sqlSignedComma(&s);
s = sqlEatChar(s, '{');
AllocArray(ret->mrnaRefs, ret->mrnaRefCount);
for (i=0; i<ret->mrnaRefCount; ++i)
    {
    ret->mrnaRefs[i] = sqlStringComma(&s);
    }
s = sqlEatChar(s, '}');
s = sqlEatChar(s, ',');
*pS = s;
return ret;
}

void altGraphFree(struct altGraph **pEl)
/* Free a single dynamically allocated altGraph such as created
 * with altGraphLoad(). */
{
struct altGraph *el;

if ((el = *pEl) == NULL) return;
freeMem(el->tName);
freeMem(el->vTypes);
freeMem(el->vPositions);
freeMem(el->edgeStarts);
freeMem(el->edgeEnds);
/* All strings in mrnaRefs are allocated at once, so only need to free first. */
if (el->mrnaRefs != NULL)
    freeMem(el->mrnaRefs[0]);
freeMem(el->mrnaRefs);
freez(pEl);
}

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

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

void altGraphOutput(struct altGraph *el, FILE *f, char sep, char lastSep) 
/* Print out altGraph.  Separate fields with sep. Follow last field with lastSep. */
{
int i;
fprintf(f, "%u", el->id);
fputc(sep,f);
if (sep == ',') fputc('"',f);
fprintf(f, "%s", el->tName);
if (sep == ',') fputc('"',f);
fputc(sep,f);
fprintf(f, "%d", el->tStart);
fputc(sep,f);
fprintf(f, "%d", el->tEnd);
fputc(sep,f);
if (sep == ',') fputc('"',f);
fprintf(f, "%s", el->strand);
if (sep == ',') fputc('"',f);
fputc(sep,f);
fprintf(f, "%u", el->vertexCount);
fputc(sep,f);
if (sep == ',') fputc('{',f);
for (i=0; i<el->vertexCount; ++i)
    {
    fprintf(f, "%u", el->vTypes[i]);
    fputc(',', f);
    }
if (sep == ',') fputc('}',f);
fputc(sep,f);
if (sep == ',') fputc('{',f);
for (i=0; i<el->vertexCount; ++i)
    {
    fprintf(f, "%d", el->vPositions[i]);
    fputc(',', f);
    }
if (sep == ',') fputc('}',f);
fputc(sep,f);
fprintf(f, "%u", el->edgeCount);
fputc(sep,f);
if (sep == ',') fputc('{',f);
for (i=0; i<el->edgeCount; ++i)
    {
    fprintf(f, "%d", el->edgeStarts[i]);
    fputc(',', f);
    }
if (sep == ',') fputc('}',f);
fputc(sep,f);
if (sep == ',') fputc('{',f);
for (i=0; i<el->edgeCount; ++i)
    {
    fprintf(f, "%d", el->edgeEnds[i]);
    fputc(',', f);
    }
if (sep == ',') fputc('}',f);
fputc(sep,f);
fprintf(f, "%d", el->mrnaRefCount);
fputc(sep,f);
if (sep == ',') fputc('{',f);
for (i=0; i<el->mrnaRefCount; ++i)
    {
    if (sep == ',') fputc('"',f);
    fprintf(f, "%s", el->mrnaRefs[i]);
    if (sep == ',') fputc('"',f);
    fputc(',', f);
    }
if (sep == ',') fputc('}',f);
fputc(lastSep,f);
}

/* -------------------------------- End autoSql Generated Code -------------------------------- */


static boolean isEndVertice(bool **em, int vertexCount, int vertice, 
	unsigned char *vTypes)
/* check to see if there are any edges coming out of this vertice */
{
int i;
for(i=0; i<vertexCount; i++)
    {
    if(em[vertice][i] && (vTypes[i] != ggUnused))
	return FALSE;
    }
return TRUE;
}

void countPathsFromVertice(bool **em, unsigned char *vTypes, int vertexCount, int vertice, int *pathCount)
/* recursively count paths from vertice */
{
int i=0;
/* check for termination */
if( isEndVertice(em, vertexCount, vertice, vTypes))
    {
    (*pathCount)++;
    }
else
    {
    /* recursively call for all vertices that are connected to from this vertex */
    for(i = 0; i < vertexCount; i++)
	{
	if(em[vertice][i] && vTypes[i] != ggUnused)
	    {
	    countPathsFromVertice(em, vTypes, vertexCount, i, pathCount);
	    }
	}
    }
}

int altGraphNumAltSplices(struct altGraph *ag)
/* Count number of times that exons have more than one edge through them */
{
int pathCount=0;
int i=0;
int vertexCount = ag->vertexCount;
bool **em;

/* construct the edge matrix */
AllocArray(em, vertexCount);
for (i=0; i<vertexCount; ++i)
    {
    AllocArray(em[i], vertexCount);
    }
for (i=0; i<ag->edgeCount; ++i)
    em[ag->edgeStarts[i]][ag->edgeEnds[i]] = TRUE;

/* recursively count all possible paths */
countPathsFromVertice(em, ag->vTypes, vertexCount, 0, &pathCount);

/* clean up */
for(i = 0; i < vertexCount; i++)
    freez(&em[i]);
freez(&em);

return pathCount;
}
