#include "sithDSSCog.h"

#include "Cog/sithCog.h"
#include "Cog/sithCogExec.h"
#include "Dss/sithMulti.h"
#include "World/sithThing.h"
#include "Devices/sithComm.h"
#include "Main/Main.h"

int sithDSSCog_SendMessage(sithCog *a1, int a2, int a3, int a4, int a5, int a6, int a7, flex32_t param0, flex32_t param1, flex32_t param2, flex32_t param3, int a11)
{
    int v12; // edi
    SithThing *v13; // eax
    SithThing *v14; // eax
    
    NETMSG_START;

    NETMSG_PUSHS32(a7);
    v12 = 1;
    NETMSG_PUSHS16(a1 ? a1->idx : -1);
    NETMSG_PUSHU8(a3);
    NETMSG_PUSHU8(a5);

    if ( a3 == 3 && (v13 = sithThing_GetThingByIndex(a4)) != 0 ) {
        NETMSG_PUSHS32(v13->guid);
    }
    else {
        NETMSG_PUSHS32(a4);
    }

    if ( a5 == 3 && (v14 = sithThing_GetThingByIndex(a6)) != 0 ) {
        NETMSG_PUSHS32(v14->guid);
    }
    else {
        NETMSG_PUSHS32(a6);
    }

    NETMSG_PUSHS16(a2 & 0xFF);
    
    NETMSG_PUSHF32(param0);
    NETMSG_PUSHF32(param1);
    NETMSG_PUSHF32(param2);
    NETMSG_PUSHF32(param3);

    //printf("%x %x %x %x %x %x %x, %f %f %f %f\n", a7, a1->idx, a3, a5, a, b, a2, param0, param1, param2, param3);
    
    NETMSG_END(DSS_SENDTRIGGER);

    if ( a2 == SITH_MESSAGE_TOUCHED )
        v12 = 0;
    return sithComm_SendMsgToPlayer(&sithComm_netMsgTmp, a11, 1, v12);
}

int sithDSSCog_ProcessMessage(SithMessage *in_netMsg)
{
    int senderType; // edi
    int senderIdx; // ebx
    int sourceIndex; // ebp
    SithThing *v6; // eax
    SithThing *v7; // eax
    int msgid; // eax
    SithThing *v12; // eax
    flex32_t param3; // [esp+10h] [ebp-1Ch]
    flex32_t param2; // [esp+14h] [ebp-18h]
    flex32_t param1; // [esp+18h] [ebp-14h]
    flex32_t param0; // [esp+1Ch] [ebp-10h]
    sithCog *cog; // [esp+20h] [ebp-Ch]
    int linkId; // [esp+28h] [ebp-4h]
    int sourceType; // [esp+30h] [ebp+4h]
    
    NETMSG_IN_START(in_netMsg);

    linkId = NETMSG_POPS32();
    cog = sithCog_GetCogByIndex(NETMSG_POPS16());
    senderType = NETMSG_POPU8();
    sourceType = NETMSG_POPU8();
    senderIdx = NETMSG_POPS32();
    sourceIndex = NETMSG_POPS32();
    if ( senderType == SENDERTYPE_THING )
    {
        v6 = sithThing_GetGuidThing(senderIdx);
        if ( v6 )
            senderIdx = v6->idx;
    }
    if ( sourceType == SENDERTYPE_THING )
    {
        v7 = sithThing_GetGuidThing(sourceIndex);
        if ( v7 )
            sourceIndex = v7->idx;
    }
    msgid = NETMSG_POPS16() & 0xFF;
    param0 = NETMSG_POPF32();
    param1 = NETMSG_POPF32();
    param2 = NETMSG_POPF32();
    param3 = NETMSG_POPF32();
    //printf("%x %x %x %x %x %x %x, %f %f %f %f\n", linkId, cog->idx, senderType, sourceType, senderIdx, sourceIndex, msgid, param0, param1, param2, param3);
    if ( !cog )
    {
        sithCog_BroadcastMessageEx(msgid, senderType, senderIdx, sourceType, sourceIndex, param0, param1, param2, param3);
        return 1;
    }
    if ( senderType == SENDERTYPE_THING )
    {
        v12 = sithThing_GetThingByIndex(senderIdx);
        if ( !v12 || (v12->flags & SITH_TF_CAPTURED) == 0 )
            return 1;
    }
    sithCog_SendMessageEx(cog, msgid, senderType, senderIdx, sourceType, sourceIndex, linkId, param0, param1, param2, param3);
    return 1;
}

int sithDSSCog_SyncCogState(sithCog *cog, int sendto_id, int mpFlags)
{
    SithCogSymbolTable *v13; // ebp
    
    NETMSG_START;

    NETMSG_PUSHS32(cog->idx);
    NETMSG_PUSHS32(cog->script_running);
    NETMSG_PUSHS32(cog->flags);
    if (cog->script_running)
    {
        NETMSG_PUSHS32(cog->msecTimerTimeout);
        NETMSG_PUSHS32(cog->execPos);
        NETMSG_PUSHS32(cog->senderId);
        NETMSG_PUSHS32(cog->senderRef);
        NETMSG_PUSHS32(cog->senderType);
        NETMSG_PUSHS32(cog->sourceIdx);
        NETMSG_PUSHS32(cog->sourceType);
    }
    if ( (cog->flags & SITH_COG_PULSE_SET) != 0 )
    {
        NETMSG_PUSHS32(cog->msecPulseInterval);
        NETMSG_PUSHS32(cog->msecNextPulseTime);
    }
    if ( (cog->flags & SITH_COG_TIMER_SET) != 0 )
        NETMSG_PUSHS32(cog->field_20);
    v13 = cog->pSymbolTable;
    if ( v13->numUsedSymbols )
    {
        for (int i = 0; i < v13->numUsedSymbols; i++)
        {
            NETMSG_PUSHU8(v13->aSymbols[i].val.type & 0xFF);
        }

        // TODO: figure out how to handle this in 64-bit
        for (int i = 0; i < v13->numUsedSymbols; i++)
        {
            SithCogSymbol* sym = &v13->aSymbols[i];
            if (sym->val.type == SITHCOG_VALUE_FLOAT)
            {
                NETMSG_PUSHS32((uint32_t)sym->val.data[0]);
            }
            else if ( sym->val.type == SITHCOG_VALUE_VECTOR )
            {
#ifndef COG_COMPRESS_VAR_SIZE
                NETMSG_PUSHF32(sym->val.dataAsFloat[0]);
                NETMSG_PUSHF32(sym->val.dataAsFloat[1]);
                NETMSG_PUSHF32(sym->val.dataAsFloat[2]);
#else
                if (sym->val.dataAsPtrs[0]){
                    cog_flex_t* ptr = (cog_flex_t*)sym->val.dataAsPtrs[0];
                    NETMSG_PUSHF32(ptr[0]);
                    NETMSG_PUSHF32(ptr[1]);
                    NETMSG_PUSHF32(ptr[2]);
                }
                else {
                    NETMSG_PUSHF32(0.0f);
                    NETMSG_PUSHF32(0.0f);
                    NETMSG_PUSHF32(0.0f);
                }
#endif
            }
            else if (Main_bMotsCompat && sym->val.type == SITHCOG_VALUE_STRING)
            {

            }
            else
            {
                NETMSG_PUSHS32((uint32_t)sym->val.data[0]); // TODO ??? this is a pointer?
            }
        }
    }

    NETMSG_END(DSS_SYNCCOG);
    return sithComm_SendMsgToPlayer(&sithComm_netMsgTmp, sendto_id, mpFlags, 1);
}

int sithDSSCog_ProcessCogState(SithMessage *msg)
{
    sithCog *cog; // eax
    SithCogSymbolTable *v13; // ebp
    
    NETMSG_IN_START(msg);

    cog = sithCog_GetCogByIndex(NETMSG_POPS32());
    if (!cog)
        return 0;

    cog->script_running = NETMSG_POPS32();
    cog->flags = NETMSG_POPS32();
    if (cog->script_running)
    {
        cog->msecTimerTimeout = NETMSG_POPS32();
        cog->execPos = NETMSG_POPS32();
        cog->senderId = NETMSG_POPS32();
        cog->senderRef = NETMSG_POPS32();
        cog->senderType = NETMSG_POPS32();
        cog->sourceIdx = NETMSG_POPS32();
        cog->sourceType = NETMSG_POPS32();
    }

    if (cog->flags & SITH_COG_PULSE_SET)
    {
        cog->msecPulseInterval = NETMSG_POPS32();
        cog->msecNextPulseTime = NETMSG_POPS32();
    }

    if (cog->flags & SITH_COG_TIMER_SET)
    {
        cog->field_20 = NETMSG_POPS32();
    }
    
    v13 = cog->pSymbolTable;
    if ( v13->numUsedSymbols )
    {
        for (int i = 0; i < v13->numUsedSymbols; i++)
        {
            v13->aSymbols[i].val.type = NETMSG_POPU8();
        }

        // TODO: verify in 64-bit, particularly with AICLASS
        for (int i = 0; i < v13->numUsedSymbols; i++)
        {
            SithCogSymbol* sym = &v13->aSymbols[i];
            if (sym->val.type == SITHCOG_VALUE_FLOAT)
            {
                sym->val.data[0] = NETMSG_POPS32();
            }
            else if ( sym->val.type == SITHCOG_VALUE_VECTOR )
            {
#ifndef COG_COMPRESS_VAR_SIZE
                sym->val.dataAsFloat[0] = NETMSG_POPF32();
                sym->val.dataAsFloat[1] = NETMSG_POPF32();
                sym->val.dataAsFloat[2] = NETMSG_POPF32();
#else
                if (sym->val.dataAsPtrs[0]){
                    cog_flex_t* ptr = (cog_flex_t*)sym->val.dataAsPtrs[0];
                    ptr[0] = NETMSG_POPF32();
                    ptr[1] = NETMSG_POPF32();
                    ptr[2] = NETMSG_POPF32();
                }
                else {
                    NETMSG_POPF32();
                    NETMSG_POPF32();
                    NETMSG_POPF32();
                }
#endif
            }
            else if (Main_bMotsCompat && sym->val.type == SITHCOG_VALUE_STRING)
            {
                
            }
#ifdef QOL_IMPROVEMENTS
            else if (!Main_bMotsCompat && sym->val.type == SITHCOG_VALUE_STRING)
            {
                
            }
#endif
            else
            {
                sym->val.data[0] = NETMSG_POPS32();
            }
        }
    }

    return 1;
}
