#define __MAKE_PLUGIN__

#include<hgl/plugin/PlugIn.h>
#include<hgl/plugin/PlugInInterface.h>
#include<string.h>
#include<malloc.h>
#include<hgl/al/al.h>

using namespace hgl;
using namespace openal;

typedef struct                                  /* WAV File-header */
{
    ALubyte  Id[4]            ;
    ALsizei  Size                ;
    ALubyte  Type[4]            ;
}
WAVFileHdr_Struct;

typedef struct                                  /* WAV Fmt-header */
{
    ALushort Format            ;
    ALushort Channels            ;
    ALuint   SamplesPerSec    ;
    ALuint   BytesPerSec        ;
    ALushort BlockAlign        ;
    ALushort BitsPerSample    ;
}
WAVFmtHdr_Struct;

typedef struct                                    /* WAV FmtEx-header */
{
    ALushort Size                ;
    ALushort SamplesPerBlock    ;
}
WAVFmtExHdr_Struct;

typedef struct                                  /* WAV Smpl-header */
{
    ALuint   Manufacturer        ;
    ALuint   Product            ;
    ALuint   SamplePeriod        ;
    ALuint   Note                ;
    ALuint   FineTune            ;
    ALuint   SMPTEFormat        ;
    ALuint   SMPTEOffest        ;
    ALuint   Loops            ;
    ALuint   SamplerData        ;

    struct
    {
        ALuint Identifier        ;
        ALuint Type                ;
        ALuint Start            ;
        ALuint End                ;
        ALuint Fraction            ;
        ALuint Count            ;
    }
    Loop[1]            ;
}
WAVSmplHdr_Struct;

typedef struct                                  /* WAV Chunk-header */
{
    ALubyte  Id[4]            ;
    ALuint   Size                ;
}
WAVChunkHdr_Struct;

ALvoid alutLoadWAVMemory(ALbyte *memory, ALsizei memory_size,ALenum *format, ALvoid **data, ALsizei *size, ALsizei *freq, ALboolean *loop)
{
    WAVChunkHdr_Struct ChunkHdr;
    WAVFmtExHdr_Struct FmtExHdr;
    WAVFileHdr_Struct FileHdr;
    WAVSmplHdr_Struct SmplHdr;
    WAVFmtHdr_Struct FmtHdr;
    ALbyte *Stream;

    *format=0;
    *data=NULL;
    *size=0;
    *freq=0;
    *loop=AL_FALSE;

    if (memory)
    {
        Stream=memory;

        if (Stream)
        {
            memcpy(&FileHdr, Stream, sizeof(WAVFileHdr_Struct));
            Stream+=sizeof(WAVFileHdr_Struct);
            FileHdr.Size=((FileHdr.Size+1)&~1)-4;
            while ((FileHdr.Size!=0)&&(memcpy(&ChunkHdr, Stream, sizeof(WAVChunkHdr_Struct))))
            {
                Stream+=sizeof(WAVChunkHdr_Struct);
                if (!memcmp(ChunkHdr.Id, "fmt ", 4))
                {
                    memcpy(&FmtHdr, Stream, sizeof(WAVFmtHdr_Struct));
                    if (FmtHdr.Format==0x0001)
                    {
                        *format=(FmtHdr.Channels==1? (FmtHdr.BitsPerSample==8?AL_FORMAT_MONO8:AL_FORMAT_MONO16):
                             (FmtHdr.BitsPerSample==8?AL_FORMAT_STEREO8:AL_FORMAT_STEREO16));
                        *freq=FmtHdr.SamplesPerSec;
                        Stream+=ChunkHdr.Size;
                    }
                    else
                    {
                        memcpy(&FmtExHdr, Stream, sizeof(WAVFmtExHdr_Struct));
                        Stream+=ChunkHdr.Size;
                    }
                }
                else if (!memcmp(ChunkHdr.Id, "data", 4))
                {
                    if (FmtHdr.Format==0x0001)
                    {
                        *size=ChunkHdr.Size;
                        *data=malloc(ChunkHdr.Size+31);
                        if (*data) memcpy(*data, Stream, ChunkHdr.Size);
                        memset(((char *)*data)+ChunkHdr.Size, 0, 31);
                        Stream+=ChunkHdr.Size;
                    }
                    else if (FmtHdr.Format==0x0011)
                    {
                        //IMA ADPCM
                    }
                    else if (FmtHdr.Format==0x0055)
                    {
                        //MP3 WAVE
                    }
                }
                else if (!memcmp(ChunkHdr.Id, "smpl", 4))
                {
                    memcpy(&SmplHdr, Stream, sizeof(WAVSmplHdr_Struct));
                    *loop = (SmplHdr.Loops ? AL_TRUE : AL_FALSE);
                    Stream+=ChunkHdr.Size;
                }
                else
                    Stream+=ChunkHdr.Size;
                Stream+=ChunkHdr.Size&1;
                FileHdr.Size-=(((ChunkHdr.Size+1)&~1)+8);
            }
        }
    }
}

ALvoid alutUnloadWAV(ALenum, ALvoid *data, ALsizei, ALsizei)
{
    if (data)
        free(data);
}
//--------------------------------------------------------------------------------------------------
struct OutInterface
{
    void (*Load)(ALbyte *,ALsizei,ALenum *,ALvoid **,ALsizei *,ALsizei *,ALboolean *);
    void (*Clear)(ALenum,ALvoid *,ALsizei,ALsizei);

    void *(*Open)(ALbyte *,ALsizei,ALenum *,ALsizei *,double *);
    void  (*Close)(void *);
    uint  (*Read)(void *,char *,uint);
    void  (*Restart)(void *);
};

static OutInterface out_interface=
{
    alutLoadWAVMemory,
    alutUnloadWAV,

    NULL,
    NULL,
    NULL,
    NULL
};
//--------------------------------------------------------------------------------------------------
const u16char plugin_intro[]=U16_TEXT("WAV音频文件解码(2014-04-09,代码源自ALUT)");

uint32 GetPlugInVersion()
{
    return(2);        //版本号
                    //根据版本号取得不同的API
}

u16char * GetPlugInIntro()
{
    return((u16char *)plugin_intro);
}

bool GetPlugInInterface(uint32 ver,void *data)
{
    if(ver==2)
    {
        memcpy(data,&out_interface,sizeof(OutInterface));
    }
    else
        return(false);

    return(true);
}

static PlugInInterface pii=
{
    nullptr,

    GetPlugInVersion,
    GetPlugInIntro,

    GetPlugInInterface,
    nullptr,

    nullptr,
    nullptr
};

HGL_PLUGIN_FUNC PlugInInterface *InitPlugIn()
{
    return &pii;
}
//--------------------------------------------------------------------------------------------------
