/*   -*- coding: utf-8 -*-  */
/**********************************************************************
*
*  module   : SxmlNode
*  fichier  : SxmlCumul.c
* Auteur   : Jacques DUCLOY
*  Date     : 2013
*
***********************************************************************/

#include <stdio.h>
#include "SxmlNode.h"
#include "Buffer.h"
#include <getopt.h>

int getopt();
extern char *optarg;

Buffer *bufInput;
Buffer *bufKey;
SxmlNode *currentGroup;
SxmlNode *currentList;
char *currentPos;
char *iTag;
int noTagI;
int charTab;
int wMode;
int iW;
double dW;
char *strW;
static char  strFreq[10];

char *getInput()
{
  char *posTab;
  if (BufferGets(bufInput))
    {
      if (wMode)
	{
	  posTab=strrchr(BufferString(bufInput), charTab);
	  if (!posTab) {perror("tab mandatory"); exit (EXIT_FAILURE);}
	  strcpy(strW, posTab+1);
	  BufferTailCut(bufInput, strlen(strW)+1);
	}
      return BufferString(bufInput);
    }
  else return NULL;
}

SxmlNode *createItem(char *k)
{
  SxmlNode *itemNode;
  itemNode=SxmlElementCreate(iTag);
  SxmlAppendChild(itemNode, SxmlLeafCreate("k", k));
  SxmlAppendChild(itemNode, SxmlLeafCreate("n", "1"));
  if (wMode) SxmlAppendChild(itemNode, SxmlLeafCreate("w", strW));
  return itemNode;
}

SxmlNode *incrementItem(SxmlNode *itemNode)
{
  int iN;
  int iW;
  double dW;
  SxmlNode *nodeN;
  SxmlNode *nodeW;
  nodeN=SxmlGetFirstChildByTagName(itemNode, "n");
  nodeW=SxmlGetFirstChildByTagName(itemNode, "w");
  iN=atoi(SxmlLeafText(nodeN));
  iN++;
  sprintf(strFreq, "%d", iN);
  SxmlLeafSetText(nodeN, strFreq);
  switch(wMode)
    {
    case 0:
      break;
    case 'i':
      iW=atoi(SxmlLeafText(nodeW));
      iW+=atoi(strW);
      sprintf(strFreq, "%d", iW);
      SxmlLeafSetText(nodeW, strFreq);
      break;
    case 'd':
      dW=strtod(SxmlLeafText(nodeW),NULL);
      dW+=strtod(strW, NULL);
      sprintf(strFreq, "%08.3f", dW);
      SxmlLeafSetText(nodeW, strFreq);
      break;
    }
  return itemNode;
}

void createGroupRecord()
{
  char *posTab;
  char *posTab1;
  SxmlNode *n1;
  SxmlNode *n2;

  if (!(posTab=strchr(BufferString(bufInput),charTab))) 
    {
      currentGroup=createItem(BufferString(bufInput));
      return;
    }
  currentGroup=NULL;
  posTab=BufferString(bufInput);
  while ((posTab1=strchr(posTab,charTab)))
    {
      if(!currentGroup)
	{
	  currentGroup=SxmlElementCreate("g");
	  n1=currentGroup;
	  BufferStrncpy(bufKey, BufferString(bufInput), posTab1-BufferString(bufInput));
	}
      else
	{
	   SxmlAppendChild(n1,n2=SxmlElementCreate("g"));
	   n1=n2;
	}
      posTab1[0]='\0';
      SxmlAddFirstChild(n1, SxmlLeafCreate("k",posTab));
      SxmlAppendChild(n1,n2=SxmlElementCreate("l"));
      posTab=posTab1+1; 
      n1=n2;
    }
  SxmlAppendChild(n1,createItem(posTab));
}

int testNewRecord()
{
  char *posTab;
  posTab=strchr(BufferString(bufInput),charTab);
  if (SxmlNodeHasName(currentGroup,iTag))
    {
      if (posTab) return 1;
      if (strcmp(BufferString(bufInput), SxmlLeafText(SxmlGetFirstChildByTagName(currentGroup,"k")))==0) 
	{
	  currentPos=BufferString(bufInput);
	  currentList=currentGroup;
	  return 0;
	}
      return 1;
    }
  if (!posTab) return 1;
  if (strncmp(BufferString(bufKey), BufferString(bufInput), 
	      posTab-BufferString(bufInput))!=0) return 1;
  currentPos=posTab+1;
  currentList=SxmlGetFirstChildByTagName(currentGroup,"l");
  return 0;
}

void insertNewTree(SxmlNode *list, char *pos)
{
  char *newPos;
  char *posTab;
  SxmlNode *newGroup;
  SxmlNode *newList;

  if(!(posTab=strchr(pos,charTab)))
    {  /*  insertion de l'élément terminal */
      SxmlAppendChild (list, SxmlLeafCreate(iTag,pos));
      return;
    }
  newPos=posTab+1;
  posTab[0]='\0';
  SxmlAppendChild(list,newGroup=SxmlElementCreate("g"));
  SxmlAppendChild(newGroup, SxmlLeafCreate("k",pos));
  SxmlAppendChild(newGroup, newList=SxmlElementCreate("l"));
  insertNewTree(newList, newPos);
  return;
}

SxmlNode *insertTree(SxmlNode *list, char *pos)
{
  char *posTab;
  SxmlNode *lastChild;
  SxmlNode *newList;
  char *newPos;
  char *kOld;

  posTab=strchr(pos,charTab);
  if (SxmlNodeHasName(list,iTag)) /* terminal */
    {
      if (!posTab)
	{
	  if (strcmp(pos,SxmlLeafText(SxmlGetFirstChildByTagName(list,"k")))==0)
	    {
	      incrementItem(list);
	      return list;
	    }
	}
    }
  if(!posTab)
    {  /*  insertion d'un élément */
      SxmlAppendChild (list, SxmlLeafCreate(iTag,pos));
      return list;
    }
  lastChild=SxmlLastChild(list);
  if (SxmlNodeHasName(lastChild,iTag))
    { /* groupe après un élement */
      insertNewTree(list,pos);
      return list;
    }
 
  kOld=SxmlLeafText(SxmlGetFirstChildByTagName(lastChild,"k"));
  posTab[0]='\0';
  if (strcmp(pos,kOld)==0)
    { /* même clé */
      newList=SxmlGetFirstChildByTagName(lastChild,"l");
      newPos=posTab+1;
      insertTree(newList, newPos);
      return list;
    }
   posTab[0]=charTab;
   insertNewTree(list,pos);
   return list;
}



int replaceElem (SxmlNode *currentGroup)
{
  SxmlNode *listGroup;
  if (!SxmlIsElement(currentGroup)) return 0;
  if (SxmlNodeHasName(currentGroup,iTag)) 
    {
      SxmlNode *newElem;
      newElem=SxmlFirstChild(currentGroup);
      SxmlRemoveChild(newElem);
      SxmlReplaceChild(currentGroup, newElem);
      SxmlFree(currentGroup);
      return 1;
    }
  if ((listGroup=SxmlGetFirstChildByTagName(currentGroup,"l")))
    {
      SxmlNode *gOrE;
      gOrE=SxmlFirstChild(listGroup);
      while (gOrE)
	{
	  SxmlNode *nextGorE;
	  nextGorE=SxmlNextSibling(gOrE);
	  replaceElem (gOrE);
	  gOrE=nextGorE;
	}
    }
  return 1;
}

int computeWI(SxmlNode *currentGroup)
{
  SxmlNode *listGroup;
  int sum;
  sum=0;
  if (SxmlNodeHasName(currentGroup,iTag)) return atoi(SxmlLeafText(SxmlGetFirstChildByTagName(currentGroup,"w")));
  if ((listGroup=SxmlGetFirstChildByTagName(currentGroup,"l")))
    {
      SxmlNode *gOrE;
      SxmlReset(listGroup);
      while ((gOrE=SxmlNextNode(listGroup)))
	{
	  sum+=computeWI(gOrE);
	}
      sprintf(strFreq, "%d", sum);
      SxmlAppendChild(currentGroup, SxmlLeafCreate("w", strFreq));
    }
  return sum;
}

double computeWD(SxmlNode *currentGroup)
{
  SxmlNode *listGroup;
  double sum;
  sum=0;
  if (SxmlNodeHasName(currentGroup,iTag)) return strtod(SxmlLeafText(SxmlGetFirstChildByTagName(currentGroup,"w")), NULL);
  if ((listGroup=SxmlGetFirstChildByTagName(currentGroup,"l")))
    {
      SxmlNode *gOrE;
      SxmlReset(listGroup);
      while ((gOrE=SxmlNextNode(listGroup)))
	{
	  sum+=computeWD(gOrE);
	}
      sprintf(strFreq, "%08.3f", sum);
      SxmlAppendChild(currentGroup, SxmlLeafCreate("w", strFreq));
    }
  return sum;
}


int computeN(SxmlNode *currentGroup)
{
  SxmlNode *listGroup;
  int sum;
  sum=0;
  if (SxmlNodeHasName(currentGroup,iTag)) return atoi(SxmlLeafText(SxmlGetFirstChildByTagName(currentGroup,"n")));
  if ((listGroup=SxmlGetFirstChildByTagName(currentGroup,"l")))
    {
      SxmlNode *gOrE;
      SxmlReset(listGroup);
      while ((gOrE=SxmlNextNode(listGroup)))
	{
	  sum+=computeN(gOrE);
	}
      sprintf(strFreq, "%d", sum);
      SxmlAppendChild(currentGroup, SxmlLeafCreate("n", strFreq));
    }
  return sum;
}

int compute(SxmlNode *currentGroup)
{
  SxmlNode *listGroup;
  if (!SxmlIsElement(currentGroup)) return 0;
  if (SxmlNodeHasName(currentGroup,iTag)) return 1;
  computeN(currentGroup);
  switch(wMode)
    {
    case 0:
      return 1;
    case 'i':
      computeWI(currentGroup);
      return 1;
    case 'd':
      computeWD(currentGroup);
      return 1;
    }
  /*
  if ((listGroup=SxmlGetFirstChildByTagName(currentGroup,"l")))
    {
      SxmlNode *gOrE;
      int f;
      int t;
      f=0;
      t=0;
      while ((gOrE=SxmlNextNode(listGroup)))
	{
	  f++;
	  t+=computeFreqCount(gOrE);
	}
      sprintf(strFreq, "%d", f);
      SxmlAppendChild(currentGroup, SxmlLeafCreate("n", strFreq));
      sprintf(strFreq, "%d", t);
      SxmlAppendChild(currentGroup, SxmlLeafCreate("t", strFreq));
      return t;
    }
  */
  return 0;
}

void printGroup()
{
  printf("%s\n", SxmlToString(currentGroup));
}

int main (int argc, char **argv)
{
  int cOption;
  
  noTagI=0;
  iTag="i";
  charTab='\t';
  wMode=0;
  strW=malloc(100);

  while((cOption=getopt(argc,argv,"i:t:w:"))!=EOF)
    {
      switch (cOption)
	{
	case 'i':
	  iTag=optarg;
	  break;
	case 't':
	  charTab=optarg[0];
	  break;
	case 'w':
	  wMode=optarg[0];
	  break;
	}
    }

  bufInput=BufferCreate(100,100);
  bufKey=BufferCreate(100,100);


  if (getInput()) createGroupRecord();
  while  (getInput())
    {
      if (testNewRecord())
	{
	  compute(currentGroup);
	  printGroup();
	  SxmlFree(currentGroup);
	  createGroupRecord();
	  continue;
	}
      insertTree(currentList,currentPos);
    }
  compute(currentGroup);
  printGroup();
  exit(EXIT_SUCCESS);
}
