// Copyright (C) 1999-2005 Open Source Telecom Corporation.
//  
// This program 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.
// 
// This program 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 this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// 
// As a special exception, you may use this file as part of a free software
// library without restriction.  Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License.  This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
//
// This exception applies only to the code released under the name GNU
// ccScript.  If you copy code from other releases into a copy of GNU
// ccScript, as the General Public License permits, the exception does
// not apply to the code that you add in this way.  To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own for GNU ccScript, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.
//

#include "engine.h"

using namespace std;
using namespace ost;

#ifdef	HAVE_STRCASECMP
#ifndef	stristr
#define	stristr(x, y) strcasestr(x, y)
#endif
#endif

#ifdef	WIN32
#define	stristr(x,y)	strstr(x,y)
#endif

ScriptCommand::ScriptCommand(ScriptCommand *ini) :
Keydata(), Mutex()
{
        memcpy(&keywords, &ini->keywords, sizeof(keywords));
        memcpy(&traps, &ini->traps, sizeof(traps));
        active = NULL;
        keyword_count = ini->keyword_count;
        trap_count = ini->trap_count;
        imask = ini->imask;
        dbcount = 0;
        dbc = NULL;
        tq = NULL;
	ripple = ini->ripple;
}

ScriptCommand::ScriptCommand() :
Keydata(), Mutex()
{
        imask = 0;
        unsigned i;
        memset(&keywords, 0, sizeof(keywords));
        for(i = 0; i < TRAP_BITS; ++i)
                traps[i] = "<undefined>";

	ripple = false;
        active = NULL;
        keyword_count = 0;
        trap_count = 0;
        dbcount = 0;
        dbc = NULL;
        tq = NULL;
}

const char *ScriptCommand::getExternal(const char *opt)
{
	return NULL;
}

bool ScriptCommand::isInput(Line *line)
{
	return false;
}

void ScriptCommand::errlog(const char *level, const char *msg)
{
}

bool ScriptCommand::control(char **args)
{
	ScriptBinder *module;
	ScriptImage *img;

	enter();
	module = ScriptBinder::first;
	img = active;

	while(module)
	{
		if(module->control(img, args))
			break;
		module = module->next;
	}

	leave();
	if(module)
		return true;

	return false;
}
	
Script::Method ScriptCommand::getHandler(const char *keyword)
{
        Keyword *key;
        char keybuf[33];
        int len = 0;
        char *kw = keybuf;

        while(len++ < 32 && *keyword && *keyword != '.')
                *(kw++) = (*keyword++);
        *kw = 0;
        keyword = keybuf;

        key = keywords[Script::getIndex(keyword)];

        while(key)
        {
                if(!stricmp(key->keyword, keyword))
                        return key->method;

                key = key->next;
        }
        return (Method)NULL;
}

bool ScriptCommand::isInitial(const char *keyword)
{
        Keyword *key;
        char keybuf[33];
        int len = 0;
        char *kw = keybuf;

        while(len++ < 32 && *keyword && *keyword != '.')
                *(kw++) = (*keyword++);
        *kw = 0;
        keyword = keybuf;

        key = keywords[Script::getIndex(keyword)];

        while(key)
        {
                if(!stricmp(key->keyword, keyword))
                        return key->init;

                key = key->next;
        }
	return false;
}

const char *ScriptCommand::check(char *keyword, Line *line, ScriptImage *img)
{
        Keyword *key;
        char keybuf[33];
        int len = 0;
        char *kw = keybuf;

        while(len++ < 32 && *keyword && *keyword != '.')
                *(kw++) = *(keyword++);

        *kw = 0;
        keyword = keybuf;
        key = keywords[Script::getIndex(keyword)];

        while(key)
        {
                if(!stricmp(key->keyword, keyword))
                        return check(key->check, line, img);

                key = key->next;
        }
        return "unknown command";
}

void ScriptCommand::aliasModule(const char *id, const char *use)
{
	char temp[65];

	snprintf(temp, sizeof(temp), "use.%s", id);
	setValue(temp, use);
}

unsigned long ScriptCommand::getTrapDefault(void)
{
	return 0x03;
}

unsigned long ScriptCommand::getTrapHandler(Name *scr)
{
	return getTrapDefault();
}

unsigned long ScriptCommand::getTrapModifier(const char *trapname)
{
	return getTrapMask(trapname);
}

const char *ScriptCommand::check(Check chk, Line *line, ScriptImage *img)
{
	return (this->*(chk))(line, img);
}

unsigned ScriptCommand::getTrapId(const char *trapname)
{
        unsigned i;

        for(i = 0; i < TRAP_BITS; ++i)
        {
                if(!stricmp(traps[i], trapname))
                        return i;
        }
        return 0;
}

unsigned long ScriptCommand::getTrapMask(unsigned id)
{
        return 1 << id;
}

unsigned long ScriptCommand::getTrapMask(const char *trapname)
{
        unsigned long mask = 1;
        unsigned i;

        for(i = 0; i < TRAP_BITS; ++i)
        {
                if(!stricmp(traps[i], trapname))
                        return mask;

                mask = mask << 1;
        }
        return 0;
}

void ScriptCommand::load(Script::Define *keydefs)
{
        size_t len;
        int key;
        Keyword *script;

        for(;;)
        {
                if(!keydefs->keyword)
                        break;

                len = strlen(keydefs->keyword) + 1;
                key = Script::getIndex(keydefs->keyword);
                script = (Keyword *)alloc(sizeof(Keyword) + len - 1);
                setString(script->keyword, len, keydefs->keyword);
                script->method = keydefs->method;
		script->init = keydefs->init;
                script->check = keydefs->check;
                script->next = keywords[key];
                keywords[key] = script;
                ++keydefs;
        }
}

const char *ScriptCommand::getTrapName(unsigned id)
{
	if(id < trap_count)
		return traps[id];

	return NULL;
}

int ScriptCommand::trap(const char *trapname, bool inherited)
{
        if(inherited)
                imask |= (1 << trap_count);

        traps[trap_count++] = alloc((char *)trapname);
        return trap_count;
}

bool ScriptCommand::isInherited(unsigned id)
{
        if(imask & (1 << id))
                return true;

        return false;
}

bool ScriptCommand::useMember(Line *line, const char *list)
{
	const char *cp = getMember(line);

	if(cp && !list)
		return false;

	if(!cp)
		return true;

	if(stristr(list, cp))
		return true;

	return false;
}

unsigned ScriptCommand::getCount(Line *line)
{
	unsigned idx = 0;
	unsigned count = 0;
	while(idx < line->argc)
	{
		if(*(line->args[idx++]) == '=')
			++idx;
		else
			++count;
	}
	return count;
}

bool ScriptCommand::useKeywords(Line *line, const char *list)
{
	unsigned idx = 0;
	const char *cp;

	while(idx < line->argc)
	{
		cp = line->args[idx++];
		if(*cp != '=')
			continue;

		if(!list)
			return false;

		if(!stristr(list, cp))
			return false;
		++idx;
	}
	return true;
}	

bool ScriptCommand::hasKeywords(Line *line)
{
	unsigned idx = 0;

	if(!stricmp(line->cmd, "_keydata_"))
		return true;
	
	while(idx < line->argc)
		if(*line->args[idx++] == '=')
			return true;

	return false;
}

const char *ScriptCommand::findKeyword(ScriptImage *img, Line *line, const char *keyword)
{
	unsigned idx = 0;
	const char *cp;
	char namebuf[128];

	while(idx < line->argc)
	{
		cp = line->args[idx++];
		if(*cp == '=')
		{
			if(!stricmp(++cp, keyword))
				return line->args[idx];
			++idx;
		}
	}
	if(img)
	{
		snprintf(namebuf, sizeof(namebuf), "%s.%s", img->getCurrent()->name, keyword);
		return img->getLast(namebuf);
	}
	return NULL;
}	

const char *ScriptCommand::findKeyword(Line *line, const char *keyword)
{
	unsigned idx = 0;
	const char *cp;

	while(idx < line->argc)
	{
		cp = line->args[idx++];
		if(*cp == '=')
		{
			if(!stricmp(++cp, keyword))
				return line->args[idx];
			++idx;
		}
	}
	return NULL;
}	

const char *ScriptCommand::getMember(Line *line)
{
	const char *cp = strchr(line->cmd, '.');

	if(cp)
		++cp;

	return cp;
}

const char *ScriptCommand::getOption(Line *line, unsigned *idx)
{
	const char *cp;

	for(;;)
	{
		if(*idx >= line->argc)
			return NULL;

		cp = line->args[*idx];
		++*idx;
		if(*cp == '=')
		{
			++*idx;
			continue;
		}
		else if(*cp == '{')
			return ++cp;
		else
			return cp;
	}
}


syntax highlighted by Code2HTML, v. 0.9.1