/**********************************************************************
*
*  projet   : Infometrics
*  module   : Histo
*  commande : Histo.c
*  fichier  : Histo.c
*  Auteur   : Jacques DUCLOY
*  Date     : Juillet 97
*  $Id: Histo.c,v 1.2 2005/06/22 15:42:00 parmentf Exp $
*
***********************************************************************
*
* Copyleft Université de  Lorraine
* 
***********************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include "Histo.h"
#include "Except.h"

Histo *HistoCreate(int n, int m1)
{
  if (n>0)
    {
      Histo *h1;
      if(!(h1=(Histo *)malloc(sizeof(Histo))))
	{
	  ExceptSetError("Histo","MA","Memory allocation failed","","",2);
	  exit(2);
	}

      h1->maxElem=n;
      h1->nElem=0;
      h1->mode=m1;
      switch(m1)
	{
	case 'i':
	  if(!(h1->tabInt=(int*)malloc ( n*sizeof(int))))
	    {
	      ExceptSetError("Histo","MA","Memory allocation failed","","",2);
	      exit(2);
	    }
	  break;
	case 'f':
	  if(!(h1->tabFloat=(float*)malloc ( n*sizeof(float))))
	    {
	      ExceptSetError("Histo","MA","Memory allocation failed","","",2);
	      exit(2);
	    }
	  break;
	}
      
      if(!(h1->tabNode=(SgmlNode**)malloc ( n*sizeof(SgmlNode *))))
	{
	  ExceptSetError("Histo","MA","Memory allocation failed","","",2);
	  exit(2);
	}
      h1->cut=0;
      h1->freeMode=0;
      return h1;
    }
  return NULL;
}

Histo* HistoSetCut (Histo *h1, int c)
{
  h1->cut=c;
  return h1;
}

Histo* HistoFloatSetCut (Histo *h1, float f1)
{
  h1->cutFloat=f1;
  return h1;
}

Histo* HistoSetFreeMode (Histo *h1, int c)
{
  h1->freeMode=c;
  return h1;
}

Histo *HistoInsertTail(Histo *h1, SgmlNode *s1, int i1)
{
  h1->tabInt[h1->nElem]=i1;
  h1->tabNode[h1->nElem]=s1;
  h1->nElem++;
  return h1;
}

Histo *HistoFloatInsertTail(Histo *h1, SgmlNode *s1, float f1)
{
  h1->tabFloat[h1->nElem]=f1;
  h1->tabNode[h1->nElem]=s1;
  h1->nElem++;
  return h1;
}


Histo* HistoInsertAndShift(Histo *h1, SgmlNode *s1, int i1)
{
  int j;
  j=h1->nElem-1;
  while(j)
    {
      h1->tabInt[j+1]=h1->tabInt[j];
      h1->tabNode[j+1]=h1->tabNode[j];
      if (i1 <= h1->tabInt[j-1])
	{
	  h1->tabInt[j]=i1;
	  h1->tabNode[j]=s1;
	  break;
	}
      j--;
    }
  if(j==0)
    {
      h1->tabInt[1]=h1->tabInt[0];
      h1->tabNode[1]=h1->tabNode[0];
      h1->tabInt[0]=i1;
      h1->tabNode[0]=s1;
    }
  h1->nElem++;
  return h1;
}


Histo* HistoFloatInsertAndShift(Histo *h1, SgmlNode *s1, float f1)
{
  int j;
  j=h1->nElem-1;
  while(j)
    {
      h1->tabFloat[j+1]=h1->tabFloat[j];
      h1->tabNode[j+1]=h1->tabNode[j];
      if (f1 <= h1->tabFloat[j-1])
	{
	  h1->tabFloat[j]=f1;
	  h1->tabNode[j]=s1;
	  break;
	}
      j--;
    }
  if(j==0)
    {
      h1->tabFloat[1]=h1->tabFloat[0];
      h1->tabNode[1]=h1->tabNode[0];
      h1->tabFloat[0]=f1;
      h1->tabNode[0]=s1;
    }
  h1->nElem++;
  return h1;
}

Histo* HistoAdd(Histo *h1, SgmlNode *s1, int i1)
{
  if (i1<= h1->cut)return h1;
  if (h1->nElem==0)return HistoInsertTail(h1,s1,i1);
  if (h1->nElem < h1->maxElem)
    {
      if (i1 <= h1->tabInt[h1->nElem-1])return HistoInsertTail(h1,s1,i1);
      return HistoInsertAndShift(h1,s1,i1);
    }
  else
    {
      if (i1 <= h1->tabInt[h1->nElem-1])return h1;
      if (h1->freeMode)SgmlFree (h1->tabNode[h1->nElem-1]);
      h1->nElem--;
      return HistoInsertAndShift(h1,s1,i1);
    }
  return h1;
}

Histo* HistoFloatAdd(Histo *h1, SgmlNode *s1, float f1)
{
  if (f1<= h1->cutFloat)return h1;
  if (h1->nElem==0)return HistoFloatInsertTail(h1,s1,f1);
  if (h1->nElem < h1->maxElem)
    {
      if (f1 <= h1->tabFloat[h1->nElem-1])return HistoFloatInsertTail(h1,s1,f1);
      return HistoFloatInsertAndShift(h1,s1,f1);
    }
  else
    {
      if (f1 <= h1->tabFloat[h1->nElem-1])return h1;
      if (h1->freeMode)SgmlFree (h1->tabNode[h1->nElem-1]);
      h1->nElem--;
      return HistoFloatInsertAndShift(h1,s1,f1);
    }
  return h1;
}


SgmlNode *HistoToSgmlAndReset(Histo *h1,
			      char *listTag,
			      char *elemTag,
			      char *freqTag,
			      char *freqFormat)
{
  SgmlNode *s1;
  SgmlNode *e1;
  int j;
  static char  strFreq[10];

  j=0;

  if(h1->nElem)
    {
      s1=SgmlCreateMark(listTag);
      while (j < h1->nElem)
	{
	  SgmlAddSon(s1, e1=SgmlCreateMark(elemTag));
	  SgmlAddSon(e1, h1->tabNode[j]);
	  if(h1->mode=='i')sprintf(strFreq,freqFormat,h1->tabInt[j]); 
	  else sprintf(strFreq,freqFormat,h1->tabFloat[j]); 
	  SgmlAddSon(e1, SgmlCreateLeaf(freqTag, strFreq));
	  j++;
	}
      h1->nElem=0;
    }
  else return NULL;
  return s1;
}
