/*
  Copyright (c) 2003 by Stefan Kurtz and The Institute for
  Genomic Research.  This is OSI Certified Open Source Software.
  Please see the file LICENSE for licensing information and
  the file ACKNOWLEDGEMENTS for names of contributors to the
  code base.
*/

#ifndef STREEACC_H
#define STREEACC_H

#ifdef STREESMALL
#include "st_streesmall.h"
#endif

#ifdef STREELARGE
#include "st_streelarge.h"
#endif

#ifdef STREEHUGE
#include "st_streehuge.h"
#endif

#ifdef ST_DEBUG
#define SHOWVAL(S)    fprintf(stderr,"#%s %lu\n",#S,(Showuint) S)
#define SETVAL(E,VAL) *(E) = VAL;\
                      if((E) > stree->maxset)\
                      {\
                        stree->maxset = E;\
                      }
#else

//}

/*
  This file contains some macros for retrieving depth, headpositions,
  and suffix links.
*/

#define SETVAL(E,VAL) *(E) = VAL

//\Ignore{

#endif

//}

/*
  \texttt{GETBOTH} retrieves the \emph{depth} and the \emph{headposition} of 
  a branching node referred to by \texttt{PT}. In case, we need these values
  for a node of the current chain, the distance is not set. So we compute 
  it as the difference between the next free base address, and the base 
  address of the node the chain starts with. Then we refer to the current depth
  and the number of the current leaf. In case, the node is large, we can
  directly look up the values. In case, the node is small, we determine
  the distance, and a pointer to the large node at the end of the chain.
  Then we can retrieve the depth and the head positions from this, as
  proved in \cite{KUR:1998}, Observation 7.
*/

#define GETBOTH(DP,HP,PT) \
        if(stree->chainstart != NULL && (PT) >= stree->chainstart)\
        {\
          distance = 1 + \
                     DIVBYSMALLINTS((Uint) (stree->nextfreebranch - (PT)));\
          DP = stree->currentdepth + distance;\
          HP = stree->nextfreeleafnum - distance;\
        } else\
        {\
          if(ISLARGE(*(PT)))\
          {\
            DP = GETDEPTH(PT);\
            HP = GETHEADPOS(PT);\
          } else\
          {\
            distance = GETDISTANCE(PT);\
            GETCHAINEND(largeptr,PT,distance);\
            DP = GETDEPTH(largeptr) + distance;\
            HP = GETHEADPOS(largeptr) - distance;\
          }\
        }

/*
  The macros \texttt{GETONLYHEADPOS}, \texttt{GETONLYDEPTH}, and
  \texttt{GETDEPTHAFTERHEADPOS} retrieve the depth or the head position.
  This is done as in the previous macro, and we omit it here.
*/

//\Ignore{

#define GETONLYHEADPOS(HP,PT) \
        if(stree->chainstart != NULL && (PT) >= stree->chainstart)\
        {\
          distance = 1 + DIVBYSMALLINTS((Uint) (stree->nextfreebranch - (PT)));\
          HP = stree->nextfreeleafnum - distance;\
        } else\
        {\
          if(ISLARGE(*(PT)))\
          {\
            HP = GETHEADPOS(PT);\
          } else\
          {\
            distance = GETDISTANCE(PT);\
            GETCHAINEND(largeptr,PT,distance);\
            HP = GETHEADPOS(largeptr) - distance;\
          }\
        }

#define GETONLYDEPTH(DP,PT) \
        if(stree->chainstart != NULL && (PT) >= stree->chainstart)\
        {\
          distance = 1 + DIVBYSMALLINTS((Uint) (stree->nextfreebranch - (PT)));\
          DP = stree->currentdepth  + distance;\
        } else\
        {\
          if(ISLARGE(*(PT)))\
          {\
            DP = GETDEPTH(PT);\
          } else\
          {\
            distance = GETDISTANCE(PT);\
            GETCHAINEND(largeptr,PT,distance);\
            DP = GETDEPTH(largeptr) + distance;\
          }\
        }

#define GETDEPTHAFTERHEADPOS(DP,PT) \
        if(stree->chainstart != NULL && (PT) >= stree->chainstart)\
        {\
          DP = stree->currentdepth + distance;\
        } else\
        {\
          if(ISLARGE(*(PT)))\
          {\
            DP = GETDEPTH(PT);\
          } else\
          {\
            DP = GETDEPTH(largeptr) + distance;\
          }\
        }

#define GETHEADPOSAFTERDEPTH(HP,PT) \
        if(stree->chainstart != NULL && (PT) >= stree->chainstart)\
        {\
          HP = stree->nextfreeleafnum - distance;\
        } else\
        {\
          if(ISLARGE(*(PT)))\
          {\
            HP = GETHEADPOS(PT);\
          } else\
          {\
            HP = GETHEADPOS(largeptr) - distance;\
          }\
        }

#define NEXTNODE(PT)\
        if(ISLARGE(*(PT)))\
        {\
          PT += LARGEINTS;\
        } else\
        {\
          PT += SMALLINTS;\
        }

//}

/*
  The suffix link is always determined for the \emph{headnode}. If this
  is large, the we have to retrieve it from that node. Otherwise, the
  suffix link refers to the next node. In both cases, the depth of the 
  \emph{headnode} is decremented.
*/

#define FOLLOWSUFFIXLINK\
        if(ISLARGE(*(stree->headnode)))\
        {\
          stree->headnode = stree->branchtab + GETSUFFIXLINK(stree->headnode);\
        } else\
        {\
          stree->headnode += SMALLINTS;\
        }\
        stree->headnodedepth--

/*
  Whenever \emph{insertleaf} is called, \emph{onsuccpath} stores the 
  address of the new leaf.
  Whenever \emph{insertbranch} is called, \emph{onsuccpath} stores the 
  address of the new branching node. Both nodes are a successor of the
  node, for which a suffix link is possible to be computed in the
  next step. In case linear retrieval of suffix links is required, 
  it is possible to start at the node referenced by \emph{onsuccpath}.
*/

#if defined(STREELARGE) || defined(STREESMALL)
#define RECALLSUCC(S)             stree->onsuccpath = S
#else
#define RECALLSUCC(S)             /* Nothing */
#endif

/*
  The following three macros handle the setting of the suffix link in a 
  nil reference. The \emph{RECALL}-macros store the address of the 
  reference. In case the reference is a new leaf, this is marked. 
*/

#define RECALLNEWLEAFADDRESS(A)   stree->setlink = A;\
                                  stree->setatnewleaf = True
#define RECALLLEAFADDRESS(A)      stree->setlink = A;\
                                  stree->setatnewleaf = False
#define RECALLBRANCHADDRESS(A)    stree->setlink = (A) + 1;\
                                  stree->setatnewleaf = False

#ifdef STREEHUGE
#define SETNILBIT                 *(stree->setlink) = NILBIT
#else
#define SETNILBIT                 if(stree->setatnewleaf)\
                                  {\
                                    *(stree->setlink) = NILBIT;\
                                  } else\
                                  {\
                                    *(stree->setlink) |= NILBIT;\
                                  }
#endif

#define SETMAXBRANCHDEPTH(D)      if((D) > stree->maxbranchdepth)\
                                  {\
                                    stree->maxbranchdepth = D;\
                                  }

//\Ignore{

/*
#ifdef SHOWLEAD
#define LEADLEVEL 3
#else
#define LEADLEVEL 4
#endif
*/

#define LEADLEVEL 2

#ifdef ST_DEBUG
#define SHOWINDEX(NODE)\
        if((NODE) == UNDEFINEDREFERENCE)\
        {\
          DEBUG0(LEADLEVEL,"UNDEFINEDREFERENCE");\
        } else\
        {\
          if(NILPTR(NODE))\
          {\
            DEBUG0(LEADLEVEL,"NILPTR");\
          } else\
          {\
            if(ISLEAF(NODE))\
            {\
              DEBUG1(LEADLEVEL,"Leaf %lu",(Showuint) GETLEAFINDEX(NODE));\
            } else\
            {\
              if(ISLARGE(stree->branchtab[GETBRANCHINDEX(NODE)]))\
              {\
                DEBUG1(LEADLEVEL,"Large %lu",(Showuint) GETBRANCHINDEX(NODE));\
              } else\
              {\
                DEBUG1(LEADLEVEL,"Small %lu",(Showuint) NODE);\
              }\
            }\
          }\
        }
#else
#define SHOWINDEX(NODE) /* Nothing */
#endif

#ifdef ST_DEBUG
void showtable(Suffixtree *stree,BOOL final);
void checkstree(Suffixtree *stree);
void showstate(Suffixtree *stree);
void showstree(Suffixtree *stree);
void enumlocations(Suffixtree *stree,void(*processloc)(Suffixtree *stree,Location *));
void checklocation(Suffixtree *stree,Location *loc);
#endif

//TLB; access.c functions
Uint getmaxtextlenstree(void);
void getbranchinfostree(Suffixtree *stree,Uint whichinfo,
                        Branchinfo *branchinfo,Bref btptr);

//TLB; streedbg.c functions
void showlocation(FILE *fp,Suffixtree *stree,Location *loc);

//TLB; scanpref.c functions
SYMBOL *scanprefixfromnodestree(Suffixtree *stree,Location *loc,
                                           Bref btptr,SYMBOL *left,
                                           SYMBOL *right,Uint rescanlength);
SYMBOL *scanprefixstree(Suffixtree *stree,Location *outloc,
                                   Location *inloc,SYMBOL *left,
                                   SYMBOL *right,Uint rescanlength);
SYMBOL *findprefixpathstree(Suffixtree *stree,
                                       ArrayPathinfo *path,
                                       Location *outloc,
                                       Location *inloc,
                                       SYMBOL *left,
                                       SYMBOL *right,
                                       Uint rescanlength);

//TLB; linkloc.c functions
void rescanstree(Suffixtree *stree,Location *loc,
                 Bref btptr,SYMBOL *left,SYMBOL *right);
void linklocstree(Suffixtree *stree,Location *outloc,Location *inloc);

//TLB; dfs.c functions
Sint depthfirststree(Suffixtree *stree,Reference *startnode,
                     Sint (*processleaf)(Uint,Bref,void *),
                     BOOL (*processbranch1)(Bref,void *),
                     Sint (*processbranch2)(Bref,void *),
                     BOOL (*stoptraversal)(void *),void *stopinfo,void *info);

//TLB; overmax.c functions
void overallstree(Suffixtree *stree,BOOL skiproot,
                  void(*processnode)(Suffixtree *,Bref,Uint,Uint,void *),
                  void *info);

#endif

//}
