#include <stdio.h>
#include <stdlib.h>
#include "fiximage.h"
#include "fixgui.h"


static Value native_file_read(Heap *heap, Value *error, int num_params, Value *params, void *data)
{
   FILE *f;
   char *fname;
   int err, len, read;
   char buf[256], *s;
   Value ret;

   err = fixscript_get_string(heap, params[0], 0, -1, &fname, NULL);
   if (err) {
      return fixscript_error(heap, error, err);
   }

   f = fopen(fname, "rb");
   snprintf(buf, sizeof(buf), "can't read from file: %s", fname);
   free(fname);
   if (!f) {
      *error = fixscript_create_error_string(heap, buf);
      return fixscript_int(0);
   }

   fseek(f, 0, SEEK_END);
   len = (int)ftell(f);
   fseek(f, 0, SEEK_SET);

   if (data == (void *)1) {
      ret = fixscript_create_string(heap, NULL, 0);
      if (ret.value) {
         if (fixscript_set_array_length(heap, ret, len) != FIXSCRIPT_SUCCESS) {
            ret = fixscript_int(0);
         }
      }
   }
   else {
      ret = fixscript_create_shared_array(heap, len, 1);
   }
   if (!ret.value) {
      fclose(f);
      return fixscript_error(heap, error, FIXSCRIPT_ERR_OUT_OF_MEMORY);
   }

   err = fixscript_lock_array(heap, ret, 0, len, (void **)&s, 1, 0);
   if (err) {
      fclose(f);
      return fixscript_error(heap, error, err);
   }

   read = fread(s, len, 1, f);
   fixscript_unlock_array(heap, ret, 0, len, (void **)&s, 1, 1);

   if (read != 1) {
      fclose(f);
      *error = fixscript_create_error_string(heap, buf);
      return fixscript_int(0);
   }

   fclose(f);
   return ret;
}


static Value native_file_write(Heap *heap, Value *error, int num_params, Value *params, void *data)
{
   FILE *f;
   char *fname;
   int err, len, written;
   char buf[256], *s;

   err = fixscript_get_array_length(heap, params[1], &len);
   if (err) {
      return fixscript_error(heap, error, err);
   }

   err = fixscript_get_string(heap, params[0], 0, -1, &fname, NULL);
   if (err) {
      return fixscript_error(heap, error, err);
   }
   f = fopen(fname, "wb");
   snprintf(buf, sizeof(buf), "can't write to file: %s", fname);
   free(fname);
   if (!f) {
      *error = fixscript_create_error_string(heap, buf);
      return fixscript_int(0);
   }
 
   err = fixscript_lock_array(heap, params[1], 0, len, (void **)&s, 1, 1);
   if (err) {
      fclose(f);
      return fixscript_error(heap, error, err);
   }

   written = fwrite(s, len, 1, f);
   fixscript_unlock_array(heap, params[1], 0, len, (void **)&s, 1, 0);

   if (written != 1) {
      fclose(f);
      *error = fixscript_create_error_string(heap, buf);
      return fixscript_int(0);
   }

   fclose(f);
   return fixscript_int(0);
}


static Heap *create_heap()
{
   Heap *heap;

   heap = fixscript_create_heap();
   fixscript_register_native_func(heap, "file_read#1", native_file_read, (void *)0);
   fixscript_register_native_func(heap, "file_read_text#1", native_file_read, (void *)1);
   fixscript_register_native_func(heap, "file_write#2", native_file_write, NULL);
   fiximage_register_functions(heap);
   return heap;
}


static Script *worker_load(Heap **heap, const char *fname, char **error_msg, void *data)
{
   *heap = create_heap();
   fixgui_register_worker_functions(*heap);
   return fixscript_load_file(*heap, fname, error_msg, ".");
}


int app_main(int argc, char **argv)
{
   Heap *heap;
   Script *script;
   Value error;
   char *error_msg;

   heap = create_heap();
   fixgui_register_functions(heap, worker_load, NULL);

   script = fixscript_load_file(heap, "example/main", &error_msg, ".");
   if (!script) {
      fprintf(stderr, "%s\n", error_msg);
      fflush(stderr);
      return 0;
   }
   fixscript_run(heap, script, "init#0", &error);
   if (error.value) {
      fixscript_dump_value(heap, error, 1);
      return 0;
   }
   return 1;
}
