/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
/* SIP (Seal Installable Packages) setup app 1.0 */
/* (C) 2001 Kostas Michalopoulos aka Bad Sector  */
/* e-mail: michalopoylos@hotmail.com             */
/* www: http://www.badseal.org                   */
/*      http://me.badseal.org/                   */
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */

#include "allegro.h"
#include "seal.h"
#include "app.h"
#include "dialogs.h"
#include "sscript.h"
#include "registry.h"

#define FTYPES "SYSTEM/FILETYPES"

#define MSG_INSTALL 100001

p_appwin mainwin = NULL;
p_textline path = NULL;
p_stattext status = NULL;
p_process prog;
l_dword pos = 0;

l_text filename = NULL;

char *title = NULL;
char *cright = NULL;
char *lang = NULL;
char *file[1024];
char *dir[1024];
int files = 0;
char *dest = NULL;
char *scr = NULL;
int datapos = 0;
int ask_for_path = 0;
int script = 0;

char *get_str(FILE *f)
{
  int i = 0;
  char ch;
  char *s;

  s = (char *) malloc(1);
  s[0] = 0;
  do {
    fread(&ch, 1, 1, f);
    s = (char *) realloc(s, i+2);
    s[i] = ch;
    i++;
    s[i] = 0;
  } while (!feof(f) && ch > 0);

  return s;
}

static void cmd_status(l_int args, l_text arg[])
{
  if (args == 0) strcpy(status->text, ""); else strcpy(status->text, arg[0]);
  VIEW(status)->draw_view(VIEW(status));
}

static void cmd_copy_files(l_int args, l_text arg[])
{
  FILE *in = fopen(filename, "rb");
  FILE *out;
  l_int i;

  fseek(in, datapos, SEEK_SET);

  prog->size = files;
  pos = 0;
  VIEW(prog)->draw(VIEW(prog));
  for (i=0;i<files;i++) {
    char fn[1024];
    l_int fsize;
    l_int fw = 0;
    l_int block;
    char buff[4096];

    pos = i+1;
    VIEW(prog)->draw(VIEW(prog));
    strcpy(fn, path->text);
    if (fn[strlen(fn)-1] != '/' && strcmp(path->text, "")) strcat(fn, "/");
    strcat(fn, dir[i]);
    if (fn[strlen(fn)-1] != '/' && strcmp(dir[i], "")) strcat(fn, "/");
    strcat(fn, file[i]);
    out = fopen(fn, "wb");
    fread(&fsize, 4, 1, in);
    do {
      if (fw+4096 > fsize) block = fsize-fw; else block = 4096;
      fread(&buff, block, 1, in);
      fwrite(&buff, block, 1, out);
      fw += block;
    } while (fw < fsize);
    fclose(out);
  };
  fclose(in);
}

static void cmd_register_ext(l_int args, l_text arg[])
{
  char keyname[255];
/* UNUSED
  int i, j;
*/
  strcpy(keyname, arg[0]);
  if (create_key(FTYPES, keyname) != RE_SUCCESS) {
    msgbox(MW_ERROR, MB_OK, "Cannot register extension - %s", arg[0]);
    return;
  };
  if (create_key(key_in_path(FTYPES, keyname), "loader") != RE_SUCCESS) {
    msgbox(MW_ERROR, MB_OK, "Cannot register extension loader - %s", arg[0]);
    return;
  };
  if (create_key(key_in_path(FTYPES, keyname), "mime") != RE_SUCCESS) {
    msgbox(MW_ERROR, MB_OK, "Cannot register extension MIME type - %s", arg[0]);
    return;
  };
  set_key(key_in_path(FTYPES, keyname), arg[2]);
  set_key(key_in_path(key_in_path(FTYPES, keyname), "mime"), arg[3]);
  set_key(key_in_path(key_in_path(FTYPES, keyname), "loader"), arg[1]);
}

static void cmd_create_icon(l_int args, l_text arg[])
{
  l_char ininame[1024];
  l_text icon;

  if (args < 4) return;
  if (args > 4) icon = arg[4]; else icon = "./system/bmp/app.bmp";
  strcpy(ininame, "./programs/");
  strcat(ininame, arg[0]);
  strcat(ininame, "/desktop.inf");
  DEBUG_printf(ininame);
  setini_tofile(ininame, "desktop", "validate", "1", INI_STRING);
  setini_tofile(ininame, strupr(arg[1]), "name", arg[2], INI_STRING);
  setini_tofile(ininame, strupr(arg[1]), "img", icon, INI_STRING);
  setini_tofile(ininame, strupr(arg[1]), "des", arg[3], INI_STRING);
}

static void trans_ev(p_object o, p_event event)
{
  if (event->type == EV_MESSAGE && event->message == MSG_INSTALL) {
    p_sscript ss;

    clear_event(event);

    ss = sscript_init(malloc(sizeof(t_sscript)));
    ss->set_code(ss, scr);
    ss->define_command(ss, "STATUS", &cmd_status);
    ss->define_command(ss, "COPY_FILES", &cmd_copy_files);
    ss->define_command(ss, "REGISTER_EXT", &cmd_register_ext);
    ss->define_command(ss, "CREATE_ICON", &cmd_create_icon);

    if (ss->compile(ss)) {
      ss->execute(ss);
    } else {
      switch (ss->error.code) {
        case SSE_SYNTAX_ERROR: {
          msgbox(MW_ERROR, MB_OK, "SealScript compilation error (L%i): syntax error", ss->error.line);
        }; break;
        case SSE_NOT_ENOUGH_ARGS: {
          msgbox(MW_ERROR, MB_OK, "SealScript compilation error (L%i): not enough parameters", ss->error.line);
        }; break;
        case SSE_LABEL_NOT_FOUND: {
          msgbox(MW_ERROR, MB_OK, "SealScript compilation error (L%i): label not found", ss->error.line);
        }; break;
        default: {
          msgbox(MW_ERROR, MB_OK, "Unknown SealScript compilation error at line %i, code %i", ss->error.line, ss->error.code);
        }; break;
      };
    };

    OBJECT(ss)->done(OBJECT(ss));
    free(ss);
  };
}

void app_init()
{
  p_stattext s = NULL;
  p_button b = NULL;
  l_int fh;
/* UNUSED
  l_int i, j;
*/
  t_rect r = rect_assign(0, 0, 404, 300);
  mainwin = appwin_init(malloc(sizeof(t_appwin)), r, "Seal Installable Package", WF_MINIMIZE, ap_id, &trans_ev);
  VIEW(mainwin)->align |= TX_ALIGN_CENTER;
  OBJECT(desktop)->insert(OBJECT(desktop), OBJECT(mainwin));
  fh = FONT_GETHEIGHT(VIEW(mainwin)->font)+2;

  r = rect_assign(2, 20, 400, 20+fh);
  s = stattext_init(malloc(sizeof(t_stattext)), r, TX_ALIGN_CENTERX|TX_ALIGN_TOP, "Seal Installable Packages support version 0.1");
  OBJECT(mainwin)->insert(OBJECT(mainwin), OBJECT(s));
  r.a.y += fh; r.b.y += fh;
  s = stattext_init(malloc(sizeof(t_stattext)), r, TX_ALIGN_CENTERX|TX_ALIGN_TOP, "(C) 2001 Kostas Michalopoulos aka Bad Sector");
  OBJECT(mainwin)->insert(OBJECT(mainwin), OBJECT(s));

  r.a.y += 2*fh; r.b.y += 2*fh;
  s = stattext_init(malloc(sizeof(t_stattext)), r, TX_ALIGN_LEFT|TX_ALIGN_TOP, "%s", title);
  OBJECT(mainwin)->insert(OBJECT(mainwin), OBJECT(s));
  r.a.y += fh; r.b.y += fh;
  s = stattext_init(malloc(sizeof(t_stattext)), r, TX_ALIGN_LEFT|TX_ALIGN_TOP, "%s", cright);
  OBJECT(mainwin)->insert(OBJECT(mainwin), OBJECT(s));
  r.a.y += fh; r.b.y += fh;
  s = stattext_init(malloc(sizeof(t_stattext)), r, TX_ALIGN_LEFT|TX_ALIGN_TOP, "Language: %s", lang);
  OBJECT(mainwin)->insert(OBJECT(mainwin), OBJECT(s));

  r.a.y += 2*fh; r.b.y += 2*fh;
  s = stattext_init(malloc(sizeof(t_stattext)), r, TX_ALIGN_LEFT|TX_ALIGN_TOP, "Install package to...");
  OBJECT(mainwin)->insert(OBJECT(mainwin), OBJECT(s));
  r.a.y = r.b.y+1; r.b.y += 21;
  r.a.x = 4;
  path = textline_init(malloc(sizeof(t_textline)), r, -1, 1-ask_for_path);
  path->set_text(path, dest);
  OBJECT(mainwin)->insert(OBJECT(mainwin), OBJECT(path));
  r.a.x = 2;

  r.a.y += 2*fh; r.b.y += 2*fh;
  status = stattext_init(malloc(sizeof(t_stattext)), r, TX_ALIGN_LEFT|TX_ALIGN_TOP, "Press `Install' to install the package...");
  OBJECT(mainwin)->insert(OBJECT(mainwin), OBJECT(status));
  r.a.y = r.b.y+1; r.b.y += 15;
  r.a.x = 4;
  prog = process_init(malloc(sizeof(t_process)), r, 10, &pos);
  VIEW(prog)->brush.color = COLOR(8);
  OBJECT(mainwin)->insert(OBJECT(mainwin), OBJECT(prog));
  r.a.x = 2;

  r = rect_assign(20, rect_sizey(VIEW(mainwin)->bounds)-30, rect_sizex(VIEW(mainwin)->bounds)/2-50, rect_sizey(VIEW(mainwin)->bounds)-5);
  b = button_init(malloc(sizeof(t_button)), r, "Install", MSG_INSTALL, BF_DEFAULT);
  OBJECT(mainwin)->insert(OBJECT(mainwin), OBJECT(b));

  r = rect_assign(rect_sizex(VIEW(mainwin)->bounds)/2+50, rect_sizey(VIEW(mainwin)->bounds)-30, rect_sizex(VIEW(mainwin)->bounds)-20, rect_sizey(VIEW(mainwin)->bounds)-5);
  b = button_init(malloc(sizeof(t_button)), r, "Close", MSG_CLOSE, BF_NORMAL);
  OBJECT(mainwin)->insert(OBJECT(mainwin), OBJECT(b));
}

app_begin(void)
{
  if (ap_process == AP_INIT) {
    FILE *f = fopen(ap_args, "rb");
    char id[4];
    int version;
/* UNUSED
    int i;
*/
    p_appwin inf;
    if (!f) {
      msgbox(MW_ERROR, MB_OK, "Cannot open file - %s", ap_args);
      return;
    };
    if (!fread(&id, 4, 1, f)) {
      msgbox(MW_ERROR, MB_OK, "Too small file - %s", ap_args);
      fclose(f);
      return;
    };
    if (id[0] != 'S' && id[1] != 'I' && id[2] != 'P' && id[3] != '0') {
      msgbox(MW_ERROR, MB_OK, "Unknown file format - %s", ap_args);
      fclose(f);
      return;
    };
    if (!fread(&version, 4, 1, f)) {
      msgbox(MW_ERROR, MB_OK, "Too small file - %s", ap_args);
      fclose(f);
      return;
    };
    if (version != 0) {
      msgbox(MW_ERROR, MB_OK, "You need a newer version for %s", ap_args);
      fclose(f);
      return;
    };
    inf = show_info(300, 0, "Reading package file. Please wait...", ap_args);
    title = get_str(f);
    cright = get_str(f);
    lang = get_str(f);
    dest = get_str(f);
    fread(&ask_for_path, 4, 1, f);
    files = 0;
    do {
      char *s = get_str(f);
      if (!strcmp(s, "\001\001\001\001")) {
        free(s);
        break;
      };
      file[files] = s;
      dir[files] = get_str(f);
      files++;
    } while (!feof(f));
    fread(&script, 4, 1, f);
    if (script) {
      scr = (char *) malloc(1);
      scr[0] = 0;
      do {
        char *s = get_str(f);
        if (!strcmp(s, "\001\001\001\001")) {
          free(s);
          break;
        };
        scr = (char *) realloc(scr, strlen(scr)+strlen(s)+4);
        strcat(scr, "\n");
        strcat(scr, s);
        free(s);
      } while (!feof(f));
      scr = (char *) realloc(scr, strlen(scr)+3);
      strcat(scr, "\n");
    } else scr = strdup("COPY_FILES\n");
    datapos = ftell(f);
    fclose(f);
    hide_info(inf);

    filename = ap_args;

    app_init();
  };
  if (ap_process == AP_FREE) {
    l_int i;
    free(title);
    free(cright);
    free(lang);
    for (i=0;i<files;i++) {
      free(file[i]);
      free(dir[i]);
    };
    free(dest);
    free(scr);
  };
} app_end;

