#include <Elementary.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

static Ecore_Con_Url *url_up = NULL;

static Eina_Bool
_upload_data_cb(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event)
{
   Ecore_Con_Event_Url_Data *ev = event;

   if (ev->url_con != url_up) return EINA_TRUE;
   if (ev->size < 1024)
     {
        char *txt = alloca(ev->size + 1);

        memcpy(txt, ev->data, ev->size);
        txt[ev->size] = 0;
        printf("R %s\n", txt);
        fflush(stdout);
     }
   return EINA_FALSE;
}

static Eina_Bool
_upload_progress_cb(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event)
{
   size_t total, current;
   Ecore_Con_Event_Url_Progress *ev = event;

   if (ev->url_con != url_up) return EINA_TRUE;
   total = ev->up.total;
   current = ev->up.now;
   if (total > 0)
     {
        printf("U %i\n", (int)((current * 1000) / total));
        fflush(stdout);
     }
   return EINA_FALSE;
}

static Eina_Bool
_upload_complete_cb(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event)
{
   Ecore_Con_Event_Url_Complete *ev = event;

   if (ev->url_con != url_up) return EINA_TRUE;
   if (ev->status != 200) printf("E %i\n", ev->status);
   else printf("O\n");
   fflush(stdout);
   elm_exit();
   return EINA_FALSE;
}

static Eina_Bool
find_tmpfile(int quality, char *buf, size_t buf_size)
{
   int i;

   // come up with a tmp file - not really that critical as its due for
   // sharing to the internet as a whole
   srand(time(NULL));
   for (i = 0; i < 100; i++)
     {
        int fd, v = rand();

        if (quality == 100) snprintf(buf, buf_size, "/tmp/e-shot-%x.png", v);
        else snprintf(buf, buf_size, "/tmp/e-shot-%x.jpg", v);
        fd = open(buf, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
        if (fd >= 0)
          {
             close(fd);
             return EINA_TRUE;
          }
     }
   return EINA_FALSE;
}

EAPI int
elm_main(int argc, char **argv)
{
   Evas_Object *win, *image;
   Eina_File *infile;
   void *fdata;
   size_t fsize;
   Eina_Bool upload = EINA_FALSE;
   const char *rgba_file, *out_file = NULL;
   int w, h, stride, quality, image_stride, y;
   char *image_data, *src;
   char opts[256];

   if (argc < 6) return 1;

   rgba_file = argv[1]; // path to raw linear memory format rgba32 pixel data
   w         = atoi(argv[2]); // width in pixels
   h         = atoi(argv[3]); // height in pixels
   stride    = atoi(argv[4]); // stride per line in bytes
   quality   = atoi(argv[5]); // qwuality to save out as (100 == lossless png)
   if (argc >= 7) out_file = eina_stringshare_add(argv[6]); // out file path
   if ((w <= 0) || (w > 65535) || (h <= 0) || (h > 65535) ||
       (stride <= 0) || (stride > (65535 * 4)) ||
       (quality < 0) || (quality > 100))
     return 1;

   // set up buffer window as scratch space
   elm_config_preferred_engine_set("buffer");
   win = elm_win_add(NULL, "Shot-Upload", ELM_WIN_BASIC);
   elm_win_norender_push(win);

   // come up with tmp out file if no dest out provided
   if (!out_file)
     {
        char buf[PATH_MAX];

        upload = EINA_TRUE;
        if (find_tmpfile(quality, buf, sizeof(buf)))
          out_file = eina_stringshare_add(buf);
     }
   // open raw rgba data file which we will mmap
   infile = eina_file_open(rgba_file, EINA_FALSE);
   if (!infile) return 2;
   fsize = eina_file_size_get(infile);
   fdata = eina_file_map_all(infile, EINA_FILE_SEQUENTIAL);
   if (!((fsize > 0) && (fdata)))
     {
        ecore_file_unlink(rgba_file);
        return 3;
     }

   // create image objectfor saving out with right format and size
   image = evas_object_image_add(evas_object_evas_get(win));
   evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888);
   evas_object_image_alpha_set(image, EINA_FALSE);
   evas_object_image_size_set(image, w, h);
   image_stride = evas_object_image_stride_get(image);
   image_data = evas_object_image_data_get(image, EINA_TRUE);
   if (!((image_stride > 0) && (image_data)))
     {
        ecore_file_unlink(rgba_file);
        return 4;
     }
   // copy data into output image (could also set data straight in
   src = fdata;
   for (y = 0; y < h; y++)
     {
        memcpy(image_data, src, w * 4);
        image_data += image_stride;
        src += stride;
     }
   if (quality == 100)
     snprintf(opts, sizeof(opts), "compress=%i", 9);
   else
     snprintf(opts, sizeof(opts), "quality=%i", quality);
   eina_file_close(infile);
   ecore_file_unlink(rgba_file);
   // save the file
   if (!evas_object_image_save(image, out_file, NULL, opts))
     return 5;

   // if we have to upload it, open our output file, mmap it and upload
   if (upload)
     {
        infile = eina_file_open(out_file, EINA_FALSE);
        if (infile)
          {
             fsize = eina_file_size_get(infile);
             fdata = eina_file_map_all(infile, EINA_FILE_SEQUENTIAL);
             if ((fsize > 0) && (fdata))
               {
                  Ecore_Event_Handler *h1, *h2, *h3;

                  h1 = ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA,
                                               _upload_data_cb, NULL);
                  h2 = ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS,
                                               _upload_progress_cb, NULL);
                  h3 = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE,
                                               _upload_complete_cb, NULL);
                  if ((h1) && (h2) && (h3))
                    {
                       url_up = ecore_con_url_new
                         ("https://www.enlightenment.org/shot.php");
                       if (url_up)
                         {
                            // why use http 1.1? proxies like squid don't
                            // handle 1.1 posts with expect like curl uses
                            // by default, so go to 1.0 and this all works
                            // dandily out of the box
                            ecore_con_url_http_version_set
                              (url_up, ECORE_CON_URL_HTTP_VERSION_1_0);
                            ecore_con_url_post
                              (url_up, fdata, fsize, "application/x-e-shot");
                            // need loop to run to drive the uploading
                            elm_run();
                         }
                    }
                  ecore_event_handler_del(h1);
                  ecore_event_handler_del(h2);
                  ecore_event_handler_del(h3);
               }
             if (fdata) eina_file_map_free(infile, fdata);
             eina_file_close(infile);
          }
        // output was temporary here
        ecore_file_unlink(out_file);
     }
   evas_object_del(win);
   eina_stringshare_del(out_file);
   return 0;
}
ELM_MAIN()
