// $Id: ID.cc,v 1.30 2003/08/31 00:38:11 vern Exp $
//
// Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
//      The Regents of the University of California.  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that: (1) source code distributions
// retain the above copyright notice and this paragraph in its entirety, (2)
// distributions including binary code include the above copyright notice and
// this paragraph in its entirety in the documentation or other materials
// provided with the distribution, and (3) all advertising materials mentioning
// features or use of this software display the following acknowledgement:
// ``This product includes software developed by the University of California,
// Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
// the University nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#include "config.h"

#include "ID.h"
#include "Expr.h"
#include "Dict.h"
#include "EventRegistry.h"
#include "Func.h"
#include "Scope.h"

ID::ID(char* arg_name, IDScope arg_scope, bool arg_is_export)
	{
	name = arg_name;
	scope = arg_scope;
	is_export = arg_is_export;
	type = 0;
	val = 0;
	attrs = 0;
	is_const = 0;
	is_enum_const = 0;
	is_type = 0;
	offset = 0;

	SetLocationInfo(&start_location, &end_location);
	}

ID::~ID()
	{
	delete name;
	Unref(type);
	Unref(val);
	Unref(attrs);
	}

string ID::ModuleName() const
	{
	return extract_module_name(name);
	}

void ID::SetVal(Val* v)
	{
	Unref(val);
	val = v;

	if ( type && val &&
	     type->Tag() == TYPE_FUNC && type->AsFuncType()->IsEvent() )
		{
		EventHandler* handler = event_registry->Lookup(name);
		if ( ! handler )
			{
			handler = new EventHandler(name);
			handler->SetLocalHandler(val->AsFunc());
			event_registry->Register(handler);
			}
		else
			{
			// Otherwise, internally defined events cannot
			// have local handler.
			handler->SetLocalHandler(val->AsFunc());
			}
		}
	}

void ID::SetVal(Val* v, init_class c)
	{
	if ( c == INIT_NONE || c == INIT_FULL )
		{
		SetVal(v);
		return;
		}

	if ( type->Tag() != TYPE_TABLE &&
	     (type->Tag() != TYPE_PATTERN || c == INIT_REMOVE) )
		{
		if ( c == INIT_EXTRA )
			Error("+= initializer only applies to tables, sets and patterns", v);
		else
			Error("-= initializer only applies to tables and sets", v);
		}

	else
		{
		if ( c == INIT_EXTRA )
			{
			if ( ! val )
				SetVal(v);
			else
				v->AddTo(val, 0);
			}
		else
			{
			if ( val )
				v->RemoveFrom(val);
			}
		}

	Unref(v);
	}

void ID::SetVal(Expr* ev, init_class c)
	{
	Attr* a = attrs->FindAttr(c == INIT_EXTRA ?
					ATTR_ADD_FUNC : ATTR_DEL_FUNC);

	if ( ! a )
		Internal("no add/delete function in ID::SetVal");

	EvalFunc(a->AttrExpr(), ev);
	}

void ID::SetAttrs(Attributes* a)
	{
	Unref(attrs);
	attrs = a;

	if ( val && val->Type()->Tag() == TYPE_TABLE )
		val->AsTableVal()->SetAttrs(attrs);
	}

void ID::AddAttrs(Attributes* a)
	{
	if ( ! a )
		return;

	if ( attrs )
		attrs->AddAttrs(a);
	else
		attrs = a;

	if ( val && val->Type()->Tag() == TYPE_TABLE )
		val->AsTableVal()->SetAttrs(attrs);

	}

void ID::EvalFunc(Expr* ef, Expr* ev)
	{
	Expr* arg1 = new ConstExpr(val->Ref());
	ListExpr* args = new ListExpr();
	args->Append(arg1);
	args->Append(ev->Ref());

	CallExpr* ce = new CallExpr(ef->Ref(), args);

	SetVal(ce->Eval(0));
	Unref(ce);
	}

void ID::Error(const char* msg, const BroObj* o2)
	{
	BroObj::Error(msg, o2, 1);
	SetType(error_type());
	}

void ID::Describe(ODesc* d) const
	{
	d->Add(name);
	}
