#include <Vector.h>
#include <Streaming.h>
#include <Arduino.h>
#include "app.h"
#include "config.h"
#include "types.h"
#include "common/macros.h"
#include "common/error_codes.h"
#include "Addon.h"
#include "features.h"

#include <Arduino.h>

/*
void printMessage(const char* pattern, ...)
{
    char buffer[256];
    va_list args;
    va_start(args, pattern);
    vsnprintf(buffer, sizeof(buffer), pattern, args);
    va_end(args);
    
    Serial.print(buffer);
}
*/

short App::setFlag(ushort addonId, ushort flag)
{
    Addon *addon = byId(addonId);
    if (addon)
    {
        addon->setFlag(flag);
        return E_OK;
    }
    return ERROR_WARNING;
}

ushort App::numByFlag(ushort flag)
{
    uchar s = addons.size();
    uchar l = 0;
    String out = "";
    for (uchar i = 0; i < s; i++)
    {
        Addon *addon = addons[i];
        if (!!(addon->hasFlag(flag)))
        {
            l++;
        }
    }
    return l;
}

#ifdef HAS_STATES
short App::appState(short nop)
{
    uchar s = addons.size();
    uchar si = 0;
    String out = "";
    uchar l = numByFlag(STATE);
    for (uchar i = 0; i < s; i++)
    {
        Addon *addon = addons[i];
        if (!!(addon->hasFlag(STATE)))
        {
            si++;
            out += addon->state();
            if (si < l)
            {
                out += ",";
            }
        }
    }
    const char *response = Bridge::CreateResponse(STATE_RESPONSE_CODE, 0, out.c_str());
    Serial.write(response);
}
#endif
short App::debug()
{
#ifndef MEARSURE_PERFORMANCE
    if (millis() - debugTS > DEBUG_INTERVAL)
    {
        uchar s = addons.size();
        uchar nb = 0;
        for (uchar i = 0; i < s; i++)
        {
            Addon *addon = addons[i];
            if (addon->hasFlag(DEBUG))
            {
                if ((addon->debug)(&Serial))
                {
                    Serial.println("\n");
                    nb++;
                }
            }
        }
        if (nb)
        {
            Serial.println("\n");
        }
        debugTS = millis();
    }
#endif
}

short App::info()
{
    uchar s = addons.size();
    for (uchar i = 0; i < s; i++)
    {
        Addon *addon = addons[i];
        if (addon->hasFlag(INFO))
        {
            addon->info(&Serial);
            Serial << "\n";
        }
    }
    return E_OK;
}

Addon *App::byId(short id)
{
    uchar s = addons.size();
    for (uchar i = 0; i < s; i++)
    {
        Addon *addon = addons[i];
        if (addon->id == id)
        {
            return addon;
        }
    }
    return NULL;
}

void App::setup_addons()
{
    
#ifdef HAS_COMMUNICATION
    addons.push_back((Addon *)com);
#endif

    addons.push_back((Addon *)this);
    uchar s = addons.size();
    for (uchar i = 0; i < s; i++)
    {
        Addon *addon = addons[i];
        if (addon->hasFlag(SETUP))
        {
            addon->setup();
        }
    }
}
void App::loop_addons()
{

#ifdef MEARSURE_PERFORMANCE
    millis_t now = millis();
#endif

    uchar s = addons.size();
    for (uchar i = 0; i < s; i++)
    {
        Addon *addon = addons[i];
        if (addon->hasFlag(LOOP))
        {
            addon->now = millis();
            addon->loop();
        }
    }

#ifdef MEARSURE_PERFORMANCE
    addonLoopTime = millis() - now;
    if (millis() - printPerfTS > 3000)
    {
        printPerfTS = now;
        Serial << SPACE("Addon loop time") << addonLoopTime << "\n";
    }
#endif
    debug();
}
