#ifndef CSCommand_h
#define CSCommand_h

#define CSERIAL_CMD_DBG_EN 0    /* Set this value to 1 to enable debugging */
#define CSERIAL_CMD_BUFF_LEN 64 /* Max length for each serial command */

#include "Component.h"
#include <stdio.h>
#include <stdarg.h>


typedef struct
{
    char command[CSERIAL_CMD_BUFF_LEN];
    Component* owner;
    ComponentFnPtr fn__;
    ComponentFnPtr fn_;
    ComponentVarArgsFnPtr fn;
    void (*read)();
    void (*write)();
    void (*execute)();
} cSerialCommandCallback;

class CSCommand : public Component
{

public:
    
    CSCommand() : Component()
    {
        _init();
    }

    void runFoo(va_list args) {
        std::cout << "Run Foo!\n";
    }

    void addCommand(char *cmd, ComponentVarArgsFnPtr fn, void (*read)(), void (*write)(), void (*execute)())
    {   
        commandList = (cSerialCommandCallback*)realloc(commandList, (commandCount + 1) * sizeof(cSerialCommandCallback));
        strncpy_s(commandList[commandCount].command, cmd, CSERIAL_CMD_BUFF_LEN);
        
        commandList[commandCount].fn = fn;
        commandList[commandCount].owner = this;
        
        /*
        commandList[commandCount].read = read;
        commandList[commandCount].write = write;
        
        commandList[commandCount].execute = execute;*/

        std::cout << "Adding FN" << cmd;
        commandCount++;
    }


    cSerialCommandCallback *commandList;

    char buffer[CSERIAL_CMD_BUFF_LEN];
    char *pBuff;
    char *last;
    int commandCount;

    // Example of invoking ComponentVarArgsFnPtr within a loop
    void invokeVarArgsFnPtr(Component *c, ComponentVarArgsFnPtr fnPtr, ...)
    {
        va_list args;
        va_start(args, fnPtr);
        
        // Skip the first argument
        va_arg(args, int);

        // Invoke the function pointer
        (c->*fnPtr)(args);

        va_end(args);
    }

    void _init(void)
    {
        commandList = NULL;
        pBuff = buffer;
        last = buffer;
        commandCount = 0;
        addCommand((char*)"foo",(ComponentVarArgsFnPtr)&CSCommand::runFoo,NULL,NULL,NULL);
    }

    void runTests(void) {
        int i = 0;
        for (i = 0; (i < commandCount); i++) {
            Component* c = commandList[i].owner;
            ComponentVarArgsFnPtr ptr = commandList[i].fn;
            // short ret = (c->*ptr)(0,0);
            invokeVarArgsFnPtr(c, ptr, "arg0", "arg1", 2);

        }
    }
};

#endif
