/* Some relatively small utility functions that act on ffAlis.
 * (Separated from fuzzyFinder.c so people can do light ffAli 
 * work without including 100k of fuzzyFinder object code.) 
 *
 * This file is copyright 2002 Jim Kent, but license is hereby
 * granted for all use - public, private or commercial. */

#include "common.h"
#include "dnautil.h"
#include "fuzzyFind.h"

static char const rcsid[] = "$Id: ffAli.c,v 1.9 2004/02/13 09:33:32 kent Exp $";

void ffFreeAli(struct ffAli **pAli)
/* Dispose of memory gotten from fuzzyFind(). */
{
struct ffAli *ali = *pAli;
if (ali != NULL)
    {
    while (ali->right)
        ali = ali->right;
    slFreeList(&ali);
    }
*pAli = NULL;
}

int ffOneIntronOrientation(struct ffAli *left, struct ffAli *right)
/* Return 1 for GT/AG intron between left and right, -1 for CT/AC, 0 for no
 * intron. */
{
if (left->nEnd != right->nStart)
    return 0;
return intronOrientation(left->hEnd, right->hStart);
}

int ffIntronOrientation(struct ffAli *ali)
/* Return + for positive orientation overall, - for negative,
 * 0 if can't tell. */
{
struct ffAli *left = ali, *right;
int orient = 0;

if (left != NULL)
    {
    while((right = left->right) != NULL)
	{
	orient += intronOrientation(left->hEnd, right->hStart);
	left = right;
	}
    }
return orient;
}

struct ffAli *ffRightmost(struct ffAli *ff)
/* Return rightmost block of alignment. */
{
while (ff->right != NULL)
    ff = ff->right;
return ff;
}

struct ffAli *ffMakeRightLinks(struct ffAli *rightMost)
/* Given a pointer to the rightmost block in an alignment
 * which has all of the left pointers filled in, fill in
 * the right pointers and return the leftmost block. */
{
struct ffAli *ff, *last = NULL;

for (ff = rightMost; ff != NULL; ff = ff->left)
    {
    ff->right = last;
    last = ff;
    }
return last;
}


static int countGoodStart(struct ffAli *ali)
/* Return number of perfect matchers at start. */
{
DNA *n = ali->nStart;
DNA *h = ali->hStart;
int count = ali->nEnd - ali->nStart;
int i;
for (i=0; i<count; ++i)
    {
    if (*n++ != *h++)
        break;
    }
return i;
}

static int countGoodEnd(struct ffAli *ali)
/* Return number of perfect matchers at start. */
{
DNA *n = ali->nEnd;
DNA *h = ali->hEnd;
int count = ali->nEnd - ali->nStart;
int i;
for (i=0; i<count; ++i)
    {
    if (*--n != *--h)
        break;
    }
return i;
}

void ffCountGoodEnds(struct ffAli *aliList)
/* Fill in the goodEnd and badEnd scores. */
{
struct ffAli *ali;
for (ali = aliList; ali != NULL; ali = ali->right)
    {
    ali->startGood = countGoodStart(ali);
    ali->endGood = countGoodEnd(ali);
    }
}

int ffAliCount(struct ffAli *d)
/* How many blocks in alignment? */
{
int acc = 0;
while (d != NULL)
    {
    ++acc;
    d = d->right;
    }
return acc;
}

struct ffAli *ffAliFromSym(int symCount, char *nSym, char *hSym,
	struct lm *lm, char *nStart, char *hStart)
/* Convert symbol representation of alignments (letters plus '-')
 * to ffAli representation.  If lm is nonNULL, ffAli result 
 * will be lmAlloced, else it will be needMemed. This routine
 * depends on nSym/hSym being zero terminated. */
{
struct ffAli *ffList = NULL, *ff = NULL;
char n, h;
int i;

for (i=0; i<=symCount; ++i)
    {
    boolean isGap;
    n = nSym[i];
    h = hSym[i];
    isGap = (n == '-' || n == 0 || h == '-' || h == 0);
    if (isGap)
	{
	if (ff != NULL)
	    {
	    ff->nEnd = nStart;
	    ff->hEnd = hStart;
	    ff->left = ffList;
	    ffList = ff;
	    ff = NULL;
	    }
	}
    else
	{
	if (ff == NULL)
	    {
	    if (lm != NULL)
		{
		lmAllocVar(lm, ff);
		}
	    else
		{
		AllocVar(ff);
		}
	    ff->nStart = nStart;
	    ff->hStart = hStart;
	    }
	}
    if (n != '-')
	{
	++nStart;
	}
    if (h != '-')
	{
	++hStart;
	}
    }
ffList = ffMakeRightLinks(ffList);
return ffList;
}
