/********************************************************************************
 * Stat List code copyright 1999-2001                                           *
 * Markanth : markanth@spaceservices.net                                        *
 * Devil's Lament : spaceservices.net port 3778                                 *
 * Web Page : http://spaceservices.net/~markanth/                               *
 *                                                                              *
 * All I ask in return is that you give me credit on your mud somewhere         *
 * or email me if you use it.                                                   *
 ********************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined(WIN32)
#include <unistd.h>
#endif
#include "merc.h"
#include "interp.h"
#include "recycle.h"

STAT_DATA *stat_list;
long TopGameStat[MAX_GAMESTAT];

void save_statlist ( void )
{
    STAT_DATA *pstat;
    FILE *fp;
    bool found = FALSE;
    int i;

    if ( ( fp = file_open ( STAT_FILE, "w" ) ) == NULL )
    {
        perror ( STAT_FILE );
    }

    fprintf ( fp, "TOPSTATS %d ", MAX_GAMESTAT );
    for ( i = 0; i < MAX_GAMESTAT; i++ )
        fprintf ( fp, "%ld ", TopGameStat[i] );
    fprintf ( fp, "\n" );
    for ( pstat = stat_list; pstat != NULL; pstat = pstat->next )
    {
        found = TRUE;
        fprintf ( fp, "%s ", pstat->name );
        for ( i = 0; i < MAX_GAMESTAT; i++ )
            fprintf ( fp, "%ld ", pstat->gamestat[i] );
        fprintf ( fp, "\n" );
    }
    file_close ( fp );
    if ( !found )
        unlink ( STAT_FILE );
}

void load_statlist ( void )
{
    FILE *fp;
    STAT_DATA *stat_last;
    int i, maxStat = 0;

    if ( ( fp = file_open ( STAT_FILE, "r" ) ) == NULL )
        return;

    if ( !str_cmp ( fread_word ( fp ), "TOPSTATS" ) );
    {
        maxStat = fread_number ( fp );
        for ( i = 0; i < maxStat; i++ )
            TopGameStat[i] = fread_number ( fp );
    }

    stat_last = NULL;
    for ( ;; )
    {
        STAT_DATA *pstat;

        if ( feof ( fp ) )
        {
            file_close ( fp );
            return;
        }

        pstat = new_stat_data (  );
        pstat->name = str_dup ( fread_word ( fp ) );
        for ( i = 0; i < maxStat; i++ )
            pstat->gamestat[i] = fread_number ( fp );
        fread_to_eol ( fp );

        if ( stat_list == NULL )
            stat_list = pstat;
        else
            stat_last->next = pstat;
        stat_last = pstat;
    }
}

void update_statlist ( CHAR_DATA * ch, bool pdelete )
{
    STAT_DATA *prev;
    STAT_DATA *curr;
    int i;

    if ( IS_NPC ( ch ) || IS_IMMORTAL ( ch ) )
        return;

    prev = NULL;

    for ( curr = stat_list; curr != NULL; prev = curr, curr = curr->next )
    {
        if ( !str_cmp ( ch->name, curr->name ) )
        {
            if ( prev == NULL )
                stat_list = stat_list->next;
            else
                prev->next = curr->next;

            free_stat_data ( curr );
            save_statlist (  );
        }
    }
    if ( pdelete )
    {
        return;
    }

    curr = new_stat_data (  );
    curr->name = str_dup ( ch->name );
    for ( i = 0; i < MAX_GAMESTAT; i++ )
    {
        curr->gamestat[i] = ch->pcdata->gamestat[i];

        if ( curr->gamestat[i] > TopGameStat[i] )
            TopGameStat[i] = curr->gamestat[i];
    }

    curr->next = stat_list;
    stat_list = curr;
    save_statlist (  );
    return;
}

CH_CMD ( do_showstats )
{
    int option;
    char arg[MIL];

    argument = one_argument ( argument, arg );

    if ( arg[0] == '\0' )
    {
        chsend ( "      {ROPTIONS AVAILABLE:{x\n\r", ch );
        chsend ( "      {G1{x - Ranking of Player Killers (pkills)\n\r", ch );
        chsend ( "      {G2{x - Ranking of Player Deaths (pdeaths)\n\r", ch );
        chsend ( "      {G3{x - Ranking of Mob Kills (mkills)\n\r", ch );
        chsend ( "      {G4{x - Ranking of Mob Deaths (mdeaths)\n\r", ch );
        if ( IS_IMMORTAL ( ch ) )
            chsend ( "      {Gdelete <name>{x - deletes from statlist\n\r",
                     ch );
        return;
    }
    option = atoi ( arg );

    if ( !str_cmp ( arg, "delete" ) && IS_IMMORTAL ( ch ) )
    {
        STAT_DATA *prev = NULL;
        STAT_DATA *curr = NULL;
        bool found = FALSE;

        for ( curr = stat_list; curr != NULL; prev = curr, curr = curr->next )
        {
            if ( !str_cmp ( argument, curr->name ) )
            {
                if ( prev == NULL )
                    stat_list = stat_list->next;
                else
                    prev->next = curr->next;

                free_stat_data ( curr );
                save_statlist (  );
                found = TRUE;
            }
        }
        if ( !found )
            chprintf ( ch, "Error deleting %s.\n\r", argument );
    }
    else if ( option == 1 || !str_prefix ( arg, "pkills" ) )
        show_game_stats ( ch, PK_KILLS );
    else if ( option == 3 || !str_prefix ( arg, "mkills" ) )
        show_game_stats ( ch, MOB_KILLS );
    else if ( option == 2 || !str_prefix ( arg, "pdeaths" ) )
        show_game_stats ( ch, PK_DEATHS );
    else if ( option == 4 || !str_prefix ( arg, "mdeaths" ) )
        show_game_stats ( ch, MOB_DEATHS );
    else
        do_showstats ( ch, "" );

    return;
}

int compare_stats args ( ( const void *v1, const void *v2 ) );

int compare_stats ( const void *v1, const void *v2 )
{
    return *( long * ) v2 - *( long * ) v1;
}

void show_game_stats ( CHAR_DATA * ch, int type )
{
    STAT_DATA *curr;
    BUFFER *output;
    char buf[MSL];
    /* max 2000 entries? 
       old entries will be shoved to the end anyways
     */
    long top[2000];
    int count, pos, loop, dcount;
    bool found = FALSE;
    const char *stat_name[MAX_GAMESTAT] = {
        "PLAYER KILLERS",
        "MOB KILLERS",
        "PK DEATHS",
        "MOB DEATHS",
    };

    output = new_buf (  );
    count = 0;
    pos = 0;
    dcount = 0;
    sprintf ( buf, "{CRANKING OF %s{x", stat_name[type] );
    add_buf ( output, buf );
    add_buf ( output, "\n\r" );
    loop = 0;
    for ( curr = stat_list; curr != NULL; curr = curr->next )
    {
        if ( count >= 2000 )
            break;
        if ( curr->gamestat[type] > 0 )
        {
            top[count] = curr->gamestat[type];
            count++;
            found = TRUE;
        }
    }

    qsort ( top, count, sizeof ( long ), compare_stats );

    for ( loop = 0; loop < count; loop++ )
    {
        if ( loop >= 49 )
            break;

        for ( curr = stat_list; curr != NULL; curr = curr->next )
        {
            if ( curr->gamestat[type] != top[loop] )
                continue;
            if ( dcount++ >= 50 )
                break;
            sprintf ( buf, "{G%2d{w){W %-20s {w[{R%8ld{W]{x    ", dcount,
                      curr->name, top[loop] );
            add_buf ( output, buf );
            if ( ++pos % 2 == 0 )
            {
                add_buf ( output, "\n\r" );
                pos = 0;
            }
        }
    }

    if ( !found )
        add_buf ( output, "\n\rNo one found yet.\n\r" );
    else if ( pos % 2 != 0 )
        add_buf ( output, "\n\r" );
    page_to_char ( buf_string ( output ), ch );
    free_buf ( output );
    return;
}