#ifndef AICA_H
#define AICA_H

#include <string>
#include <vector>
// Piss take!
#include <stdio.h>
#include <map>

#include "ORANGE/CDT/List.h"

//#include "GREEN/Sample/sample.h"
//#include "GREEN/Snd/snd.h"

// todo: kos attribution?

#define SPU_RAM_BASE 0xa0800000
#define SPU_REG_BASE 0xa0700000

#define SNDREGADDR(x) (0xa0700000 + (x))
#define CHNREGADDR(chn, x) SNDREGADDR(0x80*(chn) + (x))

#define AICA_MEM_CHANNELS   0x020000

typedef struct aica_chan {
    uint32      cmd;        /* Command ID */
    uint32      base;       /* Sample base in RAM */
    uint32      type;       /* (8/16bit/ADPCM) */
    uint32      length;     /* Sample length */
    uint32      loop;       /* Sample looping */
    uint32      loopstart;  /* Sample loop start */
    uint32      loopend;    /* Sample loop end */
    uint32      freq;       /* Frequency */
    uint32      vol;        /* Volume 0-255 */
    uint32      pan;        /* Pan 0-255 */
    uint32      pos;        /* Sample playback pos */
    uint32      pad[5];     /* Padding */
} aica_chan_t;

#define AICA_CHANNEL(x)     (AICA_MEM_CHANNELS + (x) * sizeof(aica_chan_t))

using namespace std;

#define ADPCM_MAX_PACKET_SIZE 32512
#define ADPCM_MAX_PACKET_DURATION 5943.945578f

struct snd_effect;
LIST_HEAD(selist, snd_effect);

typedef struct snd_effect {
    uint32  locl, locr;
    uint32  len;
    uint32  rate;
    uint32  used;
    uint16  stereo;
    uint32  fmt;

    LIST_ENTRY(snd_effect)  list;
} snd_effect_t;

// todo: clean up???
class RSnd;

class CAicaBuffer
{
    public:
    snd_effect_t *buffer;
    uint32_t duration;
    

    CAicaBuffer(snd_effect_t *, uint32_t);
    ~CAicaBuffer();
};


// todo ???
class CAicaSound
{  
    public:

    RSnd *sound = nullptr;
    uint8_t volume = 0;

    //payload
    
    string fileName;
    uint8_t type = 0;
    uint32_t size = 0;    
    bool payloadDelivered = false;
    uint32_t  length;
    uint32_t  sampleRate;    
    uint16_t  bitsize;
    uint16_t  fmt;

    int32_t bufferSize = 0;
    uint8_t numChannels;
    uint16_t duration;
    uint8_t *aicaPayload = nullptr;
    
    CAicaBuffer *active = nullptr;    
    RList<CAicaBuffer>	ms_listAicaBuffers;

	uint8_t aicaBufferCount = 0;
    int32_t soundStartTime = 0;
    int32_t activeSegmentStartTime = 0;

    CAicaSound(uint8_t *, int32_t , uint8_t , uint32_t );
    //CAicaSound(RSnd *, uint8_t);
    ~CAicaSound();    

    // todo:???    
	int8_t LoadAdPCMBuffers(void);
	int8_t ClearAdPCMBuffers(void);
    void Reset();
    void ResetActiveAicaBuffer(void);
    CAicaBuffer* GetActiveAicaBuffer(int32_t timeStamp = 0);    
    bool UpdateActiveAicaBuffer(int32_t currTime = 0, int32_t offset = 0);
};

class CAicaSoundPack
{
    // todo???
    public:

    static bool m_bStoreAllInAICA;

    int type = 0;
    int32_t lastUpdate = 0;
    int32_t checkDiff = 0;
    
    CAicaSoundPack();
   ~CAicaSoundPack();

    void PollActiveSounds();   	    
    RList<RSnd>	ms_listActive;
    CAicaSound* Get(const string & index);     
    uint8_t Add(RSnd*);
    uint8_t Delete(RSnd*);    
};

#endif