/*************************************************************************/
/*                                                                       */
/*                  Language Technologies Institute                      */
/*                     Carnegie Mellon University                        */
/*                        Copyright (c) 1999                             */
/*                        All Rights Reserved.                           */
/*                                                                       */
/*  Permission is hereby granted, free of charge, to use and distribute  */
/*  this software and its documentation without restriction, including   */
/*  without limitation the rights to use, copy, modify, merge, publish,  */
/*  distribute, sublicense, and/or sell copies of this work, and to      */
/*  permit persons to whom this work is furnished to do so, subject to   */
/*  the following conditions:                                            */
/*   1. The code must retain the above copyright notice, this list of    */
/*      conditions and the following disclaimer.                         */
/*   2. Any modifications must be clearly marked as such.                */
/*   3. Original authors' names are not deleted.                         */
/*   4. The authors' names are not used to endorse or promote products   */
/*      derived from this software without specific prior written        */
/*      permission.                                                      */
/*                                                                       */
/*  CARNEGIE MELLON UNIVERSITY AND THE CONTRIBUTORS TO THIS WORK         */
/*  DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING      */
/*  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT   */
/*  SHALL CARNEGIE MELLON UNIVERSITY NOR THE CONTRIBUTORS BE LIABLE      */
/*  FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES    */
/*  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN   */
/*  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,          */
/*  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF       */
/*  THIS SOFTWARE.                                                       */
/*                                                                       */
/*************************************************************************/
/*             Author:  Alan W Black (awb@cs.cmu.edu)                    */
/*               Date:  December 1999                                    */
/*************************************************************************/
/*                                                                       */
/*    Feature support                                                    */
/*                                                                       */
/*************************************************************************/

#include "cst_error.h"
#include "cst_features.h"

CST_VAL_REGISTER_TYPE(features,cst_features)

static cst_featvalpair *feat_find_featpair(const cst_features *f, 
					   const char *name)
{
    cst_featvalpair *n;
    
    if (f == NULL)
	return NULL;
    else
    {
	for (n=f->head; n; n=n->next)
	    if (cst_streq(name,n->name))
		return n;
	return NULL;
    }
}

cst_features *new_features(void)
{
    cst_features *f;

    f = cst_alloc(cst_features,1);
    f->head = NULL;
    f->ctx = NULL;
    return f;
}

cst_features *new_features_local(cst_alloc_context ctx)
{
    cst_features *f;

    f = (cst_features *)cst_local_alloc(ctx, sizeof(*f));
    f->head = NULL;
    f->ctx = ctx;
    return f;
}

void delete_features(cst_features *f)
{
    cst_featvalpair *n, *np;

    if (f)
    {
	for (n=f->head; n; n=np)
	{
	    np = n->next;
	    delete_val(n->val);
	    cst_local_free(f->ctx,n);
	}
        delete_val(f->owned_strings);
	cst_local_free(f->ctx,f);
    }
}

int feat_present(const cst_features *f, const char *name)
{
    if (feat_find_featpair(f,name) != NULL)
        return 1;
    else if (f && f->linked)
        return feat_present(f->linked,name);
    else 
        return 0;
}

int feat_length(const cst_features *f)
{
    int i=0;
    cst_featvalpair *p;
    if (f)
	for (i=0,p=f->head; p; p=p->next)
	    i++;
    return i;
}

int feat_remove(cst_features *f, const char *name)
{
    cst_featvalpair *n,*p,*np;
    
    if (f == NULL)
	return FALSE; /* didn't remove it */
    else
    {
	for (p=NULL,n=f->head; n; p=n,n=np)
	{
	    np = n->next;
	    if (cst_streq(name,n->name))
	    {
		if (p == 0)
		    f->head = np;
		else
		    p->next = np;
		delete_val(n->val);
		cst_local_free(f->ctx,n);
		return TRUE;
	    }
	}
	return FALSE;
    }
}

int feat_int(const cst_features *f, const char *name)
{
    return val_int(feat_val(f,name));
}

float feat_float(const cst_features *f, const char *name)
{
    return val_float(feat_val(f,name));
}

const char *feat_string(const cst_features *f, const char *name)
{
    return val_string(feat_val(f,name));
}

const cst_val *feat_val(const cst_features *f, const char *name)
{
    cst_featvalpair *n;
    n = feat_find_featpair(f,name);

    if (n == NULL)
    {
        if (f && f->linked)
        {   /* Search the linked features too if there are any */
            /* We assume the linked features haven't been deleted, and */
            return feat_val(f->linked,name);
        }
        else
            return NULL; /* its really not there at all */
    }
    else
	return n->val;
}

int get_param_int(const cst_features *f, const char *name,int def)
{
    const cst_val *v;
    
    v = feat_val(f,name);
    if (v != NULL)
        return val_int(v);
    else
	return def;
}

float get_param_float(const cst_features *f, const char *name, float def)
{
    const cst_val *v;
    
    v = feat_val(f,name);
    if (v != NULL)
        return val_float(v);
    else
	return def;
}
const char *get_param_string(const cst_features *f, const char *name, const char *def)
{
    const cst_val *v;
    
    v = feat_val(f,name);
    if (v != NULL)
        return val_string(v);
    else
	return def;
}

const cst_val *get_param_val(const cst_features *f, const char *name, cst_val *def)
{
    const cst_val *v;
    
    v = feat_val(f,name);
    if (v != NULL)
        return v;
    else
	return def;
}

void feat_set_int(cst_features *f, const char *name, int v)
{
    feat_set(f,name,int_val(v));
}

void feat_set_float(cst_features *f, const char *name, float v)
{
    feat_set(f,name,float_val(v));
}

void feat_set_string(cst_features *f, const char *name, const char *v)
{
    feat_set(f,name,string_val(v));
}

void feat_set(cst_features *f, const char* name, const cst_val *val)
{
    cst_featvalpair *n;
    n = feat_find_featpair(f,name);

    if (val == NULL)
    {
	cst_errmsg("cst_features: trying to set a NULL val for feature \"%s\"\n",
		   name);
    }
    else if (n == NULL)
    {   /* first reference to this feature so create new fpair */
	cst_featvalpair *p;
	p = (cst_featvalpair *)cst_local_alloc(f->ctx, sizeof(*p));
	p->next = f->head;
        p->name = name;
	p->val = val_inc_refcount(val);
	f->head = p;
    }
    else
    {
	delete_val(n->val);
	n->val = val_inc_refcount(val);
    }
}

int feat_copy_into(const cst_features *from,cst_features *to)
{
    /* Copy all features in from into to */
    cst_featvalpair *p;
    int i;

    for (i=0,p=from->head; p; p=p->next,i++)
	feat_set(to,p->name,p->val);
    
    return i;
}

int feat_link_into(const cst_features *from,cst_features *to)
{
    /* Thus allows more global features to be linked, without a copy */
    /* This is used to make things thread safe(r)                    */
    to->linked = from;
    return 1;
}

const char *feat_own_string(cst_features *f,const char *n)
{
    f->owned_strings = cons_val(string_val(n),f->owned_strings);
    return val_string(val_car(f->owned_strings));
}

int cst_feat_print(cst_file fd,const cst_features *f)
{
    cst_featvalpair *p;
    
    for (p=f->head; p; p=p->next)
    {
	cst_fprintf(fd, "%s ",p->name);
	val_print(fd,p->val);
	cst_fprintf(fd,"\n");
    }

    return 0;
}
