/* ************************************************************************
*   File: quest.c				   A utility to CircleMUD *
*  Usage: writing/reading player's quest bits                             *
*                                                                         *
*  Code done by Billy H. Chan  				   		  *
*                                                                         *
************************************************************************ */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "structs.h"
#include "utils.h"
#include "interpreter.h"

void send_to_char(char *messg, struct char_data *ch);
struct char_data *get_char_vis(struct char_data *ch, char *arg1);

void free_quest(struct quest * q)
{
	free(q);
}

void write_quests(struct char_data *ch)
{
  FILE *file;
  char fn[127];
  struct quest *temp;

  get_filename(GET_NAME(ch),fn,QUEST_FILE);
  unlink(fn);
  if( !GET_QUESTS(ch) )
    return;

  file = fopen(fn,"wt");

  temp = GET_QUESTS(ch);
  
  while( temp )
  {
    fwrite(temp, sizeof(struct quest), 1, file);
    temp = temp->next;
  }
  fclose(file);
}

void read_quests(struct char_data *ch)
{   
  FILE *file;
  char fn[127];
  struct quest *temp, *temp2;

  get_filename(GET_NAME(ch),fn,QUEST_FILE);

  file = fopen(fn,"r");

  if( !file )
    return;
 
  CREATE(GET_QUESTS(ch),struct quest,1);
  temp = GET_QUESTS(ch); 

  do 
  {  
    fread(temp, sizeof(struct quest), 1, file);
    if( !feof(file) ){
      CREATE(temp2,struct quest,1);
      temp->next = temp2;
      temp = temp->next;
    } 
  } while( !feof(file) ); 
  
  fclose(file);
} 

struct quest *find_quest(struct char_data * ch, int zone)
{
	struct quest * previous, *temp, * next = GET_QUESTS(ch);
	bool contloop = TRUE;

	previous = NULL;

	while ((next != NULL) && contloop) {
		if (next->zone < zone) {
			previous = next;
			next = next->next;
		}
		else if (next->zone == zone)
			return next;
		else
			contloop = FALSE;
	}
	CREATE(temp, struct quest, 1);
	temp->zone = zone;
	temp->firstrow = 0;
	temp->secondrow = 0;
	temp->next = next;
	if (previous) 
		previous->next = temp;
	else
		GET_QUESTS(ch) = temp;
	return temp;
}

questrow get_quest_bits(struct char_data * ch, int zone, int row, int offset, int length)
{
	struct quest * q;
	questrow temp, accum = 0;
	int i = 0;

	q = find_quest(ch, zone);

	if (row >= 2)
		temp = q->secondrow;
	else
		temp = q->firstrow;
	
	while (i < length) {
		if (IS_SET(temp, 1 << (offset + i)))
			SET_BIT(accum, 1 << i);
		i++;
	}
	return accum;
} 	

void change_quest_bits(struct char_data * ch, int zone, int row, int offset, int length, int value)
{
	struct quest * q;
	questrow loc;
	int i = 0;

	if (offset < 0)
		offset = 0;
	if (offset > 31)
		offset = 31;
	while ((offset + length) > 32) {
		length--;		
	}
	q = find_quest(ch, zone);

	if (row >= 2) 
		loc = q->secondrow;
	else
		loc = q->firstrow;

	while (i < length) {
		if (IS_SET(value, 1 << i))
			SET_BIT(loc, 1 << (offset + i));
		else
			REMOVE_BIT(loc, 1 << (offset + i));
		i++;
	}					
	if (row >= 2) 
		q->secondrow = loc;
	else
		q->firstrow = loc;
}

void add_quest_bits(struct char_data * ch, int zone, int row, int offset, int length, int value)
{
	struct quest * q;
	questrow loc;

	if (offset < 0)
		offset = 0;
	if (offset > 31)
		offset = 31;
	while ((offset + length) >= 32)
		length --;		

	q = find_quest(ch, zone);

	if (row >= 2)
		loc = q->secondrow;
	else
		loc = q->firstrow;

	if (value >= (1 << (length + 1)))
		value -= (1 << (length + 1));

	loc += (value << offset);

	if (row >= 2) 
		q->secondrow = loc;
	else
		q->firstrow = loc;
}


ACMD(do_showquest)
{
  int zone, i, j;
  struct char_data * victim;
  questrow temp;
  char buf[256], arg1[256], arg2[256];

  if (!*argument) {
    strcpy(buf, "Showquest usage: showquest <player> <zone>\r\n");
    send_to_char(buf, ch);
    return;
  }

  strcpy(buf, two_arguments(argument, arg1, arg2));
  if (!*arg2) {
    strcpy(buf, "Showquest usage: showquest <player> <zone>\r\n");
    send_to_char(buf, ch);	
    return;
  }

  victim = get_char_vis(ch, arg1);

  zone = atoi(arg2);

  sprintf(buf, "%-35.35s01234567890123456789012345678901\r\n", GET_NAME(victim));
  send_to_char(buf, ch);
  for (j = 1; j <= 2; j++) {
     temp = get_quest_bits(victim, zone, j, 0, 32);
     sprintf(buf, "Questbits for Zone %d in Row %d is: ", zone, j);
     sprintf(buf, "%-35.35s", buf);
     for (i = 0; i < 32; i++) {
	  if (temp & 1)
		  sprintf(buf, "%s1", buf);
	  else
		  sprintf(buf, "%s0", buf);
	  temp = temp >> 1;
     }
     strcat(buf, "\r\n");
     send_to_char(buf, ch);
  }
}

ACMD(do_setquest)
{
  int zone, offset, length, row;
  long value;
  struct char_data * victim;
  questrow temp;
  char buf[256], arg1[256];

  if (!*argument) {
    if (subcmd == SCMD_SET_QUEST_BIT)
	    strcpy(buf, "setquest usage: setquest <player> <zone> <row> <offset> <length> <value>\r\n");
    else
	    strcpy(buf, "addquest usage: addquest <player> <zone> <row> <offset> <length> <value>\r\n");
    send_to_char(buf, ch);
    return;
  }

  half_chop(argument, arg1, argument);
  victim = get_char_vis(ch, arg1);

  half_chop(argument, arg1, argument);
  zone = atoi(arg1);
  if (!*arg1 || (zone < 0) || (zone > 500)) {
    strcpy(buf, "zone must be a number between 0 and 500");
    send_to_char(buf, ch);
    return;	
  }

  half_chop(argument, arg1, argument);
  row = atoi(arg1);
  if (!*arg1 || (row < 0) || (row > 2)) {
    strcpy(buf, "row must be a number between 1 and 2");
    send_to_char(buf, ch);
    return;		
  }

  half_chop(argument, arg1, argument);
  offset = atoi(arg1);
  if (!*arg1 || (offset < 0) || (offset > 31)) {
    strcpy(buf, "offset must be a number between 0 and 31");
    send_to_char(buf, ch);
    return;		
  }

  half_chop(argument, arg1, argument);
  length = atoi(arg1); 
  if (!*arg1 || (length < 0) || (length > 32)) {
    strcpy(buf, "length must be a number between 1 and 32");
    send_to_char(buf, ch);
    return;		
  }

  if (length + offset > 32) {
	strcpy(buf, "length and offset must not exceed 32");
	send_to_char(buf, ch);
	return;
  }

  half_chop(argument, arg1, argument);
  if (!*arg1) {
    strcpy(buf, "a value must be given");
    send_to_char(buf, ch);
    return;		
  }
  value = atol(arg1); 

  if (subcmd != SCMD_SET_QUEST_BIT) {
	  temp = get_quest_bits(victim, zone, row, offset, length);
	  if (value >= 0)
		value += temp;
	  else
	        value = temp & ~value;
	}
  change_quest_bits(victim, zone, row, offset, length, value);
  send_to_char("Quest bit has been modified.\r\n", ch);
}