/* The following code is based on ILAB OLC by Jason Dinkel */
/* Mobprogram code by Lordrom for Nevermore Mud */

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "tables.h"
#include "olc.h"
#include "recycle.h"
#include "interp.h"

#define MPEDIT( fun )           bool fun(CHAR_DATA *ch, char*argument)

const struct olc_cmd_type mpedit_table[] = {
/*	{	command		function	}, */

    {"commands", show_commands},
    {"create", mpedit_create},
    {"code", mpedit_code},
    {"show", mpedit_show},
    {"list", mpedit_list},
    {"?", show_help},

    {NULL, 0}
};

void unlink_mprog ( VNUM pnum )
{
    MPROG_LIST *list, *list_next;
    MOB_INDEX_DATA *pMob;
    VNUM vnum = 0;
    int nMatch = 0, count, pos = 0;

    for ( vnum = 0; nMatch < top_mob_index; vnum++ )
    {
        if ( ( pMob = get_mob_index ( vnum ) ) == NULL )
            continue;

        nMatch++;
        count = -1;
        for ( list = pMob->mprogs; list != NULL; list = list_next )
        {
            list_next = list->next;
            count++;

            if ( list->vnum != pnum )
                continue;

            if ( count == 0 )
            {
                REMOVE_BIT ( pMob->mprog_flags, pMob->mprogs->trig_type );
                list = pMob->mprogs;
                pMob->mprogs = list->next;
                free_mprog ( list );
            }
            else
            {
                while ( ( list_next = list->next ) && ( ++pos < count ) )
                    list = list_next;

                if ( list_next )
                {
                    REMOVE_BIT ( pMob->mprog_flags, list_next->trig_type );
                    list->next = list_next->next;
                    free_mprog ( list_next );
                }
            }
        }
    }
}

void mpedit ( CHAR_DATA * ch, char *argument )
{
    MPROG_CODE *pMcode;
    char arg[MAX_INPUT_LENGTH];
    char command[MAX_INPUT_LENGTH];
    int cmd;
    AREA_DATA *ad;

    smash_tilde ( argument );
    strcpy ( arg, argument );
    argument = one_argument ( argument, command );

    EDIT_MPCODE ( ch, pMcode );

    if ( pMcode )
    {
        ad = get_vnum_area ( pMcode->vnum );

        if ( ad == NULL )       /* ??? */
        {
            edit_done ( ch );
            return;
        }

        if ( !IS_BUILDER ( ch, ad ) )
        {
            chsend ( "MPEdit: Insufficient security to modify code.\n\r",
                     ch );
            edit_done ( ch );
            return;
        }
    }

    if ( command[0] == '\0' )
    {
        mpedit_show ( ch, argument );
        return;
    }

    if ( !str_cmp ( command, "done" ) )
    {
        edit_done ( ch );
        return;
    }

    for ( cmd = 0; mpedit_table[cmd].name != NULL; cmd++ )
    {
        if ( !str_prefix ( command, mpedit_table[cmd].name ) )
        {
            if ( ( *mpedit_table[cmd].olc_fun ) ( ch, argument ) && pMcode )
                if ( ( ad = get_vnum_area ( pMcode->vnum ) ) != NULL )
                    SET_BIT ( ad->area_flags, AREA_CHANGED );
            return;
        }
    }

    interpret ( ch, arg );

    return;
}

CH_CMD ( do_mpedit )
{
    MPROG_CODE *pMcode;
    char command[MAX_INPUT_LENGTH];

    argument = one_argument ( argument, command );

    if ( is_number ( command ) )
    {
        VNUM vnum = atol ( command );
        AREA_DATA *ad;

        if ( ( pMcode = get_mprog_index ( vnum ) ) == NULL )
        {
            chsend ( "MPEdit : That vnum does not exist.\n\r", ch );
            return;
        }

        ad = get_vnum_area ( vnum );

        if ( ad == NULL )
        {
            chsend ( "MPEdit : VNUM no asignado a ningun area.\n\r", ch );
            return;
        }

        if ( !IS_BUILDER ( ch, ad ) )
        {
            chsend ( "MPEdit : Insuficiente seguridad para editar area.\n\r",
                     ch );
            return;
        }

        ch->desc->pEdit = ( void * ) pMcode;
        ch->desc->editor = ED_MPCODE;

        return;
    }

    if ( !str_cmp ( command, "create" ) )
    {
        if ( argument[0] == '\0' )
        {
            chsend ( "Sintaxis : mpedit create [vnum]\n\r", ch );
            return;
        }

        mpedit_create ( ch, argument );
        return;
    }
    if ( !str_cmp ( command, "delete" ) )
    {
        if ( argument[0] == '\0' )
        {
            chsend ( "Syntax: mpedit delete [vnum]\n\r", ch );
            return;
        }
        mpedit_delete ( ch, argument );
        return;
    }

    chsend ( "Sintaxis : mpedit [vnum]\n\r", ch );
    chsend ( "           mpedit create [vnum]\n\r", ch );

    return;
}

MPEDIT ( mpedit_create )
{
    MPROG_CODE *pMcode;
    VNUM value = atol ( argument );
    AREA_DATA *ad;

    if ( IS_NULLSTR ( argument ) || value < 1 )
    {
        chsend ( "Sintaxis : mpedit create [vnum]\n\r", ch );
        return FALSE;
    }

    ad = get_vnum_area ( value );

    if ( ad == NULL )
    {
        chsend ( "MPEdit : VNUM no asignado a ningun area.\n\r", ch );
        return FALSE;
    }

    if ( !IS_BUILDER ( ch, ad ) )
    {
        chsend ( "MPEdit : Insuficiente seguridad para crear MobProgs.\n\r",
                 ch );
        return FALSE;
    }

    if ( get_mprog_index ( value ) )
    {
        chsend ( "MPEdit: Code vnum already exists.\n\r", ch );
        return FALSE;
    }

    pMcode = new_mpcode (  );
    pMcode->vnum = value;
    pMcode->next = mprog_list;
    mprog_list = pMcode;
    ch->desc->pEdit = ( void * ) pMcode;
    ch->desc->editor = ED_MPCODE;

    chsend ( "MobProgram Code Created.\n\r", ch );

    return TRUE;
}

MPEDIT ( mpedit_show )
{
    MPROG_CODE *pMcode;
    char buf[MAX_STRING_LENGTH];

    EDIT_MPCODE ( ch, pMcode );

    sprintf ( buf, "Vnum:       [%ld]\n\r" "Code:\n\r%s\n\r", pMcode->vnum,
              pMcode->code );
    chsend ( buf, ch );

    return FALSE;
}

MPEDIT ( mpedit_code )
{
    MPROG_CODE *pMcode;
    EDIT_MPCODE ( ch, pMcode );

    if ( argument[0] == '\0' )
    {
        string_append ( ch, &pMcode->code );
        return TRUE;
    }

    chsend ( "Syntax: code\n\r", ch );
    return FALSE;
}

MPEDIT ( mpedit_list )
{
    int count = 1;
    MPROG_CODE *mprg;
    char buf[MAX_STRING_LENGTH];
    BUFFER *buffer;
    bool fAll = !str_cmp ( argument, "all" );
    char blah;
    AREA_DATA *ad;

    buffer = new_buf (  );

    for ( mprg = mprog_list; mprg != NULL; mprg = mprg->next )
        if ( fAll ||
             ENTRE ( ch->in_room->area->min_vnum, mprg->vnum,
                     ch->in_room->area->max_vnum ) )
        {
            ad = get_vnum_area ( mprg->vnum );

            if ( ad == NULL )
                blah = '?';
            else if ( IS_BUILDER ( ch, ad ) )
                blah = '*';
            else
                blah = ' ';

            sprintf ( buf, "[%3d] (%c) %5ld\n\r", count, blah, mprg->vnum );
            add_buf ( buffer, buf );

            count++;
        }

    if ( count == 1 )
    {
        if ( fAll )
            add_buf ( buffer, "No existen MobPrograms.\n\r" );
        else
            add_buf ( buffer, "No existen MobPrograms en esta area.\n\r" );
    }

    page_to_char ( buf_string ( buffer ), ch );
    free_buf ( buffer );

    return FALSE;
}

MPEDIT ( mpedit_delete )
{
    MPROG_CODE *curr, *prev;
    VNUM value = atol ( argument );
    AREA_DATA *ad;

    if ( IS_NULLSTR ( argument ) || value < 1 )
    {
        chsend ( "Syntax : mpedit create [vnum]\n\r", ch );
        return FALSE;
    }

    if ( get_mprog_index ( value ) == NULL )
    {
        chsend ( "MPEdit : Mob program not found.\n\r", ch );
        return FALSE;
    }

    ad = get_vnum_area ( value );
    if ( ad == NULL )
    {
        chsend ( "MPEdit : Mob program not assigned to an area.\n\r", ch );
        return FALSE;
    }

    if ( !IS_BUILDER ( ch, ad ) )
    {
        chsend ( "MPEdit : Insufficient security to create MobProgs.\n\r",
                 ch );
        return FALSE;
    }

    unlink_mprog ( value );
    prev = NULL;
    for ( curr = mprog_list; curr != NULL; prev = curr, curr = curr->next )
    {
        if ( curr->vnum != value )
            continue;
        if ( prev == NULL )
            mprog_list = mprog_list->next;
        else
            prev->next = curr->next;

        free_mpcode ( curr );
    }
    save_area ( ad );
    chsend ( "MobProgram Code Deleted.\n\r", ch );

    return TRUE;
}