#include <pebble.h>

// Persistent storage key
#define SETTINGS_KEY 1

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


static char s_api[40];
static char s_username[40];
static char s_password[40];
static char s_server[255];
static bool s_js_ready;

static Window *s_window;
//static Layer *window_layer;
//static GRect bounds;
static TextLayer *s_text_layer;

static ActionBarLayer *s_action_bar_layer;

static GBitmap *s_h_on_bitmap, *s_h_off_bitmap, *s_q_mark_bitmap;


bool is_home_on = false;

static uint32_t size ;
  
  
typedef enum {
  status,
  username,
  password,
  server
} AppKey;


static char * msg;


// Define our settings struct
typedef struct Settings {
  char username;
  char password;
  char server;
} Settings;

// An instance of the struct
static Settings settings;

// Save the settings to persistent storage
static void prv_save_settings() {
  persist_write_data(SETTINGS_KEY, &settings, sizeof(settings));
}


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 select_click_handler(ClickRecognizerRef recognizer, void *context) {

  // 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) {
    // Add an item to ask for weather data
    msg = "get";
    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 up_click_handler(ClickRecognizerRef recognizer, void *context) {

  // 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) {
    // Add an item to ask for weather data
    msg = "home_on";
    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 down_click_handler(ClickRecognizerRef recognizer, void *context) {

  // 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) {
    // Add an item to ask for weather data
    msg = "home_off";
    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 click_config_provider(void *context) {
  window_single_click_subscribe(BUTTON_ID_SELECT, select_click_handler);
  window_single_click_subscribe(BUTTON_ID_UP, up_click_handler);
  window_single_click_subscribe(BUTTON_ID_DOWN, down_click_handler);
}

void comm_is_ready() {
  // Get information about the window
  Layer *window_layer = window_get_root_layer(s_window);
  GRect bounds = layer_get_bounds(window_layer);

  // Create a text layer and set the text
  const GEdgeInsets label_insets = {.right = ACTION_BAR_WIDTH, .left = ACTION_BAR_WIDTH / 2};
  s_text_layer = text_layer_create(grect_inset(bounds, label_insets));
  text_layer_set_text(s_text_layer, "Welcome to Syno Cam Switch ! ready to switch...");

  // Set the font and text alignment
  text_layer_set_font(s_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD));
  text_layer_set_text_alignment(s_text_layer, GTextAlignmentCenter);

  // Add the text layer to the window
  layer_add_child(window_get_root_layer(s_window), text_layer_get_layer(s_text_layer));

  // Enable text flow and paging on the text layer, with a slight inset of 10, for round screens
  text_layer_enable_screen_text_flow_and_paging(s_text_layer, 10);

  // Push the window, setting the window animation to 'true'
  window_stack_push(s_window, true);

  // App Logging!
  APP_LOG(APP_LOG_LEVEL_DEBUG, "Just pushed a window!");

  // waiting for BT comm ready 
  // click provider
  window_set_click_config_provider(s_window, click_config_provider);

}

static void inbox_received_callback(DictionaryIterator *iter, void *context) {
  // A new message has been successfully received
  APP_LOG(APP_LOG_LEVEL_DEBUG, "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();
  }

  // Read API returns
  // Tuple *api_tuple = dict_read_first(iter);
  Tuple *api_tuple = dict_find(iter, MESSAGE_KEY_status);

  if(api_tuple) {
    strncpy(s_api, api_tuple->value->cstring, 40);
    // Display in the TextLayer
    text_layer_set_text(s_text_layer, s_api);
  }else{
    APP_LOG(APP_LOG_LEVEL_DEBUG, "not status message... ");
  }
 
  // Read String preferences
  Tuple *username_t = dict_find(iter, MESSAGE_KEY_username);
  if(username_t) {
    strncpy(s_username, username_t->value->cstring, 40);
    prv_save_settings();
    APP_LOG(APP_LOG_LEVEL_DEBUG, "new username in settings... %s",s_username);
  }

  Tuple *password_t = dict_find(iter, MESSAGE_KEY_password);
  if(password_t) {
    strncpy(s_password, password_t->value->cstring, 40);
    prv_save_settings();
    APP_LOG(APP_LOG_LEVEL_DEBUG, "new password in settings... %s",s_password);
  }
  
  Tuple *server_t = dict_find(iter, MESSAGE_KEY_server);
  if(server_t) {
    strncpy(s_server, server_t->value->cstring, 255);
    prv_save_settings();
    APP_LOG(APP_LOG_LEVEL_DEBUG, "new server in settings... %s",s_server);
  }

}

static void 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);
  
  // Create a window and get information about the window
  s_window = window_create();
  Layer *window_layer = window_get_root_layer(s_window);
  GRect bounds = layer_get_bounds(window_layer);
  
  //load buttons
  s_h_on_bitmap = gbitmap_create_with_resource(RESOURCE_ID_HOME_ON);
  s_q_mark_bitmap = gbitmap_create_with_resource(RESOURCE_ID_Q_MARK);
  s_h_off_bitmap = gbitmap_create_with_resource(RESOURCE_ID_HOME_OFF);

  s_action_bar_layer = action_bar_layer_create();
  action_bar_layer_set_icon(s_action_bar_layer, BUTTON_ID_UP, s_h_on_bitmap);
  action_bar_layer_set_icon(s_action_bar_layer, BUTTON_ID_SELECT, s_q_mark_bitmap);
  action_bar_layer_set_icon(s_action_bar_layer, BUTTON_ID_DOWN, s_h_off_bitmap);
  action_bar_layer_add_to_window(s_action_bar_layer, s_window);
  
  
  // Create a text layer and set the text
  const GEdgeInsets label_insets = {.right = ACTION_BAR_WIDTH, .left = ACTION_BAR_WIDTH / 2};
  s_text_layer = text_layer_create(grect_inset(bounds, label_insets));
  text_layer_set_text(s_text_layer, "Welcome to Syno Cam Switch !");
  
  // Set the font and text alignment
  text_layer_set_font(s_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD));
  text_layer_set_text_alignment(s_text_layer, GTextAlignmentCenter);

  // Add the text layer to the window
  layer_add_child(window_get_root_layer(s_window), text_layer_get_layer(s_text_layer));
  
  // Enable text flow and paging on the text layer, with a slight inset of 10, for round screens
  text_layer_enable_screen_text_flow_and_paging(s_text_layer, 10);

  // Push the window, setting the window animation to 'true'
  window_stack_push(s_window, true);
  
  // App Logging!
  APP_LOG(APP_LOG_LEVEL_DEBUG, "Just pushed a window!");
  
}

static void deinit(void) {
  // Destroy the text layer
  text_layer_destroy(s_text_layer);

  // Destroy the action bar layer
  action_bar_layer_destroy(s_action_bar_layer);
  
  // Destroy the window
  window_destroy(s_window);
}

int main(void) {
  init();
  app_event_loop();
  deinit();
}