#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include "vn_client.h"
#include "vn_malloc.h"

static void process_login(vn_asynch_result_t *ar, void *user_data)
{
    // get result of call
    vn_result_t *r = vn_asynch_result_get(ar, 0);
    assert(r);

    if(!r->error_code)
        printf("Login succeded!\n");
    else fprintf(stderr, "error code: %d, error string: %s\n",
                 r->error_code, r->error_string);
    vn_asynch_result_destroy(ar);
}

static void process_registration(vn_asynch_result_t *ar, void *user_data)
{
    // get result of call
    vn_result_t *r = vn_asynch_result_get(ar, 0);
    assert(r);

    if(r->error_code)
        fprintf(stderr, "error code: %d, error string: %s\n",
                r->error_code, r->error_string);
    
    if(r->kvl)
        printf("objid=%d\n", *(int*)(r->kvl[0]->value));

    vn_asynch_result_destroy(ar);
}

static void process_ptz_cmd(vn_asynch_result_t *ar, void *user_data)
{
    // get result of call
    vn_result_t *r = vn_asynch_result_get(ar, 0);
    assert(r);

    if(!r->error_code)
        printf("PTZ command completed successfully\n");
    else fprintf(stderr, "error code: %d, error string: %s\n",
                 r->error_code, r->error_string);
    vn_asynch_result_destroy(ar);
}

int main(int argc, char *argv[])
{
   if (argc != 7)
   {
      fprintf(stderr, "Usage: %s masterip port user passwd hwid name\n", argv[0]);
      return 1;
   }

   vn_client_config_t cfg = {};
   strcpy(cfg.remote_host, argv[1]);
   cfg.use_ssl = 1;
   cfg.timeout = 5;
   cfg.remote_port = 443;

   vn_client_context_t *ctx = vn_client_create(&cfg);

   // Let's login
   vn_asynch_result_t *ar = vn_client_login(ctx, argv[3], argv[4]);
   //vn_asynch_result_set_callback(ar, process_login, NULL);

   // get result of call
   vn_result_t *r = vn_asynch_result_get(ar, 3000);
   assert(r);

   if(!r->error_code)
       printf("Login succeded!\n");
   else fprintf(stderr, "error code: %d, error string: %s\n",
                r->error_code, r->error_string);
   vn_asynch_result_destroy(ar);

   // Try to register mobile device
   //vn_asynch_result_t *reg_ar = vn_client_register_device(ctx, "1234", "Test", "0", "h264");
   const char *keys[] = {"CAMERAMODEL", "HWID", "NAME", "MEDIA_FORMAT", "FRAMERATE", "ARCFRAMERATE"};
   vn_kv_t **kvl = vn_kv_list_create(sizeof(keys)/sizeof(char*));
   for(size_t k = 0; k < sizeof(keys)/sizeof(char*); k++)
   {
       kvl[k]->key = vn_malloc(strlen(keys[k]) + 1, NULL);
       strcpy((char*)kvl[k]->key, keys[k]);
   }

   kvl[0]->value = vn_malloc(strlen("iStream")+1, NULL);
   strcpy((char*)kvl[0]->value, "iStream");

   kvl[1]->value = vn_malloc(strlen(argv[5])+1, NULL);
   strcpy((char*)kvl[1]->value, argv[5]);

   kvl[2]->value = vn_malloc(strlen(argv[6])+1, NULL);
   strcpy((char*)kvl[2]->value, argv[6]);

   kvl[3]->value = vn_malloc(strlen("h264")+1, NULL);
   strcpy((char*)kvl[3]->value, "h264");

   kvl[4]->value = vn_malloc(strlen("30")+1, NULL);
   strcpy((char*)kvl[4]->value, "30");

   kvl[5]->value = vn_malloc(strlen("30")+1, NULL);
   strcpy((char*)kvl[5]->value, "30");

   vn_asynch_result_t *reg_ar = vn_client_add_object(ctx, (const vn_kv_t **)kvl);
   //vn_asynch_result_set_callback(reg_ar, process_registration, NULL);

   // get result of call
   r = vn_asynch_result_get(reg_ar, 3000);
   assert(r);

   if(r->error_code)
       fprintf(stderr, "error code: %d, error string: %s\n",
               r->error_code, r->error_string);

   if(r->kvl)
       printf("objid=%d\n", *(int*)(r->kvl[0]->value));

   vn_asynch_result_destroy(reg_ar);

   // get media URL
   vn_asynch_result_t *url_ar = vn_client_get_media_url(ctx, *(int*)(r->kvl[0]->value), 0, 0, 0, NULL, NULL, 0);
   // get result of call
   r = vn_asynch_result_get(url_ar, 1000);
   assert(r);
   if(r->error_code)
       fprintf(stderr, "error code: %d, error string: %s\n",
               r->error_code, r->error_string);
   else fprintf(stderr, "URL: %s\n", (char* )r->kvl[0]->value);
   vn_asynch_result_destroy(url_ar);

   vn_kv_list_destroy(kvl);

   // get users list
   vn_asynch_result_t *usr_ar = vn_client_get_users(ctx);
   // get result of call
   r = vn_asynch_result_get(usr_ar, 1000);
   assert(r);
   if(r->error_code)
       fprintf(stderr, "error code: %d, error string: %s\n",
               r->error_code, r->error_string);
   vn_asynch_result_destroy(usr_ar);

   // get roles list
   vn_asynch_result_t *roles_ar = vn_client_get_roles(ctx);
   // get result of call
   r = vn_asynch_result_get(roles_ar, 5000);
   assert(r);
   if(r->error_code)
       fprintf(stderr, "error code: %d, error string: %s\n",
               r->error_code, r->error_string);
   vn_asynch_result_destroy(roles_ar);


   // Return GEO positions
   int objs[] = {123, 125};
   //vn_asynch_result_t *geo_ar = vn_client_get_geo(ctx, objs, 2);
   vn_asynch_result_t *geo_ar = vn_client_get_geo(ctx, NULL, 0);
   // get result of call
   r = vn_asynch_result_get(geo_ar, 3000);
   assert(r);
   if(r->error_code)
       fprintf(stderr, "error code: %d, error string: %s\n",
               r->error_code, r->error_string);
   else {
       if(r->kvl) {
           fprintf(stderr, "GEO stat:\n");
           for (vn_kv_t **p = r->kvl; *p != 0; ++p) {
               vn_kv_t *pos = *p;
               fprintf(stderr, "\t%d ==> %s\n", *(int*)pos->key, (char*)pos->value);
           }
       }
   }
   vn_asynch_result_destroy(geo_ar);

   // Try to perform several ptz commands
   int n = 2;
   while(n--) {
       vn_asynch_result_t *ptz_ar1 = vn_client_perform_ptz_command(ctx, 125, "preset", "goto=1");
       vn_asynch_result_set_callback(ptz_ar1, process_registration, NULL);
       sleep(5);

       vn_asynch_result_t *ptz_ar2 = vn_client_perform_ptz_command(ctx, 125, "preset", "goto=2");
       vn_asynch_result_set_callback(ptz_ar2, process_registration, NULL);
       sleep(5);
   }
}
