/*
 * Original code by Xkilla
 * Ported to SWR by Atrox
 * Cleaned up and modified further by Greven and Gavin of Dark Warriors
 */
#include <sys/types.h>
#include <sys/time.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <stdarg.h>
#include "mud.h"
#include "changes.h"

/*
 * Globals
 */
char * current_date   args( ( void ) );

/*
 * Local Functions
 */

int      maxChanges;
int		 immortal_changes;
#define  VERSION 0
#define  NULLSTR( str )  ( str == NULL || str[0] == '\0' )
CHANGE_DATA * changes_table;

/* Hacktastic to make sure warning doesn't show up.. thats what man pages says todo :D */
size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm) {
	return strftime(s, max, fmt, tm);
}


void load_changes(void)
{
    FILE *fp;
    int i;

    if ( !(fp = fopen( CHANGES_FILE, "r")) )
    {
        bug( "Could not open Changes File for reading.", 0 );
        return;
    }

	immortal_changes = 0;

    fscanf( fp, "%d\n", &maxChanges );

    changes_table = (CHANGE_DATA*)calloc(1, sizeof( CHANGE_DATA) * (maxChanges+1) );
    
    for( i = 0; i < maxChanges; i++ )
    {
        changes_table[i].change = fread_string( fp );
        changes_table[i].coder = fread_string( fp );
        changes_table[i].date = fread_string( fp );
        changes_table[i].mudtime = fread_number( fp );
// Add imm variables to each data so we know if it should only show up for imms
		changes_table[i].immchange = fread_number( fp );
		if ( changes_table[i].immchange == 1)
			immortal_changes++;
    }
    fclose(fp);
    log_string(" Done changes " );  
    return;
}

char * current_date( )
{
    static char buf [ 128 ];
    struct tm * datetime;

    datetime = localtime( &current_time );
    my_strftime( buf, 128, "%x", datetime );
    return buf;
}

void save_changes(void)
{
    FILE *fp;
    int i;

    if ( !(fp = fopen( CHANGES_FILE,"w")) )
    {
        perror( CHANGES_FILE );
        return;
    }

    fprintf( fp, "%d\n", maxChanges ); 

    for( i = 0; i < maxChanges; i++ )
    {
        fprintf (fp, "%s~\n", changes_table[i].change);
  		fprintf (fp, "%s~\n", changes_table[i].coder);
        fprintf (fp, "%s~\n", changes_table[i].date);
        fprintf (fp, "%ld\n", changes_table[i].mudtime );
		fprintf	(fp, "%d\n",  changes_table[i].immchange );
        fprintf( fp, "\n" );
    } 
    fclose(fp);
    return;
} 

void delete_change(int iChange)
{
    int i,j;
    CHANGE_DATA * new_table;

    new_table = (CHANGE_DATA*)CALLOC(1, sizeof( CHANGE_DATA ) * maxChanges );

    if( !new_table )
    {
       return;
    }
    
    for ( i= 0, j = 0; i < maxChanges+1; i++)
    {
        if( i != iChange )
        {
            new_table[j] = changes_table[i];
            j++;
        }
		else
		{
			if ( changes_table[i].change )
				STRFREE(changes_table[i].change);
			if ( changes_table[i].coder )
				STRFREE(changes_table[i].coder);
			if ( changes_table[i].date )
				STRFREE(changes_table[i].date);
		}
    }
    
    free( changes_table );
    changes_table = new_table;

    maxChanges--;
    
    return;
}

void do_addchange(CHAR_DATA *ch, char *argument )
{
    CHANGE_DATA * new_table;
    char buf[MAX_STRING_LENGTH];
    
    if ( IS_NPC( ch ) )
        return;
    
    if ( argument[0] == '\0' )
    {
        send_to_char( "Syntax: addchange <change>\n\r", ch );
        send_to_char( "Type 'changes' to view the list.\n\r", ch );
        return;
    }

    maxChanges++;
    new_table = (CHANGE_DATA*)realloc( changes_table, sizeof( CHANGE_DATA ) *(maxChanges+1) );

    if (!new_table) /* realloc failed */
    {
        send_to_char ("Memory allocation failed. Brace for impact.\n\r",ch);
        return;
    }

    changes_table = new_table;
    
    changes_table[maxChanges-1].change  = STRALLOC( argument );
    changes_table[maxChanges-1].coder   = STRALLOC( ch->name );
    changes_table[maxChanges-1].date    = STRALLOC(current_date());
    changes_table[maxChanges-1].mudtime = current_time;
//Auto set it to Normal Change
	changes_table[maxChanges-1].immchange = FALSE;
    
    send_to_char("Changes Created.\n\r",ch);
    send_to_char("Type 'changes' to see the changes.\n\r",ch);
    snprintf (buf, MAX_STRING_LENGTH, "%s", "A new change has been added, type 'CHANGES' to see it." );
	echo_to_all( AT_IMMORT, buf, ECHOTAR_ALL );
    save_changes();
    return;
}
/*
 * Added by greven for imm changes
 *
 */
void do_addimmchange(CHAR_DATA *ch, char *argument )
{
    CHANGE_DATA * new_table;
    
    if ( IS_NPC( ch ) )
        return;
    
    if ( argument[0] == '\0' )
    {
        send_to_char( "Syntax: addimmchange <change>\n\r", ch );
        send_to_char( "Type 'changes' to view the list.\n\r", ch );
        return;
    }

    maxChanges++;
    new_table = (CHANGE_DATA*)realloc( changes_table, sizeof( CHANGE_DATA ) *(maxChanges+1) );

    if (!new_table) /* realloc failed */
    {
        send_to_char ("Memory allocation failed. Brace for impact.\n\r",ch);
        return;
    }

    changes_table = new_table;
    
    changes_table[maxChanges-1].change  = STRALLOC( argument );
    changes_table[maxChanges-1].coder   = STRALLOC( ch->name );
    changes_table[maxChanges-1].date    = STRALLOC(current_date());
    changes_table[maxChanges-1].mudtime = current_time;
// Autoset to imm change, do NOT echo it to the mud
	changes_table[maxChanges-1].immchange = TRUE;
	immortal_changes++;    
    send_to_char("Changes Created.\n\r",ch);
    send_to_char("Type 'changes' to see the changes.\n\r",ch);
    save_changes();
    return;
}

void do_chedit( CHAR_DATA *ch, char *argument )
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
 
    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );
 
    if ( IS_NPC(ch) )
        return;
    
    if (!ch->desc || NULLSTR(arg1) )
    {
        ch_printf(ch,"Syntax: chedit load/save\n\r",ch);
        ch_printf(ch,"Syntax: chedit delete (change number)\n\r",ch);
        ch_printf(ch,"Syntax: chedit immchange (change number)\n\r",ch);
        return;
    }

    if ( !str_cmp(arg1,"load") )
    {
        load_changes( );
        send_to_char("Changes Loaded.\n\r",ch);
        return;
    }

    if ( !str_cmp(arg1,"save") )
    {
        save_changes( );
        send_to_char("Changes Saved.\n\r",ch);
        return;
    }

    if ( !str_cmp(arg1,"immchange") )
    {
        int num;
        
        if ( NULLSTR(arg2) || !is_number( arg2 ) )
        {
            send_to_char("&wFor chedit immchange, you must provide a change number.\n\r",ch);
            send_to_char("Syntax: chedit immchange (change number)\n\r",ch);
            return;
        }

        num = atoi( arg2 );
		num--;
        if ( num < 0 || num > maxChanges )
        {
            ch_printf( ch, "Valid changes are from 1 to %d.\n\r", maxChanges );
            return;
        }
	
		if ( changes_table[num].immchange == FALSE)
			changes_table[num].immchange = TRUE;
		else
			changes_table[num].immchange = FALSE;
		immortal_changes++;
        save_changes( );
        send_to_char("Change flag changed.\n\r",ch);
        return;
    }
    if ( !str_cmp(arg1, "delete"))
    {
        int num;
        
        if ( NULLSTR(arg2) || !is_number( arg2 ) )
        {
            send_to_char("#wFor chsave delete, you must provide a change number.{x\n\r",ch);
            send_to_char("Syntax: chsave delete (change number)\n\r",ch);
            return;
        }

        num = atoi( arg2 );
		num--;
        if ( num < 0 || num > maxChanges )
        {
            ch_printf( ch, "Valid changes are from 0 to %d.\n\r", maxChanges );
            return;
        }
        delete_change( num );
        save_changes( );
        send_to_char("Change deleted.\n\r",ch);
        return;
    }
    return;
}
  
// Modified by greven for immortal stuff, as well as fixing crash if there are less than 10 changes

void do_changes(CHAR_DATA *ch, char *argument)
{
	char  buf[MAX_STRING_LENGTH];
	char  arg[MAX_INPUT_LENGTH];
	char *test;
	int   today;
	int   i, immchanges=0;
	int start = 0;
	
	one_argument( argument, arg );
	
	if (IS_NPC(ch)) return;
	
	if( maxChanges < 1 )
	{
		send_to_char("&bT&zhere are currently no changes created.", ch);
		return;
	}
	
	i = 0;
	test = current_date();
	today = 0;
	
	
	for ( i = 0; i < maxChanges; i++)
		{
		if ( !IS_IMMORTAL(ch) && changes_table[i].immchange == 1)
			continue;
		if ( NULLSTR(changes_table[i].coder) || NULLSTR(changes_table[i].change) || NULLSTR(changes_table[i].date))
			continue;
		if (!str_cmp(test,changes_table[i].date) )
			today++;
		}

	if( !str_cmp(arg, "all") )
		start = 0;
	else 
		start = maxChanges - 10;
	
	snprintf(buf, MAX_STRING_LENGTH, "&z[&w  #&z]&B|&z[&wCoder   &z    ]&B|&z%s[&wDate &z   ]&B|&wChange\n\r",
					IS_IMMORTAL(ch) ?"[&wImm&z]&B|&z" : "");
	send_to_pager(buf,ch );
	snprintf(buf, MAX_STRING_LENGTH, "&B-----|--------------|%s----------&B|&B-----------------------------\n\r",
					IS_IMMORTAL(ch) ?"-----|" : "");
	send_to_pager(buf,ch );
	
	for (i = 0; i < maxChanges; i++)
	{
		if ( changes_table[i].immchange == 1 && !IS_IMMORTAL(ch))
			{
			immchanges++;
			continue;
			}
		if ( NULLSTR(changes_table[i].coder) || NULLSTR(changes_table[i].change) || NULLSTR(changes_table[i].date))
			continue;
		if ( i < (start-immchanges) )
			continue;
		if (start == 0)
			snprintf(buf,MAX_STRING_LENGTH,"&z[&w%3d&z]&B|&z[&w%-12s&z]&B|&z%s[&W%-6s&z]&B|&w%-55s\n\r",
				(i+1 - (IS_IMMORTAL(ch) ? 0 : immchanges)), changes_table[i].coder, 
				IS_IMMORTAL(ch) ? changes_table[i].immchange == 1 ? "[&w * &z]&B|&z" : "[&w   &z]&B|&z" : "",
				changes_table[i].date,
				changes_table[i].change);
		else
			snprintf(buf,MAX_STRING_LENGTH,"&z[&w%3d&z]&B|&z[&w%-12s&z]&B|&z%s[&W%-6s&z]&B|&w%-55s\n\r",
				(i+1 - (IS_IMMORTAL(ch) ? 0 : immchanges)), changes_table[i].coder, 
				IS_IMMORTAL(ch) ? changes_table[i].immchange == 1 ? "[&w * &z]&B|&z" : "[&w   &z]&B|&z" : "",
				 changes_table[i].date,
				changes_table[i].change);
		send_to_pager(buf, ch);
	}
	send_to_pager("&B--------------------------------------------------------------\n\r", ch );
	snprintf(buf,MAX_STRING_LENGTH,"&zThere is a total of &B[&w %3d &B]&z changes in the database.\n\r", 
		maxChanges - (IS_IMMORTAL(ch) ? 0 : immortal_changes));
	send_to_pager(buf, ch);
	send_to_pager("&zAlso see: &B'&wchanges all&B'&z for a list of all the changes.\n\r",ch);
	send_to_pager("&B--------------------------------------------------------------\n\r", ch );
	snprintf(buf,MAX_STRING_LENGTH,"&zThere is a total of &B[&w %3d&B ] &znew changes that have been added today.\n\r", today);
	send_to_pager(buf, ch);
	send_to_pager("&B--------------------------------------------------------------\n\r", ch );
	return;
}