#include <kernel/kernel.h>

#include <phantasmal/log.h>
#include <phantasmal/lpc_names.h>

#include <type.h>

/* Commandset processing */
private mixed* command_sets;

/* Prototypes */
private mixed* load_command_sets_file(string filename);


static void create(void) {
  command_sets = nil;
}

void upgraded(varargs int clone) {
  if(SYSTEM()) {
    command_sets = load_command_sets_file(USER_COMMANDS_FILE);
    if(!command_sets) {
      LOGD->write_syslog("Command_sets is Nil!", LOG_FATAL);
    }
  } else
    error("Non-System code called upgraded!");
}

int num_command_sets(int loc) {
  if(!SYSTEM())
    return 0;

  if(!command_sets[loc])
    return 0;

  return sizeof(command_sets[loc]);
}

mixed* query_command_sets(int loc, int num, string cmd) {
  mixed* ret;

  if(!SYSTEM())
    return nil;

  ret = command_sets[loc][num][cmd];

  if(ret) {
    return ret[..];
  } else {
    return nil;
  }
}

/* Used when loading commands from an UNQ file.  Arg tmp_cmd is a set
   to add commands to.  Loc is the locale.  Cmds is a string with
   commands and corresponding function names in a specific format
   delimited by commas and slashes --

          cmd_name1 / func1,
          cmd_name2 / func2,
          cmd_name3 / func3,
          etc.
*/
private void add_commands_from_file(mixed* tmp_cmd, int loc, int which,
				    string cmds) {
  mixed* entries;
  int    ctr;
  string cmd, func;

  /* Make sure tmp_cmd[loc] consists of an array with at least a single
     empty mapping... */
  if(!tmp_cmd[loc]) {
    tmp_cmd[loc] = ({ ([ ]) });
  }
  if(!sizeof(tmp_cmd[loc])) {
    tmp_cmd[loc] += ({ ([ ]) });
  }

  /* If the mapping in that array is uninitialized, initialize it */
  if(!tmp_cmd[loc][0]) {
    tmp_cmd[loc][0] = ([ ]);
  }

  entries = explode(cmds, ",");
  for(ctr = 0; ctr < sizeof(entries); ctr++) {
    entries[ctr] = STRINGD->trim_whitespace(entries[ctr]);
    if(sscanf(entries[ctr], "%s/%s", cmd, func) != 2) {
      error("Command entry doesn't match format: '" + entries[ctr]
	    + "'");
    }
    cmd = STRINGD->trim_whitespace(cmd);
    func = STRINGD->trim_whitespace(func);
    tmp_cmd[loc][which][cmd] = ({ func });
  }
}

private mixed* load_command_sets_file(string filename) {
  mixed*  tmp_cmd, *unq;
  string  file;
  int     ctr, err, loc;

  file = read_file(filename);
  if(!file) {
    LOGD->write_syslog("Couldn't find file " + filename
		       + ", not updating command_sets!", LOG_ERR);
    return command_sets;
  }

  if(!find_object(PHRASED)) { compile_object(PHRASED); }
  LOGD->write_syslog("Allocating command_sets", LOG_VERBOSE);
  tmp_cmd = allocate(PHRASED->num_locales());

  unq = UNQ_PARSER->basic_unq_parse(file);
  if(!unq) {
    LOGD->write_syslog("Couldn't parse file " + filename
		       + " as UNQ!, not updating command_sets!", LOG_ERR);
    return command_sets;
  }

  err = 0;
  for(ctr = 0; ctr < sizeof(unq); ctr += 2) {
    /* Filter out whitespace */
    if(!unq[ctr] || STRINGD->is_whitespace(unq[ctr])) {
      if(typeof(unq[ctr + 1]) != T_STRING
	 || !STRINGD->is_whitespace(unq[ctr + 1])) {
	LOGD->write_syslog("Error: not type T_STRING", LOG_ERR);
	err = 1;
	break;
      }
      continue;
    }
    if(typeof(unq[ctr + 1]) != T_STRING) {
      LOGD->write_syslog("Error: not type T_STRING: '"
			 + STRINGD->mixed_sprint(unq[ctr + 1]) + "'/"
			 + typeof(unq[ctr + 1]), LOG_ERR);
      err = 1;
      break;
    }

    /* Trim whitespace in remaining entries */
    unq[ctr] = STRINGD->trim_whitespace(unq[ctr]);
    unq[ctr+1] = STRINGD->trim_whitespace(unq[ctr+1]);

    loc = PHRASED->language_by_name(unq[ctr]);
    if(loc == -1) {
      LOGD->write_syslog("Error: unknown locale '" + unq[ctr] + "'", LOG_ERR);
      err = 1;
      break;
    }

    /* Add commands to set #0 */
    add_commands_from_file(tmp_cmd, loc, 0, unq[ctr + 1]);
  }
  if(err) {
    LOGD->write_syslog("Error decoding UNQ, not updating command_sets!",
		       LOG_ERR);
    return command_sets;
  }

  return tmp_cmd;
}
