/*   -*- coding: utf-8 -*-  */
/****************************************************************************
*
*     Module SxmlNode
*     Commande : SxmlFindText.c
*
****************************************************************************/

#include <stdio.h>
#include "SxmlNode.h"
#include "Buffer.h"
#include "StrDict.h"
#include <string.h>
#include "RegExp.h"
#include "SxmlNode.h"
#include "Utf8Text.h"

int	  SFTcontextBeforeOption;
int	  SFTcontextAfterOption;
int       SFToutputWiki;
int       SFTexpressionMode;
char*	  SFTstringOption;
RegExp*   SFTContextRegExp;
SxmlNode* SFTstackPath;
StrDict*  SFTmainDict;
StrDict*  SFTbinomialDict;
int       SFTconvertMode;
Buffer*   SFTbinomialKey;

    int getopt();
    extern char *optarg;

void SFTprintStack(SxmlNode *stack)
{
  SxmlNode *elem;
  SxmlReset(stack);
  while ((elem=SxmlNodeListNextNode(stack)))
    {
      int r;
      r=SxmlRankWithTagName(elem);
      printf ("%s", SxmlNodeName(elem));
      if (r!=1) printf("[%d]", r);
      if (SxmlIteratorHasNextNode(stack)) printf ("/");
      else 
	{
	  if (SFToutputWiki==1) printf(" ");
	  else printf ("\t");
	}
    }  
}

void SFTprintStackNum(SxmlNode *stack)
{
  SxmlNode *elem;
  SxmlReset(stack);
  while ((elem=SxmlNodeListNextNode(stack)))
    {
      if (SxmlIteratorHasNextNode(stack)) printf ("%d/",SxmlRank(elem));
      else 
	{
	  if(SFToutputWiki==1)printf ("%d",SxmlRank(elem));
	  else printf ("%d\t",SxmlRank(elem));
	}
    }  
}

void SFTprint(char *matchToPrint, char *field, char *beginStr, char *endStr)
{
  int offset;
  static Buffer *memKey=NULL;
  if(SxmlInputRecordKey) 
    {
      if (SFToutputWiki==0)
	{
	  printf ("%s\t",SxmlInputRecordKey);
	}
      else
	{
	  if (!memKey)
	    {
	      memKey=NewBuffer();
	      printf ("%s\n",SxmlInputRecordKey);
	      BufferStrcpy(memKey, SxmlInputRecordKey);
	    }
	  else if (strcmp(SxmlInputRecordKey, BufferString(memKey))!=0)
	    {
	      printf ("%s\n",SxmlInputRecordKey);
	      BufferStrcpy(memKey, SxmlInputRecordKey);
	    }
	}
    }

  if(SFToutputWiki==1)
    {
      printf ("::");
      SFTprintStack(SFTstackPath);
      printf("(");
      SFTprintStackNum(SFTstackPath);
      printf(" - ");
      offset=beginStr-field;
      printf("%d)",offset);
    }
  else
    {
      SFTprintStackNum(SFTstackPath);
      SFTprintStack(SFTstackPath);
      offset=beginStr-field;
      printf("%d\t",offset);
    }
  if(SFToutputWiki==1)printf ("\n:::");

  if (SFTcontextBeforeOption > 0)
    {
      int nToPrint;
      nToPrint=beginStr-field;
      if (nToPrint==0) printf("(null)");
      else
	{
	  if (nToPrint > SFTcontextBeforeOption) nToPrint=SFTcontextBeforeOption;
	  while (nToPrint--)putchar (field[beginStr-field-nToPrint-1]);
	}
      putchar('\t');
    }
  if (SFToutputWiki==1)printf ("'''%s'''",matchToPrint);
  else printf ("%s",matchToPrint);
  if (SFTcontextAfterOption > 0)
    {
      int nDone;
      nDone=0;
      putchar ('\t');
      if (strlen(endStr)==0) printf("(null) ");
      else
	{
	  while ((nDone<SFTcontextAfterOption)&&(endStr[nDone]))
	    {
	      putchar(endStr[nDone++]);
	    }
	}
    }
  putchar('\n');
}

void SFTproceedText(char *field, char *toParse)
{
  char *beginStr;
  char *endStr;
  char *match;
  char *matchToPrint;

  beginStr=NULL;
  matchToPrint=NULL;
  match=NULL;

  if (SFTstringOption)
    {
      beginStr=strstr(toParse, SFTstringOption);
      if (beginStr)
	{
	  endStr=beginStr+strlen(SFTstringOption);
	  matchToPrint=SFTstringOption;
	}
      else matchToPrint=NULL;
    }
  else if (SFTContextRegExp)
    {
      match=RegExpExtract(SFTContextRegExp, toParse);
      if (match) 
	{
	  beginStr=RegExpLoc1;
	  endStr=RegExpLoc2;
	  matchToPrint=match;
	}
    }
  else if(SFTmainDict)
    {
      char *toParseIter;
      toParseIter=toParse;
      beginStr=toParse;
      while ((match=Utf8GetAlphaString(toParseIter, &toParseIter, SFTconvertMode)))
	{
	  char *dictValue;
	  if ((dictValue=StrDictSearch(SFTmainDict, match)))
	    {
	      if (SFTbinomialDict)
		{
		  BufferStrcpy(SFTbinomialKey, match);
		  match=Utf8GetAlphaString(toParseIter, &toParseIter, SFTconvertMode);
		  if (match)
		    {
		      BufferStrcat(SFTbinomialKey, " ");
		      BufferStrcat(SFTbinomialKey, match);
		      if (StrDictSearch(SFTbinomialDict, BufferString(SFTbinomialKey)))
			{
			  endStr=toParseIter;
			  matchToPrint=BufferString(SFTbinomialKey);
			  break;
			}
		    }
		  else return;
		}
	      else
		{
		  SxmlNode *dictNode;
		  if (SFTexpressionMode==0)
		    { 
		      endStr=toParseIter;
		      matchToPrint=match;
		      break;
		    }
		  /*   expression mode */
		  dictNode=SxmlFromString(dictValue);
		  if (SxmlNodeHasName(dictNode, "word"))
		    {
		      endStr=toParseIter;
		      matchToPrint=SxmlLeafText(dictNode);
		      break;
		    }
		  if (SxmlNodeHasName(dictNode, "string"))
		    {
		      char *dictStringToMatch;
		      dictStringToMatch=SxmlLeafText(dictNode);
		      if (strncmp(match, dictStringToMatch, strlen(dictStringToMatch))==0)
			{
			  matchToPrint=dictStringToMatch;
			  endStr=toParseIter+strlen(dictStringToMatch)-strlen(match);
                          break;
			}
		    }
		  matchToPrint=NULL;
		  if (SxmlNodeHasName(dictNode, "list"))
		    {
		      SxmlNode *elemNode;
		      SxmlReset (dictNode);
		      while ((elemNode=SxmlNextNode(dictNode)))
			{
			  if (SxmlNodeHasName(elemNode, "word"))
			    {
			      endStr=toParseIter;
			      matchToPrint=SxmlLeafText(elemNode);
			      break;
			    }
			  else
			    {
			      char *dictStringToMatch;
			      dictStringToMatch=SxmlLeafText(elemNode);
			      if (strncmp(match, dictStringToMatch, strlen(dictStringToMatch)))
				{
				  matchToPrint=dictStringToMatch;
				  endStr=toParseIter+strlen(dictStringToMatch)-strlen(match);
				  break;
				}
			    }
			}
		      break;
		    }
		}
	    }
	  else
	    {
	      beginStr=toParseIter;
	    }
	}  
    }
  if (!matchToPrint)return;

  SFTprint(matchToPrint, field, beginStr, endStr);
      
  if(SFTContextRegExp) free(match);
  SFTproceedText(field, endStr);
}

void SFTfindAndPrint(SxmlNode *node)
{
  SxmlNode *nextSibl;
  if (!node) return;
  if (SxmlIsText(node))
    {
      char *field;

      field=SxmlNodeValue(node);
      SFTproceedText(field, field);
    }
  else if (SxmlIsElement(node))
    {
      SxmlNodeListAppend(SFTstackPath, node);
      SFTfindAndPrint(SxmlFirstChild(node));
      SxmlNodeListPull(SFTstackPath);
    }
  if ((nextSibl=SxmlNextSibling(node))) SFTfindAndPrint(nextSibl);
  return;
}

  int SFTmainOption;

void SFTtextExclusive()
{
  SFTmainOption++;
  if ( SFTmainOption>1)
    {
      perror("**** SxmlFindContest, *error*  options : -d -D -r and -s are exclusive\n");
      exit (EXIT_FAILURE);
    }
}

int main (int argc, char **argv)
{
  char cOpt;
  SxmlNode *document;

  SFTmainOption=0;
  SFToutputWiki=0;
  SFTexpressionMode=0;
  SFTstringOption=NULL;
  SFTmainDict=NULL;
  SFTbinomialDict=NULL;
  SFTContextRegExp=NULL;
  SFTconvertMode=0;
  SFTbinomialKey=NewBuffer();

  while((cOpt=getopt(argc,argv,"a:b:B:d:D:els:r:t:w"))!=EOF)
    /*                                                 a: after
                                                       b: before
                                                       B: binomial dict
                                                       D: dictionary
                                                       d: dictionary entry
                                                       e: dictionary with expression mode
                                                       l: lower case mode 
                                                       r: regexp
                                                       s: string
                                                       T: trace
                                                       w : outputMode = wiki
    */
    {
      switch(cOpt)
	{
	case 'a':
	  SFTcontextAfterOption=atoi(optarg);
	  break;
	case 'b':
	  SFTcontextBeforeOption=atoi(optarg);
	  break;
	case 'B':
	  SFTbinomialDict=StrDictFromFile(optarg);
	  break;
	case 'D':
	  SFTmainDict=StrDictFromFile(optarg);
	  SFTtextExclusive();
	  break;
	case 'd':
	  if (!SFTmainDict) 
	    {
	      SFTmainDict=StrDictCreate(10,10);
	      SFTtextExclusive();
	    }
	  StrDictAddNewDatum(SFTmainDict, optarg, optarg);
	  break;
	case 'e':
	  SFTexpressionMode=1;
	  break;
	case 'l':
	  SFTconvertMode='l';
	  break;
	case 'r':
	  SFTContextRegExp=RegExpCreate(optarg);
	  SFTtextExclusive();
	  break;
	case 's':
	  SFTstringOption= optarg;
	  SFTtextExclusive();
	  break;
	case 'w':
          SFToutputWiki=1;
	  break;
	}
    }

  if (SFTstringOption && SFTContextRegExp) 
    {
      perror("**** SxmlFindContest, error options -r and -s are exclusive\n");
      exit (EXIT_FAILURE);
    }

  if (SFTmainOption==0) 
    {
      perror("**** SxmlFindText, error one option -D -r or -s is mandatory\n");
      exit (EXIT_FAILURE);
    }
  
  while ((document=SxmlInputNextDocumentElement()))
    {
      SFTstackPath=SxmlNodeListCreate();
      SxmlNodeListAppend(SFTstackPath, document);
      SFTfindAndPrint(SxmlFirstChild(document));
      SxmlFree (SFTstackPath);
    }
  exit(EXIT_SUCCESS);
}
