/*
    acadsbone.c - adsb.one provider for AS
    Copyright 2023 Ladislav Vaiz <ok1zia@nagano.cz>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.
*/
#include "ac.h"
#include <libzia.h>
#include "header.h"
#include "main.h"
#include "tsdl.h"

int acs_adsbone_init(struct acs* acs) {
    acs->adsbone_http_timer = zselect_timer_new(zsel, 1000, acs_adsbone_http_timer, acs);

    acs->load_from_main_thread = acs_adsbone_load_from_main_thread;
#ifdef Z_HAVE_SDL
    acs->plot_info = acs_adsbone_plot_info;
#endif
    acs->dead_minutes = cfg->ac_adsbone_minutes + 3;
    return 0;
}

void acs_adsbone_free(struct acs* acs) {
    if (acs->adsbone_http_timer) zselect_timer_kill(zsel, acs->adsbone_http_timer);
    zhttp_free(acs->adsbone_http);
    g_free(acs->adsbone_http_error);
}

void acs_adsbone_http_timer(void* arg) {
    struct acs* acs = (struct acs*)arg;
    acs->adsbone_http_timer = 0;

    time_t now = time(NULL);
    struct tm utc;
    gmtime_r(&now, &utc);

    dbg("\n%02d:%02dz acs_adsbone_http_timer\n", utc.tm_hour, utc.tm_min);
    const char* mywwl = ctest ? ctest->pwwlo : cfg->pwwlo;
    if (cfg->ac_centerwwl != NULL && strlen(cfg->ac_centerwwl) >= 4 && strcmp(cfg->ac_centerwwl, "(null)") != 0) mywwl = cfg->ac_centerwwl;
    double myh = qth(mywwl, 0);
    double myw = qth(mywwl, 1);
 
    char* url = g_strdup_printf("https://api.adsb.one/v2/point/%3.2f/%3.2f/250", myw * 180.0 / M_PI, myh * 180.0 / M_PI);

    acs->adsbone_http = zhttp_init();
    zhttp_get(acs->adsbone_http, zsel, url, acs_adsbone_downloaded_callback, acs);
    g_free(url);
}

void acs_adsbone_downloaded_callback(struct zhttp* http) {
    char* data;
    int remains;
    struct acs* acs = (struct acs*)http->arg;

    //dbg("acs_adsbone_downloaded_callback\n");

    if (http->state == ZHTTPST_ERROR && http->errorstr) {
        dbg("ERROR acs_adsbone_downloaded_callback: %s\n", http->errorstr);
        g_free(acs->adsbone_http_error);
        acs->adsbone_http_error = g_strdup(http->errorstr);
        zhttp_free(http);
        acs->adsbone_http = NULL;
    }
    else {
        if (http_is_content_type(http, "application/json")) {
            dbg("OK acs_adsbone_downloaded_callback\n");
            data = g_new(char, http->response->len + 1);
            zbinbuf_getstr(http->response, http->dataofs, data, http->response->len + 1);

            zhttp_free(http);
            acs->adsbone_http = NULL;

            MUTEX_LOCK(acs->sh);
            g_free(acs->sh.data);
            acs->sh.data = data;
            MUTEX_UNLOCK(acs->sh);

            zg_free0(acs->adsbone_http_error);

            remains = cfg->ac_adsbone_minutes * 60000;
            acs->adsbone_http_timer = zselect_timer_new(zsel, remains, acs_adsbone_http_timer, acs);
            return;
        }
        else {
            dbg("ERROR acs_adsbone_downloaded_callback: Bad Content-Type\n");
            g_free(acs->adsbone_http_error);
            acs->adsbone_http_error = g_strdup("Bad Content-Type");
        }
    }

    remains = 60000; // if error retry after 1 minute (longer, maybe server can decrease remaining if reply failed in the middle)
    acs->adsbone_http_timer = zselect_timer_new(zsel, remains, acs_adsbone_http_timer, acs);

}

void acs_adsbone_load_from_main_thread(struct acs* acs, const char* data) {
    struct zjson* json = zjson_init(data);
    struct zjson* states = zjson_get_array(json, "ac");
    int n = 0, added = 0;
    while (1) {
        struct zjson* one = zjson_get_array(states, NULL);
        if (one == NULL) break;

        n++;

        int feets = zjson_get_int(one, "alt_baro", 0);
        int asl = feets * 0.3048;
        if (asl < cfg->ac_minalt) {
            zjson_free(one);
            continue;
        }

        char* hex = zjson_get_str(one, "hex", NULL);
        if (hex == NULL) {
            g_free(hex);
            zjson_free(one);
            continue;
        }

        struct ac* ac = g_new0(struct ac, 1);
        if (hex != NULL) {
            g_strlcpy(ac->id, hex, AC_ID_MAXLEN);
            g_free(hex);
        }
        ac->w = zjson_get_double(one, "lat", NAN) * M_PI / 180.0;
        ac->h = zjson_get_double(one, "lon", NAN) * M_PI / 180.0;

        ac->qtfdir = (zjson_get_int(one, "true_heading", 0) - 90) * M_PI / 180.0;

        ac->feets = feets;
        ac->asl = asl;

        ac->knots = zjson_get_int(one, "gs", 0);
        ac->speed = ac->knots * 1.852;

        char* callsign = zjson_get_str(one, "r", NULL);
        if (callsign != NULL) {
            g_strlcpy(ac->callsign, callsign, AC_CALLSIGN_MAXLEN);
            g_free(callsign);
        }

        ac->when = time(NULL); // no time info in feed

        char* type = zjson_get_str(one, "t", NULL);
        if (type != NULL) {
            g_strlcpy(ac->icaotype, type, AC_ICAOTYPE_MAXLEN);
            g_free(type);
        }

        ac_fill_wingspan(acs, ac);

        g_ptr_array_add(acs->th.acs, ac);
        added++;
        zjson_free(one);
    }

    dbg("downloaded %d, added %d\n", n, added);
    zjson_free(states);
    zjson_free(json);
}

#ifdef Z_HAVE_SDL
void acs_adsbone_plot_info(struct subwin* sw, SDL_Rect* area, struct acs* acs) {
    SDL_Surface* surface = sdl->screen;
    int c;

    if (acs->adsbone_http_error != NULL) {
        c = z_makecol(252, 0, 0);
        zsdl_printf(surface, area->x + 50, area->y + 5, c, 0, ZFONT_TRANSP | ZFONT_OUTLINE, TRANSLATE("ADS-B One error: %s"), acs->adsbone_http_error);
        return;
    }
}
#endif