/* THIS CODE IS HORRIBLE.
**
** DO NOT UNDER ANY CIRCUMSTANCES TRY TO UNDERSTAND IT.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "dcs.h"
#include "toolbox.h"
#include "iconbar.h"
#include "gadgets.h"
#include "event.h"
#include "wimplib.h"

#include "miscfile.h"
#include "multicfg.h"
#include "types.h"
#include "utils.h"
#include "vars.h"
#include "saveconf.h"
#include "loadconfig.h"

int  about_to_change_config = -1;
int  config_number = -1;
int  external_edit = 0;

static int current_config=0;

char config_path_name[256] = "<Diva$Dir>.Config\0"; // These two are
char config_dir[128] = "<Boot$Dir>.Choices.PC.v";  // corrected at run-time
char config_new[16] = "\0";

configpair     config_list[32]; /* Memory schmemory */


/* generate a filename for the 'Last' file from current config_dir */
static char * get_lastname(void)
{
  static char config_lastfile[128];
  static char last[8] = "^..Last";

  strcpy(config_lastfile, config_dir);
  strcat(config_lastfile, last);
  return (config_lastfile);
}


static void write_last(void)
{
  FILE *fh;

  if (current_config == -1) return;

  fh = fopen(get_lastname(), "wb");

  if (fh != NULL)
  {
    fwrite(&current_config, sizeof(int), 1, fh);
    fclose(fh);
  }
}

extern void multicfg_change_config(void)
{
  char buffer[256];

  if (about_to_change_config != -1) current_config = about_to_change_config;

  // This ought to be a fatal error if I was being strict, but I ain't...
  if (about_to_change_config == -1 || about_to_change_config > 31 || config_list[about_to_change_config].fname[0] == 0)
    about_to_change_config = 0;

  configuration_changed = window_title_updated = FALSE;

  sprintf(config_path_name, "%s.%s", config_dir, config_list[about_to_change_config].fname);
  /*if (!file_exists(config_path_name))
    sprintf(config_path_name, "%s.Default", config_dir);*/
  if (!load_config_file())
    still_running = FALSE;
  raise_error(stringset_set_selected(0, main_window, MAIN_CONFIGSEL, config_list[about_to_change_config].long_name));
  raise_error(displayfield_set_value(0, main_window, MAIN_CONFIGNAME, config_list[about_to_change_config].long_name));
  sprintf(buffer, "PC Card configuration: %s", config_list[about_to_change_config].fname);
  raise_error(window_set_title(0,main_window,buffer));
  config_number = about_to_change_config;
  //gadget_set_flags(0, main_window, MAIN_SAVEASNEW, 0);
  //gadget_set_flags(0, main_window, MAIN_DELETE, 0);

  about_to_change_config = -1;
  broadcast_pc_message(0x44681, 5, config_path_name); /* See 'Protocol' file */
}

static int change_config_handler(int event_code, ToolboxEvent *event, IdBlock *id_block,void *handle)
{
  NotUsed (handle);
  NotUsed (event);
  NotUsed (event_code);
  NotUsed (id_block);

  raise_error(stringset_get_selected(1, main_window, MAIN_CONFIGSEL, &about_to_change_config));
  if (configuration_changed)
  {
    my_stringset_set_selected(1, main_window, MAIN_CONFIGSEL, config_number);
    raise_error(dcs_set_message(0,dcs_window,lookup_token("dcs_change_config")));
    raise_error(toolbox_show_object(0,dcs_window,0,0,0,0));
    return(1);
  }

  multicfg_change_config();
  return(0);
}

extern void multicfg_readlist(void)
{
  FILE *fh;
  int  count=0, num=0, x;
  char line[256], temp_fname[128], stringset[2048]="\0";

  about_to_change_config = -1;

  for (x=0; x!=32; x++)
    config_list[x].fname[0] = 0,
    config_list[x].long_name[0] = 0;

  while (count > -1 && num != 31)
  {
    /*fprintf(stderr, "count = %d\n", count);*/
    count = read_entry(config_dir, line, count, NULL); num++;
    /*fprintf(stderr, "count = %d\n", count);*/
    if (config_new[0] != 0 && strcmp(line, config_new) == 0)
      about_to_change_config = num-1, config_new[0] = 0;
      //fprintf(stderr, "== %d\n", num-1);

    strcpy(config_list[num-1].fname, line);
    sprintf(temp_fname, "%s.%s", config_dir, line);
    fh = fopen(temp_fname, "rb");
    line[0] = 0;
    while (strncmp(line, "ConfigName", 10) != 0 && !feof(fh))
      fgets(line, 256, fh);
    line[strlen(line)-1] = 0;
    if (!feof(fh))
      strcpy(config_list[num-1].long_name, line+11);
    else
      strcpy(config_list[num-1].long_name, config_list[num-1].fname);
    fclose(fh);
    x = read_entry(config_dir, line, count, NULL);
    if (x == -1) count = -1;
    /*fprintf(stderr, "%d: %s -- %s\n", num-1, config_list[num-1].fname, config_list[num-1].long_name);*/
  }
  raise_error(gadget_set_flags(0, main_window, MAIN_DELETE, (num==1)<<31));
  for (x=0; x<num; x++)
    strcat(stringset, config_list[x].long_name),
    strcat(stringset, ",");
  stringset[strlen(stringset)] = 0;
  raise_error(stringset_set_available(0, main_window, MAIN_CONFIGSEL, stringset));
  if (var_exists("PC_Config$StartConfig"))
  {
    var_read("PC_Config$StartConfig", line);
    system("Unset PC_Config$StartConfig");
    toolbox_show_object(0,main_window,0,0,0,0);
    sscanf(line, "%d", &about_to_change_config);
    config_number = about_to_change_config;
  }
  if (about_to_change_config != -1);
  else if (file_exists(get_lastname())) {
    fh = fopen(get_lastname(), "rb");
    if (fh != NULL)
      fread(&about_to_change_config, sizeof(int), 1, fh);
    fclose(fh);
  } else about_to_change_config = 0;
  configuration_changed = FALSE;
  //fprintf(stderr, "about_to_change_config = %d\n", about_to_change_config);
  multicfg_change_config();
}

extern void multicfg_zero_last(void)
{
  FILE *fh;
  int  xx;

  fh = fopen(get_lastname(), "wb");
  xx = 0;
  fwrite(&xx, sizeof(int), 1, fh);
  fclose(fh);
}

extern void multicfg_reimport_all(void)
{
  /* Loads and saves every config file in the current version folder,
  ** effectively removing any obsolete options / whatever from old
  ** or badly-formatted files.
  */
  char line[256];
  int  e=0;

  while( e=read_entry(config_dir, line, e, NULL) != -1 && line[0] != 0 )
  {
    sprintf(config_path_name, "%s.%s", config_dir, line);
    load_config_file();
    //pcdbox_read_config(advanced_window_wimp, itemlist);
    build_configuration();
  }
}

extern void multicfg_new_config_dir(char *import_config_dir)
{
  char cmd[256], f[256], line[256], *b;
  FILE *fh;
  int  xx;

  sprintf(cmd, "CDir %s", config_dir);
  system(cmd);
  if (import_config_dir == NULL)
  {
    sprintf(config_path_name, "%s.Default", config_dir);
    build_configuration();
    return;
  }

  /* Not what you'd call bomb-proof, but... */
  sprintf(f, "%s.Config", import_config_dir);

  sprintf(cmd, "Copy %s %s.Default ~A~C~DF~L~N~P~QRS~T~V", f, config_dir);
  system(cmd);
  fh = fopen(get_lastname(), "wb");
  xx = 0;
  fwrite(&xx, sizeof(int), 1, fh);
  fclose(fh);

  /* Import settings from !NetRun file into new Config */

  sprintf(f, "%s.!NetRun", import_config_dir);
  if (file_exists(f))
  {
    fh = fopen(f, "rb");
    while (!feof(fh) && strstr(line, ".PCNE2") == NULL)
      fgets(line, 256, fh);
    fclose(fh);
    for(b=line; *b>=32; b++)
      if (*b>='A' && *b<='Z')
        *b+=32;
    strcpy(cmd, "NE2000Basic");
    if (strstr(line, "-piso") != NULL) strcat(cmd, " -piso");
    if (strstr(line, "-pipx") != NULL) strcat(cmd, " -pipx");
    if (strstr(line, "-ptcpip") != NULL) strcat(cmd, " -ptcpip");
    sprintf(f, "%s.Default", config_dir);
    fh = fopen(f, "rb+");
    fprintf(fh, "%s\n", cmd);
    fclose(fh);
    werr(0, lookup_token("netrun_warn"));
  }
}

extern BOOL do_multicfg_initialise(void)
{
  FILE   *fh;
  char   line[256], ver[8], *vdir, *l;
  int    xx;

  raise_error(event_register_toolbox_handler(main_window,StringSet_ValueChanged,change_config_handler,0));

  fh = fopen("<PC_Config$Dir>.^.!PC.!Run", "rb");
  if (fh != NULL)
    wimp_start_task("Obey <PC_Config$Dir>.^.!PC.!Boot", &xx);
  if (fh == NULL)
  {
    fh = fopen("<Diva$Dir>.!Run", "rb");
    if (fh != NULL)
      wimp_start_task("Obey <Diva$Dir>.!Boot", &xx);
  }
  if (fh == NULL)
  {
    werr(1, lookup_token("no_diva"));
    return(0);
  }

  fgets(line, 256, fh);
  l = line;
  while (*l>31 && strncmp(l, "!PC v", 2)!=0 ) l++;
  sscanf(l+5, "%s", ver);
  if (*l<32)
  {
    werr(1, lookup_token("no_diva_version"));
    return(0);
  }
  iconbar_set_text(0, iconbar_icon, ver);
  ver[1] = ver[0]; vdir = ver+1;
  strcat(config_dir, vdir);

  //strcpy(line, config_dir);
  //strcat(line, ".Default");
  //strcpy(config_path_name, line);
  fclose(fh);

  if (!file_exists(config_dir) || read_entry(config_dir, line, 0, NULL) == -1)
  {
    if (read_entry("<Boot$Dir>.Choices.PC", line, 0, NULL) == -1)
      return(FALSE);
    xx=0;
    while ((xx=read_entry("<Boot$Dir>.Choices.PC", line, xx, NULL)) != -1);
    multicfg_zero_last();
    sprintf(line+128, "Copy <Boot$Dir>.Choices.PC.%s %s ~A~C~DF~L~N~P~QRS~T~V", line, config_dir);
    if (cancel_ok(lookup_token("config_import"), "Import,Use default"))
      system(line+128);
    else
      multicfg_new_config_dir(NULL);
  }

  atexit(write_last);
  multicfg_readlist();
  /*config_number = about_to_change_config = 0;
  change_config_handler(0,NULL,NULL,NULL);*/
  return(TRUE);
}

extern void do_multicfg_delete(void)
{
  char cmd[256];

  if (config_list[1].fname[0] == 0)
  {
    werr(0, lookup_token("delete_last"));
    return;
  }

  if (!cancel_ok(lookup_token("delete_confirm"), "Delete,Cancel"))
    return;

  sprintf(cmd, "Delete %s", config_path_name);
  system(cmd);

  broadcast_pc_message(0x44681, 3, config_path_name); // See 'Protocol' file
  multicfg_readlist();
  //multicfg_change_config();
}

extern void do_multicfg_saveasnew(char *newname)
{
  char buffer[64];
  int  x;

  strcpy(buffer, newname);
  for (x=0; x!=32; x++)
    if (strcmp(config_list[x].long_name, buffer) == 0)
      {
        werr(0,lookup_token("save_same_name"));
        return;
      }

  for (x=0; buffer[x] > 31; x++)
    if (strrchr("\"#$%&*,./:@^ ", buffer[x]) != NULL )
      buffer[x] = '_';

  if (strlen(buffer) > 9)
    sprintf(config_path_name, "%s.%c%c%c%c%c%c%c%c%c%c", config_dir, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[strlen(buffer)-5], buffer[strlen(buffer)-4], buffer[strlen(buffer)-3], buffer[strlen(buffer)-2], buffer[strlen(buffer)-1]);
  else
    sprintf(config_path_name, "%s.%s", config_dir, buffer);

  // Loop which ensures filenames aren't similar; tries ~1 -> ~9 as suffixes
  // then ~a -> ~z, then random 8-digit hex numbers!
  x='0'; while (file_exists(config_path_name))
  {
    config_path_name[strlen(config_path_name)-2] = '~';
    config_path_name[strlen(config_path_name)-1] = x;
    if (++x == ':') x = 'a';
    if (  x >= '{') sprintf(config_path_name-10, "%08x", rand());
  }
  //strcpy(config_new, config_path_name+strlen(config_dir)+1);
  //fprintf(stderr, "config_new = %s\n", config_new);

  broadcast_pc_message(0x44681, 4, config_path_name); // See 'Protocol' file
  build_configuration();
  multicfg_readlist();
  //config_number = about_to_change_config = 0;
  //multicfg_change_config();
}
