#include <pebble.h>
#define ACCEL_STEP_MS 300000

static Window *s_window;
static TextLayer *s_main_text_layer;
/*static StatusBarLayer *s_status_text_layer;
static TextLayer *s_upperleft_text_layer;
static TextLayer *s_upperright_text_layer;
static TextLayer *s_lowerleft_text_layer;
static TextLayer *s_lowerright_text_layer;
static TextLayer *s_lower_text_layer;*/

// Largest expected inbox and outbox message sizes
const uint32_t inbox_size = 150;
const uint32_t outbox_size = 64;

static uint32_t size ;
static char s_status[4];
//static char s_msg[50];

static bool s_js_ready;

typedef enum {
  status,
  x,
  y,
  z
} AppKey;


static void accel_data_handler(void *data) {
  AccelData accel = (AccelData) { .x = 0, .y = 0, .z = 0 };
  accel_service_peek(&accel);
  APP_LOG(APP_LOG_LEVEL_INFO, "t: %llu, x: %d, y: %d, z: %d",accel.timestamp, accel.x , accel.y, accel.z);
  
  APP_LOG(APP_LOG_LEVEL_INFO, "size of timestamp : %u",sizeof(accel.timestamp));
  
  // Declare the dictionary's iterator
  DictionaryIterator *out_iter;

  // Prepare the outbox buffer for this message
  AppMessageResult result = app_message_outbox_begin(&out_iter);

  if(result == APP_MSG_OK) {
    dict_write_cstring(out_iter, status, "position");
    dict_write_int16(out_iter, x, accel.x);
    dict_write_int16(out_iter, y, accel.y);
    dict_write_int16(out_iter, z, accel.z);

  // Send this message
    result = app_message_outbox_send();
    if(result != APP_MSG_OK) {
      APP_LOG(APP_LOG_LEVEL_ERROR, "Error sending the outbox: %d", (int)result);
    }
  } else {
    // The outbox cannot be used right now
    APP_LOG(APP_LOG_LEVEL_ERROR, "Error preparing the outbox: %d", (int)result);
  }
  app_timer_register(ACCEL_STEP_MS, accel_data_handler, NULL);
}

static void send_message(char * msg){

  // Declare the dictionary's iterator
  DictionaryIterator *out_iter;

  // Prepare the outbox buffer for this message
  AppMessageResult result = app_message_outbox_begin(&out_iter);

  if(result == APP_MSG_OK) {
    dict_write_cstring(out_iter, status, msg);

    // Send this message
    result = app_message_outbox_send();
    if(result != APP_MSG_OK) {
      APP_LOG(APP_LOG_LEVEL_ERROR, "Error sending the outbox: %d", (int)result);
    }
  } else {
    // The outbox cannot be used right now
    APP_LOG(APP_LOG_LEVEL_ERROR, "Error preparing the outbox: %d", (int)result);
  }
}

static void prv_up_click_handler(ClickRecognizerRef recognizer, void *context) {
  text_layer_set_text(s_main_text_layer, "wakeup");
  send_message("wakeup");
}
static void prv_select_click_handler(ClickRecognizerRef recognizer, void *context) {
  text_layer_set_text(s_main_text_layer, "awake");
  send_message("awake");
}
static void prv_down_click_handler(ClickRecognizerRef recognizer, void *context) {
  text_layer_set_text(s_main_text_layer, "gotosleep");
  send_message("gotosleep");
}

static void prv_click_config_provider(void *context) {
  window_single_click_subscribe(BUTTON_ID_SELECT, prv_select_click_handler);
  window_single_click_subscribe(BUTTON_ID_UP, prv_up_click_handler);
  window_single_click_subscribe(BUTTON_ID_DOWN, prv_down_click_handler);
}

static void prv_window_load(Window *window) {
  Layer *window_layer = window_get_root_layer(window);
  GRect bounds = layer_get_bounds(window_layer);

  s_main_text_layer = text_layer_create(GRect(0, 72, bounds.size.w, 20));
  text_layer_set_text(s_main_text_layer, "Press a button");
  text_layer_set_text_alignment(s_main_text_layer, GTextAlignmentCenter);
  layer_add_child(window_layer, text_layer_get_layer(s_main_text_layer));
}

static void prv_window_unload(Window *window) {
  text_layer_destroy(s_main_text_layer);
}

void comm_is_ready() {

  // set the text
  text_layer_set_text(s_main_text_layer, "ready");
  /*text_layer_set_text(s_upperleft_text_layer, "-");
  text_layer_set_text(s_upperleft_text_layer, "-");
  text_layer_set_text(s_main_text_layer, "Ready");
  text_layer_set_text(s_lowerleft_text_layer, "-");
  text_layer_set_text(s_lowerright_text_layer, "-");
  text_layer_set_text(s_lower_text_layer, "--:--:--");*/

}

static void inbox_received_callback(DictionaryIterator *iter, void *context) {
  // A new message has been successfully received
  APP_LOG(APP_LOG_LEVEL_INFO, "New message! ");

  size = dict_size(iter);

  // JS readiness
  Tuple *ready_tuple = dict_find(iter, MESSAGE_KEY_JSReady);

  if(ready_tuple){
    //Pebblekit JS is ready ! Safe to send messages
    s_js_ready = true;
    comm_is_ready();
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "received jsready message on watch... ");
  }
  

  // Read status returns
  Tuple *status_tuple = dict_find(iter, MESSAGE_KEY_status);

  if(status_tuple) {
    memset(s_status,'\0',sizeof(s_status));
    strncpy(s_status, status_tuple->value->cstring, 4);
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "status message received : %s",s_status);

    // DEBUG concatenate all data received
    /*
      memset(s_msg,'\0',sizeof(s_msg));
      strncpy(s_msg, "Acc. ",5);
      strcat(s_msg, s_accuracy);
      strcat(s_msg, "    Alt. ");
      strcat(s_msg, s_altitude);
      strcat(s_msg, "\n Max. ");
      strcat(s_msg, s_max_speed);
      strcat(s_msg, "\n Lat. ");
      strcat(s_msg, s_latitude);
      strcat(s_msg, "\n Long. ");
      strcat(s_msg, s_longitude);
      strcat(s_msg, "\n Time. ");
      strcat(s_msg, s_timestamp);
    */

    //APP_LOG(APP_LOG_LEVEL_DEBUG, "to display : %s ",s_msg);
    if(strcmp(s_status, "L200")==0){
      /*text_layer_set_text(s_upperleft_text_layer, s_altitude);
      text_layer_set_text(s_upperright_text_layer, s_distance);
      text_layer_set_text(s_main_text_layer, s_speed);
      text_layer_set_text(s_lowerleft_text_layer, s_avg_speed);
      text_layer_set_text(s_lowerright_text_layer, s_max_speed);
      text_layer_set_text(s_lower_text_layer, s_duration);*/
    }else if(strcmp(s_status, "S200")==0){
      //text_layer_set_text(s_lower_text_layer, "upload OK");
      vibes_short_pulse();
    }else if(strcmp(s_status, "S401")==0){
      //text_layer_set_text(s_lower_text_layer, "auth err, retrying");
    }else{
      //text_layer_set_text(s_lower_text_layer, s_status);
      vibes_double_pulse();
    }
  }else{
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "not status message... ");
  }

}


static void inbox_dropped_callback(AppMessageResult reason, void *context) {
  // A message was received, but had to be dropped
  APP_LOG(APP_LOG_LEVEL_ERROR, "Message dropped. Reason: %d", (int)reason);
}

static void outbox_sent_callback(DictionaryIterator *iter, void *context) {
  // The message just sent has been successfully delivered
  APP_LOG(APP_LOG_LEVEL_INFO, "Message sent. ");
}

static void outbox_failed_callback(DictionaryIterator *iter, AppMessageResult reason, void *context) {
  // The message just sent failed to be delivered
  APP_LOG(APP_LOG_LEVEL_ERROR, "Message send failed. Reason: %d", (int)reason);
}

static void prv_init(void) {
  
  // Open AppMessage
  app_message_open(inbox_size, outbox_size);

  // Register to be notified about inbox received events
  app_message_register_inbox_received(inbox_received_callback);
  // Register to be notified about inbox dropped events
  app_message_register_inbox_dropped(inbox_dropped_callback);
  // Register to be notified about outbox sent events
  app_message_register_outbox_sent(outbox_sent_callback);
  // Register to be notified about outbox failed events
  app_message_register_outbox_failed(outbox_failed_callback);
  
  accel_data_service_subscribe(0, NULL);

  app_timer_register(1000, accel_data_handler, NULL);



  s_window = window_create();
  window_set_click_config_provider(s_window, prv_click_config_provider);
  window_set_window_handlers(s_window, (WindowHandlers) {
    .load = prv_window_load,
    .unload = prv_window_unload,
  });
  const bool animated = true;
  window_stack_push(s_window, animated);
}

static void prv_deinit(void) {
  window_destroy(s_window);
}

int main(void) {
  prv_init();

  //APP_LOG(APP_LOG_LEVEL_DEBUG, "Done initializing, pushed window: %p", s_window);

  app_event_loop();
  prv_deinit();
}