#include <Arduino.h>
#include "actions.h"


bool arc_pressed = false;
bool animating = false;

float curr_temp = 0.0;
int32_t scale_max = 0, scale_min = 0, lastSelChartValue = 0;
lv_point_t lastChartPt;

void update_sensorNstatus(float temp, float hum, float seaLevelPress, bool presAlarm){
    glblData.temp = temp;
    glblData.hum = hum;
    glblData.seaLevelPress = seaLevelPress;
    glblData.presAlarm = presAlarm;
    update_status();
}
void update_clockdots(void){
    static bool dotState = false;
    dotState = !dotState;
    char* time = lv_label_get_text(objects.time_txt);
    if(dotState){
        time[3] = ':';
        lv_label_set_text(objects.time_txt, time);
    }else{
        time[3] = ' ';
        lv_label_set_text(objects.time_txt, time);
    }   
}

static void alarm_ani_cb(void * var, int32_t v)
{
    if(v > -1 && v < 256){
        lv_led_set_brightness(objects.alarmLED, v);
        setBacklight((v<<4) | 0x00FF,100);
    }
}

static void alarm_ani_end_cb(lv_anim_t *var)
{
    lv_obj_add_flag(objects.alarmLED, LV_OBJ_FLAG_HIDDEN);
    setBacklight(BL_BRIGHTNESS,250);
    lv_led_set_brightness(objects.alarmLED, 0);
        
}

void ui_settemp(float tmp){
    lv_arc_set_value(objects.temp_arc, (int32_t) (tmp));
}

void update_status(void){
    tm timeinfo;
    getLocalTime(&timeinfo);
    char buffer[15];
    strftime(buffer, sizeof(buffer), "%H : %M", &timeinfo);
    static unsigned long fullOnTime = millis();
    lv_label_set_text_fmt(objects.press_txt,"%4.2f hPa",glblData.seaLevelPress);
    lv_label_set_text_fmt(objects.hum_txt,"%2.0f %%rH",glblData.hum);
    lv_label_set_text_fmt(objects.outTemp_txt,ICON_THERMOMETER_SNOW "%2.1f °C",glblData.outTemp);
    lv_label_set_text(objects.time_txt,buffer);
    if(!arc_pressed && !animating){
        lv_label_set_text_fmt(objects.temp_txt,"%2.1f °C",glblData.temp);
    }else{
        glblData.settemp = lv_arc_get_value(objects.temp_arc);
        lv_label_set_text_fmt(objects.temp_txt,"%2.1f °C",glblData.settemp);
    }
    if(glblData.enBuff){
        lv_obj_remove_flag(objects.bufferIcn, LV_OBJ_FLAG_HIDDEN);
    }else{
        lv_obj_add_flag(objects.bufferIcn, LV_OBJ_FLAG_HIDDEN);
    }
    switch(glblData.override){
        case OVR_NONE:
        lv_obj_set_style_text_color(objects.bufferIcn,lv_color_hex(0xFFfafafa),LV_STATE_DEFAULT);
            if(glblData.temp < glblData.settemp-TMP_HYST){
                glblData.heating = true;
            }
            else if(glblData.temp > glblData.settemp+TMP_HYST){
                glblData.heating = false;
            }
            break;
        case OVR_ALWAYSON:
            lv_obj_set_style_text_color(objects.bufferIcn,lv_color_hex(0xFF00AA00),LV_STATE_DEFAULT);
            if(glblData.temp < glblData.settemp+3.0){   //allow for 3degC overheating
                glblData.heating = true;
            }
            else{
                glblData.heating = false;
            }
            break;   
        case OVR_ALWAYSOFF:
            lv_obj_set_style_text_color(objects.bufferIcn,lv_color_hex(0xFFAA0000),LV_STATE_DEFAULT);
            if(glblData.temp < 12){         //ensure minimum of 12°C
                glblData.heating = true;
            }
            else{
                glblData.heating = false;
            }
            break;  
    }
    if(glblData.heating){
        if(ledcRead(PWM_REL) == 0){
            ledcWrite(PWM_REL, 0xff); //turn on relay
            fullOnTime = millis();
            lv_obj_set_style_text_color(objects.heaterIcn,lv_color_hex(0xFFAA0000),LV_STATE_DEFAULT);
        }else if(millis() - fullOnTime > 1000 && glblData.relPowerSave == true){ //if relay is on for more than 1 sec, reduce to 50% if powersave mode is enabled
            ledcWrite(PWM_REL, 0x7f); //lower relay to 50%
            lv_obj_set_style_text_color(objects.heaterIcn,lv_color_hex(0xFF00AA00),LV_STATE_DEFAULT);
        }
        lv_obj_remove_flag(objects.heaterIcn, LV_OBJ_FLAG_HIDDEN);
    }else{
        ledcWrite(PWM_REL, 0); //turn off relay
        lv_obj_add_flag(objects.heaterIcn, LV_OBJ_FLAG_HIDDEN);
    }
    if(glblData.presAlarm == true){
        lv_obj_remove_flag(objects.alarmLED, LV_OBJ_FLAG_HIDDEN);
        lv_anim_t alarmAni;
        lv_anim_init(&alarmAni);
        lv_anim_set_values(&alarmAni, 0, 255);
        lv_anim_set_duration(&alarmAni, 600);
        lv_anim_set_playback_delay(&alarmAni, 0);
        lv_anim_set_playback_duration(&alarmAni, 600);
        lv_anim_set_repeat_delay(&alarmAni, 100);
        lv_anim_set_repeat_count(&alarmAni,7);
        lv_anim_set_exec_cb(&alarmAni, alarm_ani_cb);
        lv_anim_set_path_cb(&alarmAni, lv_anim_path_ease_in_out);
        lv_anim_set_completed_cb(&alarmAni,alarm_ani_end_cb);
        lv_anim_start(&alarmAni);
        ui_exitSleep();
    }
    
}

void update_wifi_strength(wifistrength_t strength, wifimode_t mode){
    if(mode != WIFIMODE_STA){
        Serial.println("WiFi mode not STA, not updating icon");
        lv_obj_set_style_text_color(objects.wifiIcn,lv_color_hex(0xFF0000EE),LV_STATE_DEFAULT);
    }else{
        Serial.println("WiFi mode STA, updating icon");
        lv_obj_set_style_text_color(objects.wifiIcn,lv_color_hex(0xf0f0f0),LV_STATE_DEFAULT);
    }
    switch(strength){
        case WIFISTRENGTH_HIGH:
            lv_label_set_text(objects.wifiIcn,ICON_WIFI_HIGH);
            break;
        case WIFISTRENGTH_MED:
            lv_label_set_text(objects.wifiIcn,ICON_WIFI_MED);
            break;
        case WIFISTRENGTH_LOW:
            lv_label_set_text(objects.wifiIcn,ICON_WIFI_LOW);
            break;
        case WIFISTRENGTH_OFF:
            lv_label_set_text(objects.wifiIcn,ICON_WIFI_OFF);
            break;
        case WIFISTRENGTH_ERROR:
            lv_obj_set_style_text_color(objects.wifiIcn,lv_color_hex(0xFF0000),LV_STATE_DEFAULT);
            lv_label_set_text(objects.wifiIcn,ICON_WIFI_OFF);
            break;    
    }
}

void chartDrawingCB(lv_event_t * e){
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t * chart = lv_event_get_target_obj(e);

    if(code == LV_EVENT_DRAW_POST_END) {
        ChartsEnum currChart = ui_getCurrentChart();
        int32_t id = lv_chart_get_pressed_point(objects.chart);

        lv_chart_series_t * ser = lv_chart_get_series_next(chart, NULL);
        //while(ser) {
            lv_area_t chart_obj_coords;
            lv_obj_get_coords(chart, &chart_obj_coords);
            lv_layer_t * layer = lv_event_get_layer(e);
            if(currChart == CHART_ID_TEMP){
                lv_draw_line_dsc_t draw_line_dsc;
                lv_draw_line_dsc_init(&draw_line_dsc);
                draw_line_dsc.color = lv_color_hex(0xaa0000);
                draw_line_dsc.dash_gap = 1;
                draw_line_dsc.dash_width = 2;
                draw_line_dsc.p1.x = chart_obj_coords.x1+5;
                draw_line_dsc.p1.y = lv_obj_get_y2(objects.y_scale) - (lv_obj_get_height(objects.y_scale)*(lv_arc_get_value(objects.temp_arc)-scale_min)*10)/((scale_max-scale_min)*10) -1;
                draw_line_dsc.p2.x = chart_obj_coords.x2-5;
                draw_line_dsc.p2.y = draw_line_dsc.p1.y;
                lv_draw_line(layer,&draw_line_dsc);
            }

            if(id != LV_CHART_POINT_NONE){
                lv_chart_get_point_pos_by_id(chart, ser, id, &lastChartPt);
                int32_t * y_array = lv_chart_get_y_array(objects.chart, ser);
                lastSelChartValue = y_array[id];
            }else if(lastChartPt.x == -1){
                return;
            }
            /*Draw a rectangle above the clicked point*/
            
            lv_draw_rect_dsc_t draw_rect_dsc;
            lv_draw_rect_dsc_init(&draw_rect_dsc);
            draw_rect_dsc.bg_color = lv_color_black();
            draw_rect_dsc.bg_opa = LV_OPA_50;
            draw_rect_dsc.radius = 3;

            
            lv_area_t rect_area;
            //rect_area.x1 = lastChartPt.x - 35;
            rect_area.x1 = chart_obj_coords.x1 + lastChartPt.x - 35;
            if(rect_area.x1 < chart_obj_coords.x1){
                rect_area.x1 = chart_obj_coords.x1;
            }else if(rect_area.x1 + 70 > chart_obj_coords.x2){
                rect_area.x1 = chart_obj_coords.x2 - 70;
            }
            rect_area.x2 = rect_area.x1 + 70;
            rect_area.y1 = chart_obj_coords.y1 + 5; //lastChartPt.y - 30;   -->always draw it at the top of the chart
            rect_area.y2 = chart_obj_coords.y1 + 25; //lastChartPt.y - 10;
            lv_draw_rect(layer, &draw_rect_dsc, &rect_area);

            /*Draw the value as label to the center of the rectangle*/
            char buf[16];
            lv_snprintf(buf, sizeof(buf), LV_SYMBOL_DUMMY"nan");
            switch(ui_getCurrentChart()){
                case CHART_ID_TEMP:
                if(lastSelChartValue > INT32_MIN)
                    lv_snprintf(buf, sizeof(buf), LV_SYMBOL_DUMMY"%0.1f °C", lastSelChartValue/10.0);
                break;
                case CHART_ID_HUM:
                if(lastSelChartValue > INT32_MIN)
                    lv_snprintf(buf, sizeof(buf), LV_SYMBOL_DUMMY"%d %%rH", lastSelChartValue);
                break;
                case CHART_ID_PRESS:
                if(lastSelChartValue > INT32_MIN)
                    lv_snprintf(buf, sizeof(buf), LV_SYMBOL_DUMMY"%d hPa", lastSelChartValue);
                break;
            }
            lv_draw_label_dsc_t draw_label_dsc;
            lv_draw_label_dsc_init(&draw_label_dsc);
            draw_label_dsc.color = lv_color_white();
            draw_label_dsc.text = buf;
            draw_label_dsc.text_local = 1;
            draw_label_dsc.align = LV_TEXT_ALIGN_CENTER;
            lv_area_t label_area = rect_area;
            lv_area_set_height(&label_area, lv_font_get_line_height(draw_label_dsc.font));
            lv_area_align(&rect_area, &label_area, LV_ALIGN_CENTER, 0, 0);
            lv_draw_label(layer, &draw_label_dsc, &label_area);
           
       //     ser = lv_chart_get_series_next(chart, ser);
        //}
    }
}

void chart_autoscale(void){
    int32_t* numbers  = lv_chart_get_y_array(objects.chart,objects.chart_series);
    int32_t max=INT32_MIN,min=INT32_MAX;
    uint32_t delta,factor = 1,gridFactor=1;
    for(uint16_t i=0; i<HISTLEN; i++){
        if(numbers[i] > max)
            max = numbers[i];
        if(numbers[i] < min)
            min = numbers[i];
    }
    delta = max-min;
    if(ui_getCurrentChart() == CHART_ID_TEMP){
        min = min/10;
        max = (max+9)/10;   //round up
        delta = (delta+9)/10;   //round up
        factor = 10;
    }
    while(delta > 51){
        delta = (delta+9)/10;
        gridFactor = gridFactor * 10;
    }
    if(delta < 6){  //major tick every 1.0 
        scale_min = min;
        scale_max = min+5*gridFactor;
        //lv_scale_set_total_tick_count(objects.y_scale, 26);
        //lv_scale_set_major_tick_every(objects.y_scale, 5);
    }else if(delta < 11){   //major tick every 2.0 
        min /= 2*gridFactor;
        min *= 2*gridFactor;
        scale_min = min;
        scale_max = min+10*gridFactor;
    }else if(delta < 26){      //major tick every 5.0 
        min /= 5*gridFactor;
        min *= 5*gridFactor;
        scale_min = min;
        scale_max = min+25*gridFactor;
    }else if(delta < 51){      //major tick every 10.0 
        min /= 10*gridFactor;
        min *= 10*gridFactor;
        scale_min = min;
        scale_max = min+50*gridFactor;
    }else{      //major tick every 50.0 should never happen because of scaler in while loop above
        min /= 50*gridFactor;
        min *= 50*gridFactor;
        scale_min = min;
        scale_max = min+250*gridFactor;
    }
    lv_chart_set_range(objects.chart, LV_CHART_AXIS_PRIMARY_Y, scale_min*factor, scale_max*factor);
    lv_scale_set_range(objects.y_scale, scale_min, scale_max);
}

void zoomAniWrapper(void *var, int32_t val){
    lv_obj_t* obj = (lv_obj_t*) var;
    int32_t x = -(lv_obj_get_width(obj)*val)/(6*255);
    int32_t y = -(lv_obj_get_height(obj)*val)/(6*255);
    lv_obj_set_pos(obj, x, y);
    lv_obj_set_style_transform_scale(obj, 255 + val/4, 0);
    lv_obj_set_style_text_opa(objects.hum_txt,255-val,0);
    lv_obj_set_style_text_opa(objects.press_txt,255-val,0);
    
}
void zomFinishedCB(lv_anim_t *var){
    if(arc_pressed){
        arc_pressed = false;
        animating = false;
        lv_label_set_text_fmt(objects.temp_txt,"%2.1f °C",glblData.temp);
    }else if(ui_getCurrentScreen() == SCREEN_ID_MAIN){ // only set arc pressed true if main screen is still active, otherwise we'll lock screen switching
        arc_pressed = true;
        animating = false;
        lv_label_set_text_fmt(objects.temp_txt,"%2.1f °C",glblData.settemp);
    }
}

void action_zoom_set_temp(lv_event_t * e){
    if((int)lv_event_get_user_data(e) == 1){
        if(arc_pressed == false && animating == false){
            animating = true;
            lv_anim_t a;
            lv_anim_init(&a);
            lv_anim_set_var(&a, objects.temp_txt);
            lv_anim_set_values(&a, 0, 255);
            lv_anim_set_duration(&a, 200);
            lv_anim_set_exec_cb(&a, zoomAniWrapper);
            lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out);
            lv_anim_set_completed_cb(&a,zomFinishedCB);
            lv_anim_start(&a);
        }
    }
    else{
        if(arc_pressed == true && animating == false){
            animating = true;
            lv_anim_t a;
            lv_anim_init(&a);
            lv_anim_set_var(&a, objects.temp_txt);
            lv_anim_set_values(&a, 255, 0);
            lv_anim_set_delay(&a,3000);
            lv_anim_set_duration(&a, 200);
            lv_anim_set_exec_cb(&a, zoomAniWrapper);
            lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out);
            lv_anim_set_completed_cb(&a,zomFinishedCB);
            lv_anim_start(&a);
        }
    }
    //lv_label_set_text_fmt(objects.temp_txt,"%2.1f °C",lv_arc_get_value(objects.temp_arc)/2.0);
    update_status();
}


static void anim_height_cb(void * var, int32_t v)
{
    lv_obj_t* obj = (lv_obj_t*) var;
    lv_obj_set_height(obj, v);
}

void action_switch_screens(lv_event_t * e){
    lv_dir_t gestDir = lv_indev_get_gesture_dir(lv_indev_get_act());
    lastChartPt.x = -1; //clear labels on chart change
    int32_t chartheight = lv_obj_get_height(objects.chart);
    switch (gestDir){
        case LV_DIR_LEFT:
        case LV_DIR_RIGHT:
        break;
        case LV_DIR_BOTTOM:
            lv_anim_t a;
            lv_anim_init(&a);
            lv_anim_set_exec_cb(&a, anim_height_cb);
            lv_anim_set_var(&a, objects.chart);
            lv_anim_set_values(&a, chartheight, 0);
            lv_anim_set_duration(&a, 200);
            lv_anim_set_path_cb(&a, lv_anim_path_bounce);
            lv_anim_start(&a);
            lv_anim_set_values(&a, 0, chartheight);
            lv_anim_set_delay(&a, 200);
            lv_anim_start(&a);
            if(ui_getCurrentChart() == CHART_ID_LEN-1){
                loadChart(1);
            }
            else{
                loadChart(ui_getCurrentChart()+1);
            }
            lv_indev_wait_release(lv_indev_active());
        break;
        case LV_DIR_TOP:
        break;
    }
}
void showChartScreen(lv_event_t * e){
    loadChart(0);
    loadScreen(SCREEN_ID_CHART);
}
void showMenuScreen(lv_event_t * e){
    loadScreen(SCREEN_ID_MENU);
}

void moveRolloUp(lv_event_t * e){
}

void moveRolloDown(lv_event_t * e){
}

void moveRolloMan(lv_event_t * e){
}

void showDebugScreen(lv_event_t * e){
    loadScreen(SCREEN_ID_DEBUG);
}

void showRolloScreen(lv_event_t * e){
    String devices = "";
    lv_dropdown_set_options(objects.deviceDropdown, devices.c_str()); 
    loadScreen(SCREEN_ID_ROLLO);
}

void showRolloPosScreen(lv_event_t * e){
    loadScreen(SCREEN_ID_ROLLOPOS);
}

void rebootESP(lv_event_t * e){
    ESP.restart();
}

void showMainScreen(lv_event_t * e){
    loadScreen(SCREEN_ID_MAIN);
}

void action_show_cursors_cb(lv_event_t * e){
    static int32_t last_id = -1;
    lv_obj_t * obj = (lv_obj_t*) lv_event_get_target(e);

    last_id = lv_chart_get_pressed_point(obj);
    if(last_id != LV_CHART_POINT_NONE) {
        lv_chart_set_cursor_point(obj, objects.chart_cursor, NULL, last_id);
    }
}


void draw_event_cb(lv_event_t * e)
{
    lv_obj_t * obj = (lv_obj_t*) lv_event_get_target(e);
    lv_draw_task_t * draw_task = lv_event_get_draw_task(e);
    lv_draw_dsc_base_t * base_dsc = (lv_draw_dsc_base_t*) lv_draw_task_get_draw_dsc(draw_task);
    lv_draw_label_dsc_t * label_draw_dsc = lv_draw_task_get_label_dsc(draw_task);
    if(base_dsc->part == LV_PART_INDICATOR) {
        if(label_draw_dsc) {
            uint8_t major_tick = lv_scale_get_major_tick_every(obj);
            if(base_dsc->id1 == 0){
                label_draw_dsc->color = lv_color_black();
            }

        }
    }
}