#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <sys/types.h>
#include <cctype>
#include "merc.h"
//#include "tables.h"
//#include "lookup.h"


/*Imported*/
char *prog_is_cooling (PROG_LIST *);

/*
 * ---------------------------------------------------------------------
 * Trigger handlers. These are called from various parts of the code
 * when an event is triggered.
 * ---------------------------------------------------------------------
 */

/*
 * A general purpose string trigger. Matches argument to a string trigger
 * phrase.
 */
void p_act_trigger(
        char *argument, CHAR_DATA *mob, OBJ_DATA *obj,
        ROOM_INDEX_DATA *room, CHAR_DATA *ch,
        const void *arg1, const void *arg2, int type )
{
    PROG_LIST *prg;
    char *msg;

    if ( (mob && obj) || (mob && room) || (obj && room) )
    {
        bug( "Multiple program types in ACT trigger.", 0 );
        return;
    }

    if ( mob )
    {
        for ( prg = mob->pIndexData->mprogs; prg != NULL; prg = prg->next )
        {
            if ( prg->trig_type == type
                    &&  stristr(prg->trig_phrase, argument) != NULL)
            {
                if ((msg = prog_is_cooling(prg)) != NULL)
                    ch_printf(ch, "%s\n\r", msg);
                else
                    program_flow( prg->vnum, prg->code, mob, NULL, NULL, ch, arg1, arg2, 1 );                
                break;
            }
        }
    }
    else if ( obj )
    {
        for ( prg = obj->pIndexData->oprogs; prg != NULL; prg = prg->next )
        {
            if ( prg->trig_type == type
                    &&  stristr(prg->trig_phrase, argument) != NULL)
            {
                if ((msg = prog_is_cooling(prg)) != NULL)
                    ch_printf(ch, "%s\n\r", msg);
                else
                    program_flow( prg->vnum, prg->code, NULL, obj, NULL, ch, arg1, arg2, 1 );
                break;
            }
        }
    }
    else if ( room )
    {
        for ( prg = room->rprogs; prg != NULL; prg = prg->next )
        {
            if ( prg->trig_type == type
                    &&  stristr(prg->trig_phrase, argument) != NULL)
            {
                if ((msg = prog_is_cooling(prg)) != NULL)
                    ch_printf(ch, "%s\n\r", msg);
                else
                    program_flow( prg->vnum, prg->code, NULL, NULL, room, ch, arg1, arg2, 1 );
                break;
            }
        }
    }
    else
        bug( "ACT trigger with no program type.", 0 );

    return;
}

/*
 * A general purpose percentage trigger. Checks if a random percentage
 * number is less than trigger phrase
 */
bool p_percent_trigger( CHAR_DATA *mob, OBJ_DATA *obj, ROOM_INDEX_DATA *room,
        CHAR_DATA *ch, const void *arg1, const void *arg2, int type )
{
    PROG_LIST *prg;
    char *msg;
    if ( (mob && obj) || (mob && room) || (obj && room) )
    {
        bug( "Multiple program types in PERCENT trigger.", 0 );
        return ( FALSE );
    }

    if ( mob )
    {
        for ( prg = mob->pIndexData->mprogs; prg != NULL; prg = prg->next )
        {
            if ( prg->trig_type == type
                    &&  number_percent() < atoi( prg->trig_phrase ))
            {
                if ((msg = prog_is_cooling(prg)) != NULL)
                    ch_printf(ch, "%s\n\r", msg);
                else
                    program_flow( prg->vnum, prg->code, mob, NULL, NULL, ch, arg1, arg2, 1 );
                return ( TRUE );
            }
        }
    }
    else if ( obj )
    {
        for ( prg = obj->pIndexData->oprogs; prg != NULL; prg = prg->next )
        {
            if ( prg->trig_type == type
                    && number_percent() < atoi( prg->trig_phrase ))
            {
                if ((msg = prog_is_cooling(prg)) != NULL)
                    ch_printf(ch, "%s\n\r", msg);
                else
                    program_flow( prg->vnum, prg->code, NULL, obj, NULL, ch, arg1, arg2, 1 );
                return ( TRUE );
            }
        }
    }
    else if ( room )
    {
        for ( prg = room->rprogs; prg != NULL; prg = prg->next )
        {
            if ( prg->trig_type == type
                    && number_percent() < atoi( prg->trig_phrase ))
            {
                if ((msg = prog_is_cooling(prg)) != NULL)
                    ch_printf(ch, "%s\n\r", msg);
                else
                    program_flow( prg->vnum, prg->code, NULL, NULL, room, ch, arg1, arg2, 1 );
                return ( TRUE );
            }
        }
    }
    else
        bug( "PERCENT trigger missing program type.", 0 );

    return ( FALSE );
}

void p_bribe_trigger( CHAR_DATA *mob, CHAR_DATA *ch, int amount )
{
    PROG_LIST *prg;
    char *msg;

    for ( prg = mob->pIndexData->mprogs; prg; prg = prg->next )
    {
        if ( prg->trig_type == TRIG_BRIBE
                &&   amount >= atoi( prg->trig_phrase ))
        {
            if ((msg = prog_is_cooling(prg)) != NULL)
                ch_printf(ch, "%s\n\r", msg);
            else
                program_flow( prg->vnum, prg->code, mob, NULL, NULL, ch, NULL, NULL, 1 );
            break;
        }
    }
    return;
}

bool p_exit_trigger( CHAR_DATA *ch, int dir, int type )
{
    CHAR_DATA *mob;
    OBJ_DATA *obj;
    ROOM_INDEX_DATA *room;
    PROG_LIST   *prg;
    char *msg;

    if ( type == PRG_MPROG )
    {
        for ( mob = ch->in_room->people; mob != NULL; mob = mob->next_in_room )
        {
            if ( IS_NPC( mob )
                    &&   ( HAS_TRIGGER_MOB(mob, TRIG_EXIT) || HAS_TRIGGER_MOB(mob, TRIG_EXALL) ) )
            {
                for ( prg = mob->pIndexData->mprogs; prg; prg = prg->next )
                {
                    /*
                     * Exit trigger works only if the mobile is not busy
                     * (fighting etc.). If you want to be sure all players
                     * are caught, use ExAll trigger
                     */
                    if ( prg->trig_type == TRIG_EXIT
                            &&  dir == atoi( prg->trig_phrase )
                            &&  mob->position == mob->pIndexData->default_pos
                            &&  can_see( mob, ch ))
                    {
                        if ((msg = prog_is_cooling(prg)) != NULL)
                            ch_printf(ch, "%s\n\r", msg);
                        else
                            program_flow( prg->vnum, prg->code, mob, NULL, NULL, ch, NULL, NULL, 1 );
                        return TRUE;
                    }
                    else
                        if ( prg->trig_type == TRIG_EXALL
                                &&   dir == atoi( prg->trig_phrase ) )
                        {
                            if ((msg = prog_is_cooling(prg)) != NULL)
                                ch_printf(ch, "%s\n\r", msg);
                            else
                                program_flow( prg->vnum, prg->code, mob, NULL, NULL, ch, NULL, NULL, 1 );
                            return TRUE;
                        }
                }
            }
        }
    }
    else if ( type == PRG_OPROG )
    {
        for ( obj = ch->in_room->contents; obj != NULL; obj = obj->next_content )
        {
            if ( HAS_TRIGGER_OBJ( obj, TRIG_EXALL ) )
            {
                for ( prg = obj->pIndexData->oprogs; prg; prg = prg->next )
                {
                    if ( prg->trig_type == TRIG_EXALL
                            && dir == atoi( prg->trig_phrase ))
                    {
                        if ((msg = prog_is_cooling(prg)) != NULL)
                            ch_printf(ch, "%s\n\r", msg);
                        else
                            program_flow( prg->vnum, prg->code, NULL, obj, NULL, ch, NULL, NULL, 1 );
                        return TRUE;
                    }
                }
            }
        }

        for ( mob = ch->in_room->people; mob; mob = mob->next_in_room )
        {
            for ( obj = mob->carrying; obj; obj = obj->next_content )
            {
                if ( HAS_TRIGGER_OBJ( obj, TRIG_EXALL ) )
                {
                    for ( prg = obj->pIndexData->oprogs; prg; prg = prg->next )
                    {
                        if ( prg->trig_type == TRIG_EXALL
                                && dir == atoi( prg->trig_phrase ))
                        {
                            if ((msg = prog_is_cooling(prg)) != NULL)
                                ch_printf(ch, "%s\n\r", msg);
                            else
                                program_flow( prg->vnum, prg->code, NULL, obj, NULL, ch, NULL, NULL, 1 );
                            return TRUE;
                        }
                    }
                }
            }
        }
    }
    else if ( type == PRG_RPROG )
    {
        room = ch->in_room;

        if ( HAS_TRIGGER_ROOM( room, TRIG_EXALL ) )
        {
            for ( prg = room->rprogs; prg; prg = prg->next )
            {
                if ( prg->trig_type == TRIG_EXALL
                        && dir == atoi( prg->trig_phrase ))
                {
                    if ((msg = prog_is_cooling(prg)) != NULL)
                        ch_printf(ch, "%s\n\r", msg);
                    else
                        program_flow( prg->vnum, prg->code, NULL, NULL, room, ch, NULL, NULL, 1 );
                    return TRUE;
                }
            }
        }
    }

    return FALSE;
}

void p_give_trigger( CHAR_DATA *mob, OBJ_DATA *obj, ROOM_INDEX_DATA *room,
        CHAR_DATA *ch, OBJ_DATA *dropped, int type )
{

    char        buf[MAX_INPUT_LENGTH], *p;
    PROG_LIST  *prg;
    char *msg;

    if ( (mob && obj) || (mob && room) || (obj && room) )
    {
        bug( "Multiple program types in GIVE trigger.", 0 );
        return;
    }

    if ( mob )
    {
        for ( prg = mob->pIndexData->mprogs; prg; prg = prg->next )
            if ( prg->trig_type == TRIG_GIVE)
            {
                if ((msg = prog_is_cooling(prg)) != NULL)
                    ch_printf(ch, "%s\n\r", msg);
                else
                {
                    p = prg->trig_phrase;
                    /*
                     * Vnum argument
                     */
                    if ( is_number( p ) )
                    {
                        if ( dropped->pIndexData->vnum == atoi(p) )
                        {
                            program_flow(prg->vnum, prg->code, mob, NULL, NULL, ch, (void *) dropped, NULL, 1);
                            return;
                        }
                    }
                    /*
                     * Dropped object name argument, e.g. 'sword'
                     */
                    else
                    {
                        while( *p )
                        {
                            p = one_argument( p, buf );
    
                            if ( is_name( buf, dropped->name )
                                    ||   !str_cmp( "all", buf ) )
                            {
                                program_flow(prg->vnum, prg->code, mob, NULL, NULL, ch, (void *) dropped, NULL, 1);
                                return;
                            }
                        }
                    }
                }
            }
    }
    else if ( obj )
    {
        for ( prg = obj->pIndexData->oprogs; prg; prg = prg->next )
            if ( prg->trig_type == type)
            {
                if ((msg = prog_is_cooling(prg)) != NULL)
                    ch_printf(ch, "%s\n\r", msg);
                else
                    program_flow( prg->vnum, prg->code, NULL, obj, NULL, ch, (void *) obj, NULL, 1 );
                return;
            }
    }
    else if ( room )
    {
        for ( prg = room->rprogs; prg; prg = prg->next )
            if ( prg->trig_type == type)
            {
                if ((msg = prog_is_cooling(prg)) != NULL)
                    ch_printf(ch, "%s\n\r", msg);
                else
                {
                    p = prg->trig_phrase;
                    /*
                     * Vnum argument
                     */
                    if ( is_number( p ) )
                    {
                        if ( dropped->pIndexData->vnum == atoi(p) )
                        {
                            program_flow( prg->vnum, prg->code, NULL, NULL, room, ch, (void *) dropped, NULL, 1 );
                            return;
                        }
                    }
                    /*
                     * Dropped object name argument, e.g. 'sword'
                     */
                    else
                    {
                        while( *p )
                        {
                            p = one_argument( p, buf );
    
                            if ( is_name( buf, dropped->name )
                                    || !str_cmp( "all", buf ) )
                            {
                                program_flow( prg->vnum, prg->code, NULL, NULL, room, ch, (void *) dropped, NULL, 1 );
                                return;
                            }
                        }
                    }
                }
            }
    }
}

void p_greet_trigger( CHAR_DATA *ch, int type )
{
    CHAR_DATA *mob;
    OBJ_DATA *obj;
    ROOM_INDEX_DATA *room;

    if ( type == PRG_MPROG )
    {
        for ( mob = ch->in_room->people; mob != NULL; mob = mob->next_in_room )
        {
            if ( IS_NPC( mob )
                    && ( HAS_TRIGGER_MOB(mob, TRIG_GREET) || HAS_TRIGGER_MOB(mob,TRIG_GRALL) ) )
            {
                /*
                 * Greet trigger works only if the mobile is not busy
                 * (fighting etc.). If you want to catch all players, use
                 * GrAll trigger
                 */
                if ( HAS_TRIGGER_MOB( mob,TRIG_GREET )
                        &&   mob->position == mob->pIndexData->default_pos
                        &&   can_see( mob, ch ) )
                    p_percent_trigger( mob, NULL, NULL, ch, NULL, NULL, TRIG_GREET );
                else
                    if ( HAS_TRIGGER_MOB( mob, TRIG_GRALL ) )
                        p_percent_trigger( mob, NULL, NULL, ch, NULL, NULL, TRIG_GRALL );
            }
        }
    }
    else if ( type == PRG_OPROG )
    {
        for ( obj = ch->in_room->contents; obj != NULL; obj = obj->next_content )
        {
            if ( HAS_TRIGGER_OBJ( obj, TRIG_GRALL ) )
            {
                p_percent_trigger( NULL, obj, NULL, ch, NULL, NULL, TRIG_GRALL );
                return;
            }
        }

        for ( mob = ch->in_room->people; mob; mob = mob->next_in_room )
        {
            for ( obj = mob->carrying; obj; obj = obj->next_content )
            {
                if ( HAS_TRIGGER_OBJ( obj, TRIG_GRALL ) )
                {
                    p_percent_trigger( NULL, obj, NULL, ch, NULL, NULL, TRIG_GRALL );
                    return;
                }
            }
        }
    }
    else if ( type == PRG_RPROG )
    {
        room = ch->in_room;

        if ( HAS_TRIGGER_ROOM( room, TRIG_GRALL ) )
            p_percent_trigger( NULL, NULL, room, ch, NULL, NULL, TRIG_GRALL );
    }

    return;
}

void p_hprct_trigger( CHAR_DATA *mob, CHAR_DATA *ch )
{
    PROG_LIST *prg;

    for ( prg = mob->pIndexData->mprogs; prg != NULL; prg = prg->next )
        if ( ( prg->trig_type == TRIG_HPCNT )
                && ( (100 * mob->hit / mob->max_hit) < atoi( prg->trig_phrase ) ) 
                && !prog_is_cooling(prg))
        {
            program_flow( prg->vnum, prg->code, mob, NULL, NULL, ch, NULL, NULL, 1 );
            break;
        }
}

bool p_input_trigger(
        CHAR_DATA *ch, char *argument, CHAR_DATA *mob, OBJ_DATA *obj,
        ROOM_INDEX_DATA *room, int type)
{

    PROG_LIST *prg;
    char *msg = NULL;

    if (mob)
    {
        for (prg = mob->pIndexData->mprogs; prg != NULL; prg = prg->next)
        {
            if ((prg->trig_type == TRIG_INPUT) && (!str_cmp(argument, prg->trig_phrase)))
            {
                if ((msg = prog_is_cooling(prg)) != NULL)
                    ch_printf(ch, "%s\n\r", msg);
                else
                    program_flow( prg->vnum, prg->code, mob, NULL, NULL, ch, NULL, NULL, 1 );
                return TRUE;
            }
        }
    }
    else if (room)
    {
        for (prg = room->rprogs; prg != NULL; prg = prg->next)
        {
            if ((prg->trig_type == TRIG_INPUT) && (!str_cmp(argument, prg->trig_phrase)))
            {
                //writelogf("mob_prog.c: 3075, room input trigger looks good");
                if ((msg = prog_is_cooling(prg)) != NULL)
                    ch_printf(ch, "%s\n\r", msg);
                else
                    program_flow( prg->vnum, prg->code, NULL, NULL, room, ch, NULL, NULL, 1 );
                return TRUE;
            }
        }
    }
    else if (obj)
    {
        for (prg = obj->pIndexData->oprogs; prg != NULL; prg = prg->next)
        {
            if ((prg->trig_type == TRIG_INPUT) && (!str_cmp(argument, prg->trig_phrase)))
            {
                //writelogf("mob_prog.c: 3089, trigger looks good");
                if ((msg = prog_is_cooling(prg)) != NULL)
                {
                    ch_printf(ch, "%s\n\r", msg);
                    //writelogf("obj cooling; ch->name: %s, message: %s", ch->name, msg);                    
                }
                else
                    program_flow( prg->vnum, prg->code, NULL, obj, NULL, ch, NULL, NULL, 1 );
                return TRUE;
            }
        }
    }

    return FALSE;

}