#include <pebble.h>

static Window *s_window;
static StatusBarLayer *s_status_text_layer;
static TextLayer *s_upperleft_text_layer;
static TextLayer *s_upperright_text_layer;
static TextLayer *s_main_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 * msg;

static char s_status[4];

//restricting long and lat to 13 char : 0-1 for the sign, 1-3 for integer, 1 for the point, 7-10 for decimal, 1 for \0
static char s_longitude[13];
static char s_latitude[13];
static char s_distance[6];

static char s_accuracy[5];
static char s_altitude[6];
static char s_altitude_accuracy[4];
static char s_timestamp[14];
static char s_duration[9];
static char s_speed[6];
static char s_max_speed[5];
static char s_avg_speed[4];

static char s_msg[50];

static bool s_js_ready;

typedef enum {
  status,
  latitude,
  longitude,
  distance,
  altitude,
  accuracy,
  altitude_accuracy,
  speed,
  max_speed,
  avg_speed,
  timestamp,
  duration
} AppKey;


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_select_click_handler(ClickRecognizerRef recognizer, void *context) {
  text_layer_set_text(s_main_text_layer, "");
  text_layer_set_text(s_lower_text_layer, "sending get geoloc");
  send_message("startstop");
}

static void prv_up_click_handler(ClickRecognizerRef recognizer, void *context) {
  text_layer_set_text(s_lower_text_layer, "Tracking stopped, sending track...");
  send_message("send");
}

static void prv_down_click_handler(ClickRecognizerRef recognizer, void *context) {
  //text_layer_set_text(s_lower_text_layer, "Tracking stopped, sending track...");
  //send_message("exit");
}

/*
static void prv_back_click_handler(ClickRecognizerRef recognizer, void *context) {
  //text_layer_set_text(s_other_text_layer, "back");
  //send_message("exit");
}
*/

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);
  //window_single_click_subscribe(BUTTON_ID_BACK, prv_back_click_handler);
}

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

  // creation of all text layers
  s_status_text_layer = status_bar_layer_create();
  s_upperleft_text_layer = text_layer_create(GRect(0, 18, bounds.size.w/2, 34));
  s_upperright_text_layer = text_layer_create(GRect(bounds.size.w/2, 18, bounds.size.w/2, 34));
  s_main_text_layer = text_layer_create(GRect(0, 52, bounds.size.w, 52));
  s_lowerleft_text_layer = text_layer_create(GRect(0, 104, bounds.size.w/2, 34));
  s_lowerright_text_layer = text_layer_create(GRect(bounds.size.w/2, 104, bounds.size.w/2, 34));
  s_lower_text_layer = text_layer_create(GRect(0, 138, bounds.size.w, 30));

  // settings of status layer
  status_bar_layer_set_colors(s_status_text_layer, GColorBlack, GColorWhite);
  status_bar_layer_set_separator_mode(s_status_text_layer, StatusBarLayerSeparatorModeDotted);
  layer_set_frame(status_bar_layer_get_layer(s_status_text_layer), GRect(0, 0, bounds.size.w, 18));
  layer_add_child(window_layer, status_bar_layer_get_layer(s_status_text_layer));
  /*
  may need to add other layers to disply BT and GPS in status bar ?
  */

  // settings of upperleft layer
  text_layer_set_background_color(s_upperleft_text_layer, GColorWhite);
  text_layer_set_text_color(s_upperleft_text_layer, GColorBlack);
  text_layer_set_font(s_upperleft_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));
  text_layer_set_text_alignment(s_upperleft_text_layer, GTextAlignmentCenter);
  layer_add_child(window_layer, text_layer_get_layer(s_upperleft_text_layer));

  // settings of upperright layer
  text_layer_set_background_color(s_upperright_text_layer, GColorWhite);
  text_layer_set_text_color(s_upperright_text_layer, GColorBlack);
  text_layer_set_font(s_upperright_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));
  text_layer_set_text_alignment(s_upperright_text_layer, GTextAlignmentCenter);
  layer_add_child(window_layer, text_layer_get_layer(s_upperright_text_layer));

  // settings of main layer
  text_layer_set_background_color(s_main_text_layer, GColorBlack);
  text_layer_set_text_color(s_main_text_layer, GColorWhite);
  text_layer_set_font(s_main_text_layer, fonts_get_system_font(FONT_KEY_BITHAM_42_BOLD));
  text_layer_set_text_alignment(s_main_text_layer, GTextAlignmentCenter);
  layer_add_child(window_layer, text_layer_get_layer(s_main_text_layer));

  // settings of lowerleft layer
  text_layer_set_background_color(s_lowerleft_text_layer, GColorWhite);
  text_layer_set_text_color(s_lowerleft_text_layer, GColorBlack);
  text_layer_set_font(s_lowerleft_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));
  text_layer_set_text_alignment(s_lowerleft_text_layer, GTextAlignmentCenter);
  layer_add_child(window_layer, text_layer_get_layer(s_lowerleft_text_layer));

  // settings of lowerright layer
  text_layer_set_background_color(s_lowerright_text_layer, GColorWhite);
  text_layer_set_text_color(s_lowerright_text_layer, GColorBlack);
  text_layer_set_font(s_lowerright_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));
  text_layer_set_text_alignment(s_lowerright_text_layer, GTextAlignmentCenter);
  layer_add_child(window_layer, text_layer_get_layer(s_lowerright_text_layer));

  // settings of lower layer
  text_layer_set_background_color(s_lower_text_layer, GColorBlack);
  text_layer_set_text_color(s_lower_text_layer, GColorWhite);
  text_layer_set_font(s_lower_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));
  text_layer_set_text_alignment(s_lower_text_layer, GTextAlignmentCenter);
  layer_add_child(window_layer, text_layer_get_layer(s_lower_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_status_text_layer, "0......................................");
  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 latitude returns
  Tuple *latitude_tuple = dict_find(iter, MESSAGE_KEY_latitude);

  if(latitude_tuple) {
    memset(s_latitude,'\0',sizeof(s_latitude));
    strncpy(s_latitude, latitude_tuple->value->cstring, 12);

    // Display in the TextLayer
    //text_layer_set_text(s_speed_text_layer, lf_latitude);
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "latitude message received : %s",s_latitude);
  }else{
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "not latitude message... ");
  }

  // Read longitude returns
  Tuple *longitude_tuple = dict_find(iter, MESSAGE_KEY_longitude);

  if(longitude_tuple) {
    memset(s_longitude,'\0',sizeof(s_longitude));
    strncpy(s_longitude, longitude_tuple->value->cstring, 12);

    // Display in the TextLayer
    //text_layer_set_text(s_speed_text_layer, lf_longitude);
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "longitude message received : %s",s_longitude);
  }else{
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "not longitude message... ");
  }

  // Read distance returns
  Tuple *distance_tuple = dict_find(iter, MESSAGE_KEY_distance);

  if(distance_tuple) {
    memset(s_distance,'\0',sizeof(s_distance));
    strncpy(s_distance, distance_tuple->value->cstring, 6);
  }else{
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "not distance message... ");
  }

  // Read accuracy returns
  Tuple *accuracy_tuple = dict_find(iter, MESSAGE_KEY_accuracy);

  if(accuracy_tuple) {
    memset(s_accuracy,'\0',sizeof(s_accuracy));
    strncpy(s_accuracy, accuracy_tuple->value->cstring, 4);

    // Display in the TextLayer
    //text_layer_set_text(s_speed_text_layer, lf_accuracy);
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "accuracy message received : %s",s_accuracy);
  }else{
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "not accuracy message... ");
  }

  // Read altitude returns
  Tuple *altitude_tuple = dict_find(iter, MESSAGE_KEY_altitude);

  if(altitude_tuple) {
    memset(s_altitude,'\0',sizeof(s_altitude));
    strncpy(s_altitude, altitude_tuple->value->cstring, 5);

    // Display in the TextLayer
    //text_layer_set_text(s_speed_text_layer, lf_altitude);
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "altitude message received : %s",altitude_tuple->value->cstring);
  }else{
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "not altitude message... ");
  }

  // Read altitude accuracy returns
  Tuple *altitude_accuracy_tuple = dict_find(iter, MESSAGE_KEY_altitude_accuracy);

  if(altitude_accuracy_tuple) {
    memset(s_altitude_accuracy,'\0',sizeof(s_altitude_accuracy));
    strncpy(s_altitude_accuracy, altitude_accuracy_tuple->value->cstring, 3);

    // Display in the TextLayer
    //text_layer_set_text(s_speed_text_layer, lf_altitude_accuracy);
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "altitude_accuracy message received : %s",s_altitude_accuracy);
  }else{
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "not altitude_accuracy message... ");
  }

  // Read timestamp returns
  Tuple *timestamp_tuple = dict_find(iter, MESSAGE_KEY_timestamp);

  if(timestamp_tuple) {
    memset(s_timestamp,'\0',sizeof(s_timestamp));
    strncpy(s_timestamp, timestamp_tuple->value->cstring, 13);

    // Display in the TextLayer
    //text_layer_set_text(s_speed_text_layer, lf_timestamp);
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "timestamp message received : %s",s_timestamp);
  }else{
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "not timestamp message... ");
  }

  // Read duration returns
  Tuple *duration_tuple = dict_find(iter, MESSAGE_KEY_duration);

  if(duration_tuple) {
    memset(s_duration,'\0',sizeof(s_duration));
    strncpy(s_duration, duration_tuple->value->cstring, 9);
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "duration message received : %s",s_duration);
  }else{
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "not duration message... ");
  }

  // Read speed returns
  Tuple *speed_tuple = dict_find(iter, MESSAGE_KEY_speed);

  if(speed_tuple) {
    memset(s_speed,'\0',sizeof(s_speed));
    strncpy(s_speed, speed_tuple->value->cstring, 5);
    //uint i_speed=atoi(s_speed);
    // Display in the TextLayer
    //text_layer_set_text(s_speed_text_layer, lf_speed);
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "speed message received : %s ",s_speed);
  }else{
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "not speed message... ");
  }

  // Read max_speed returns
  Tuple *max_speed_tuple = dict_find(iter, MESSAGE_KEY_max_speed);

  if(max_speed_tuple) {
    memset(s_max_speed,'\0',sizeof(s_max_speed));
    strncpy(s_max_speed, max_speed_tuple->value->cstring, 5);
    //uint i_max_speed=atoi(s_max_speed);
    // Display in the TextLayer
    //text_layer_set_text(s_max_speed_text_layer, lf_max_speed);
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "max_speed message received : %s ",s_max_speed);
  }else{
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "not max_speed message... ");
  }

  // Read avg_speed returns
  Tuple *avg_speed_tuple = dict_find(iter, MESSAGE_KEY_avg_speed);

  if(avg_speed_tuple) {
    memset(s_avg_speed,'\0',sizeof(s_avg_speed));
    strncpy(s_avg_speed, avg_speed_tuple->value->cstring, 4);
  }else{
    //APP_LOG(APP_LOG_LEVEL_DEBUG, "not avg_speed message... ");
  }

  // 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);

    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{
    //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);


  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) {
  //send_message("exit");
  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();
}