/*---------------------------------------------------------------*
 *
 * File : signa.c
 * Author : NTM
 * Created : 30/09/03
 *
 *
 * Copyright (C) Nicolas Thierry-Mieg, 2006.
 *
 *
 * This file is part of InterPool, written by 
 * Nicolas Thierry-Mieg (CNRS, France) Nicolas.Thierry-Mieg@imag.fr
 *
 * InterPool is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * InterPool is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with InterPool; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *---------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* memcpy, strcmp */

#include "types.h" /* MOT */

#include "signa.h"



/************************************************************************
 ******************* EXPORTED FUNCTIONS *********************************
 ************************************************************************/


/********************************************************************* 
   low-level primitives 
**********************************************************************/

/*!
  \brief Allocate memory for a new signature with nbPools pools,
  and initialize content with all pools being SIG_NEG.
*/
signature* allocSig(int nbPools)
{
  // allocate memory for the signature
  signature* newSig = (signature*)malloc(sizeof(signature));
  if (newSig==NULL)
    {
      fprintf(stderr,"in allocSig, no more memory for newSig\n");
      exit(1);
    }

  newSig->nbPools = nbPools ;

  // allocate memory for newSig->sig
  newSig->sig = (int*)malloc(nbPools * sizeof(int)) ;
  if (newSig->sig == NULL)
    {
      fprintf(stderr, "in allocSig, no more memory for newSig->sig\n") ;
      exit(1) ;
    }

  // initialize newSig->sig with SIG_NEG.
  /* CAVEAT: if SIG_NEG changes from the current 00 value, initialization
     must be changed (and probably become more complex/slow) */
  if (SIG_NEG != 00)
    {
      fprintf(stderr, "in allocSig, using SIG_NEG!=00 requires changing the code!\n") ;
      exit(1) ;
    }
  memset(newSig->sig, 0, nbPools*sizeof(int));

  return(newSig) ;
}


/*!
  \brief Returns the value of the pool of absolute number abspoolnum
  in the signature mySig.
*/
int getsigvalue(const signature* mySig, int abspoolnum)
{
  return(mySig->sig[abspoolnum]) ;
}


/*!
  \brief Set the signature value of pool of absolute number
  abspoolnum to value.
*/
void setsigvalue(signature* mySig, int abspoolnum, int value)
{
  mySig->sig[abspoolnum] = value ;
}


/*!
  \brief Return a copy of mySig in a freshly allocated memory area.
*/
signature* copysig(signature* mySig)
{
  int nbPools = mySig->nbPools ;
  signature* newSig = allocSig(nbPools) ;
  // copy content of mySig->sig
  memcpy(newSig->sig, mySig->sig, nbPools*sizeof(int)) ;

  return newSig ;
}


/*!
  \brief Return a new sig holding the canonical interpretation
  of myObservation, ie change SIG_WEAK to SIG_POS and SIG_FAINT
  to SIG_NEG. myObservation should be non-enriched, ie no SIG_xxCONF.
*/
signature* canonicalInterp(signature* myObservation)
{
  signature* interp = copysig(myObservation) ;
  int nbPools = interp->nbPools ;
  int i ;
  for (i=0; i<nbPools; i++)
    {
      int sigvalue = getsigvalue(interp, i) ;
      if (sigvalue==SIG_WEAK)
	setsigvalue(interp, i, SIG_POS) ;
      else if (sigvalue==SIG_FAINT)
	setsigvalue(interp, i, SIG_NEG) ;
      else if ((sigvalue!=SIG_POS) && (sigvalue != SIG_NEG))
	{
	  fprintf(stderr, 
		  "in canonicalInterp: bad sigvalue %d for pool %d\n", 
		  sigvalue, i) ;
	  exit(1) ;
	}
    }
  return(interp) ;
}


/*!
  \brief Test if sig1 and sig2 are equal. Return TRUE if they are, FALSE if not.
*/
bool equalSigs(signature* sig1, signature* sig2)
{
  int nbPools =sig1->nbPools ;
  if (sig2->nbPools != nbPools)
    return(FALSE) ;
  {
    // same number of pools, examine contents
    int poolnum ;
    for (poolnum=0; poolnum<nbPools; poolnum++)
      if (sig1->sig[poolnum] != sig2->sig[poolnum])
	return(FALSE) ;
    return(TRUE) ;
  }
}


/*!
  \brief Free all memory for mySig, ie: 
  - the sig vector,
  - the mySig area itself.
*/
void freeSig(signature* mySig)
{
  free(mySig->sig) ;
  free(mySig) ;
}



/********************************************************************* 
   setOfSigs datatype
**********************************************************************/

/*! 
  \brief create and return an empty setOfSigs.
 */
setOfSigs buildEmptySetOfSigs(void)
{
  setOfSigs newSet ;
  newSet.nbOfSigs = 0 ;
  newSet.distance = 0 ;
  newSet.allSigs = NULL ;

  return(newSet) ;
}


/*!
  \brief Add newSig to mySigs, i.e.:
  - increment nbOfSigs,
  - realloc allSigs so that it has room for an extra signature*, and
  - set this new pointer so that it holds newSig 
  (ie mySigs->allSigs[mySigs->nbOfSigs-1] = newSig). <br>
  NOTE: This function doesn't touch mySigs->distance. Set it 
  by hand yourself!
  CAVEAT: content of newSig is not copied: if you call this function do
  NOT freeSig(newSig)!
*/
void addSigToSet(setOfSigs* mySigs, signature* newSig)
{
  mySigs->nbOfSigs++ ;
  mySigs->allSigs = (signature**)realloc(mySigs->allSigs, 
					 mySigs->nbOfSigs * sizeof(signature*)) ;
  if (mySigs->allSigs == NULL)
    {
      fprintf(stderr, "in addSigToSet, no more memory for allSigs\n") ;
      exit(1) ;
    }
  mySigs->allSigs[mySigs->nbOfSigs - 1] = newSig ;
}


/*!
  Free all the memory pointed to in mySigs (ie, free 
  each sig from allSigs, then also free the allSigs space itself).
  For safety, we also set all fields from mySigs to 0, although
  mySigs should not be used after calling freeSetOfSigs.
*/
void freeSetOfSigs(setOfSigs mySigs)
{
  int nbOfSigs = mySigs.nbOfSigs ;

  // free each sig
  int i ;
  for (i= 0; i < nbOfSigs; i++)
    freeSig(mySigs.allSigs[i]) ;

  // now free the allSigs area itself
  free(mySigs.allSigs) ;

  // Finally, clear all fields so the object remains coherent.
  // This is a precaution, although the sig should obviously not be used
  // after being freed!
  mySigs.nbOfSigs = 0 ;
  mySigs.distance = 0 ;
  mySigs.allSigs = NULL ;
}


