#include "ajax.h"
#include "ajpat.h"

/* @func ajPatternNew **********************************************************
**
** Constructor for a pattern object
**
** @param [r] name [AjPStr] Name of the pattern
** @param [r] pat [AjPStr] Pattern as string
** @param [r] compiledPat [void*] Compiled pattern reference
** @param [r] type [ajint] type value
** @param [r] mismatch [ajint] mismatch value
** @return [AjPPattern] New pattern object
** @@
******************************************************************************/
AjPPattern ajPatternNew (AjPStr name, AjPStr pat, int type, int mismatch)
{
    AjPPattern pthis;
    void* compiled;

    AJNEW0(pthis);

    if (type == PAT_TYPE_REGEXP)
	compiled = ajRegCompCase(pat);
    else if (type == PAT_TYPE_PRO || type == PAT_TYPE_NUCL)
	/* THIS IS BOGUS, JUST HERE SO IT COMPILES AND REGEX VERSION CAN WORK */
	compiled = pat;

    ajStrAss(&pthis->Name,name);
    ajStrAss(&pthis->Pattern,pat);
    pthis->Compiled = compiled;
    pthis->Type     = type;
    pthis->Mismatch = mismatch;

    return pthis;
}

/* @func ajPatternDel **********************************************************
**
** Destructor for a pattern object
**
** @param [d] pthys [AjPPattern] Pattern object reference
** @return [void]
** @@
******************************************************************************/
void ajPatternDel (AjPPattern* pthys)
{
    AjPPattern thys = *pthys;
    ajStrDel(&thys->Name);
    ajStrDel(&thys->Pattern);

    if (thys->Type == PAT_TYPE_REGEXP)
	ajRegFree(&thys->Compiled);
    else if (thys->Type == PAT_TYPE_PRO || thys->Type == PAT_TYPE_NUCL)
	ajStrDel(thys->Compiled);

    AJFREE (*pthys);

    return;
}

AjPStr ajPatternGetName (AjPPattern thys)
{
    return thys->Name;
}

AjPStr ajPatternGetPattern (AjPPattern thys)
{
    return thys->Pattern;
}

/* @func ajPatternGetCompiledPattern *****************************************
**
** Constructor for a pattern object
**
** @param [r] thys [AjPPattern] Pattern
** @return [void*] Reference for compiled pattern
** @@
******************************************************************************/
void* ajPatternGetCompiledPattern (AjPPattern thys)
{
    return thys->Compiled;
}

ajint ajPatternGetType (AjPPattern thys)
{
    return thys->Type;
}

ajint ajPatternGetMismatch (AjPPattern thys)
{
    return thys->Mismatch;
}


/* @func ajPatlistNew **********************************************************
**
** Constructor for a pattern list object
**
** @return [AjPPatlist] New pattern list object
** @@
******************************************************************************/
AjPPatlist ajPatlistNew (void)
{
    AjPPatlist pthis;

    AJNEW0(pthis);

    pthis->Patlist=ajListNew();
    pthis->Iter=NULL;

    return pthis;
}

/* @func ajPatlistDel **********************************************************
**
** Destructor for a pattern list object
**
** @param [d] pthys [AjPPatlist] Pattern list object reference
** @return [void]
** @@
******************************************************************************/
void ajPatlistDel (AjPPatlist* pthys)
{
    AjPPatlist thys;
    AjPPattern pattern;

    thys = *pthys;

    while (ajListPop(thys->Patlist, (void **)&pattern))
	ajPatternDel(&pattern);
    ajListIterFree (thys->Iter);

    AJFREE(*pthys);

    return;
}

/* @func ajPatlistGetNext *****************************************************
**
** Parses a file into pattern list object. If there is not mismatch value on
** pattern in file, it is assumed to be 0.
**
** @param [w] pthys [AjPPatlist] Pattern list
** @param [r] pthys [AjPStr] Name of the file with patterns
** @param [r] pthys [AjPInt] Type of the patterns
** @return [void]
** @@
******************************************************************************/
void ajPatlistParsePatternFile (AjPPatlist thys, AjPStr inf, ajint type)
{
    AjPPattern pattern;
    AjPStr line = NULL;
    AjPStr pat  = NULL;
    AjPStr name = NULL;
    AjPFile infile = NULL;
    ajint mismatch = 0;
    AjPRegexp mism = ajRegCompC("<mismatch=(\\d+)>");

    infile = ajFileNewIn(inf);
    line = ajStrNew();
    pat  = ajStrNew();
    name = ajStrNew();

    while (ajFileGetsTrim(infile,&line))
    {
	if (ajStrFindC(line,">")>-1)
	{
            if (ajStrLen(name))
            {
		pattern = ajPatternNew (name,pat,type,mismatch);
		ajPatlistAdd (thys,pattern);
		ajStrClear(&name);
                ajStrClear(&pat);
	    }
	    ajStrTrim(&line,1);
	    if (ajRegExec(mism,line))
            {
		ajRegSubI(mism,1,&name);
		ajStrToInt(name,&mismatch);
		ajStrTruncate(&line,ajRegOffset(mism));
		ajStrChompEnd(&line);
	    }
	    else
		mismatch=0;
            ajStrAss(&name,line);
	}
	else
	    ajStrApp (&pat,line);
    }
    pattern = ajPatternNew (name,pat,type,mismatch);
    ajPatlistAdd (thys,pattern);

    ajStrDel(&name);
    ajStrDel(&line);
    ajStrDel(&pat);
    ajRegFree(&mism);

    return;
}

/* @func ajPatlistGetNext *****************************************************
**
** Gets next available pattern from list.
**
** @param [r] pthys [AjPPatlist] Pattern list object
** @param [w] pthys [AjPPattern] Pattern object reference
** @return [void]
** @@
******************************************************************************/
AjBool ajPatlistGetNext (AjPPatlist thys, AjPPattern* pattern)
{
    if (!thys->Iter)
	thys->Iter = ajListIter(thys->Patlist);

    if (ajListIterMore(thys->Iter))
	*pattern = ajListIterNext (thys->Iter);
    else
	return ajFalse;

    return ajTrue;
}

/* @func ajPatlistRewind ******************************************************
**
** Resets the pattern list iteration.
**
** @param [w] pthys [AjPPatlist] Pattern list object reference
** @return [AjPPattern]
** @@
******************************************************************************/
void ajPatlistRewind (AjPPatlist thys)
{
    if (thys->Iter)
	ajListIterFree (thys->Iter);

    return;
}

/* @func ajPatlistAdd *********************************************************
**
** Adds pattern into patternlist
**
** @param [w] pthys [AjPPatlist] Pattern list object reference
** @param [r] pthys [AjPPattern] Pattern to be added
** @return [ajint]
** @@
******************************************************************************/
void ajPatlistAdd (AjPPatlist thys, AjPPattern pat)
{
    ajListPushApp (thys->Patlist, pat);
    ajDebug ("ajPatlistAdd list size %d '%S' '%S' '%d' '%d'\n",
             ajListLength (thys->Patlist), pat->Name,
             pat->Pattern,pat->Type,pat->Mismatch);
    return;
}
