#include<hgl/audio/AudioPlayer.h>
#include<hgl/log/LogInfo.h>
#include<hgl/plugin/PlugIn.h>
#include<hgl/Time.h>
#include<hgl/io/MemoryInputStream.h>
#include<hgl/io/FileInputStream.h>
#include"AudioDecode.h"

namespace hgl
{
    const os_char *GetAudioDecodeName(const AudioFileType aft);

    void AudioPlayer::InitPrivate()
    {
        if(!alGenSources)
        {
            LOG_ERROR(OS_TEXT("OpenAL/EE 还未初始化!"));
            return;
        }

        auto_gain.open=false;

        audio_ptr=nullptr;

        audio_data=nullptr;
        audio_data_size=0;

        audio_buffer=nullptr;
        audio_buffer_size=0;

        decode=nullptr;

        ps=PlayState::None;

        total_time=0;

        if(!audiosource.Create())return;

        audiosource.SetLoop(false);

        source=audiosource.index;

        alGenBuffers(3,buffer);
    }

    AudioPlayer::AudioPlayer()
    {
        InitPrivate();
    }

    AudioPlayer::AudioPlayer(const os_char *filename,AudioFileType aft)
    {
        InitPrivate();

        if(filename)
            Load(filename,aft);
    }

    AudioPlayer::AudioPlayer(InputStream *stream,int size,AudioFileType aft)
    {
        InitPrivate();

        Load(stream,size,aft);
    }

//     AudioPlayer::AudioPlayer(HAC *hac,const os_char *filename,AudioFileType aft)
//     {
//         InitPrivate();
//
//         Load(hac,filename,aft);
//     }

    AudioPlayer::~AudioPlayer()
    {
        SAFE_CLEAR(decode);

        if(!audio_data)return;

        Clear();

        alDeleteBuffers(3,buffer);

        SAFE_CLEAR_ARRAY(audio_buffer);
    }

    bool AudioPlayer::Load(AudioFileType aft)
    {
        const os_char *plugin_name=GetAudioDecodeName(aft);

        if(!plugin_name)return(false);

        decode=new AudioPlugInInterface;

        if (!GetAudioInterface(plugin_name, decode, nullptr))
        {
            delete decode;
            decode=nullptr;

            LOG_ERROR(OS_TEXT("无法加载音频解码插件：")+OSString(plugin_name));
            return(false);
        }

        {
            audio_ptr=decode->Open(audio_data,audio_data_size,&format,&rate,&total_time);

            audio_buffer_size=(AudioTime(format,rate)+9)/10;        // 1/10 秒

            if(audio_buffer)
                delete[] audio_buffer;

            audio_buffer=new char[audio_buffer_size];

            wait_time=0.1;

            if(wait_time>total_time/3.0f)
                wait_time=total_time/10.0f;

            return(true);
        }
    }

    /**
    * 从流中加载音频数据,仅支持OGG
    * @param stream 要加载数据的流
    * @param size 音频数据长度
    * @param aft 音频文件类型
    * @return 是否加载成功
    */
    bool AudioPlayer::Load(InputStream *stream,int size,AudioFileType aft)
    {
        if(!alGenBuffers)return(false);
        if(!stream)return(false);
        if(size<=0)return(false);

        Clear();

        if(!RangeCheck(aft))
        {
            LOG_ERROR(OS_TEXT("未支持的音频文件类型！AudioFileType: ")+OSString::valueOf((int)aft));

            return(false);
        }
        else
        {
            audio_data=new ALbyte[size];

            stream->Read(audio_data,size);

            audio_data_size=size;
            return Load(aft);
        }
    }

    /**
    * 从文件中加载一段音频数据
    * @param filename 音频文件名称
    * @param aft 音频文件类型
    * @return 是否加载成功
    */
    bool AudioPlayer::Load(const os_char *filename,AudioFileType aft)
    {
        if(!alGenBuffers)return(false);
        if(!filename||!(*filename))return(false);

        if(!RangeCheck(aft))
            aft=CheckAudioFileType(filename);

        if(!RangeCheck(aft))
        {
            LOG_ERROR(OS_TEXT("未知的音频文件类型！AudioFile: ")+OSString(filename));
            return(false);
        }

        OpenFileInputStream fis(filename);

        return(Load(fis,fis->Available(),aft));
    }

//     /**
//     * 从文件中加载一段音频数据
//     * @param hac HAC包指针
//     * @param filename 音频文件名称
//     * @param aft 音频文件类型
//     * @return 是否加载成功
//     */
//     bool AudioPlayer::Load(HAC *hac,const os_char *filename,AudioFileType aft)
//     {
//         if(!alGenBuffers)return(false);
//
//         os_char *ext;
//         Stream *stream;
//         bool result;
//
//         ext=strrchr(filename,u'.');
//
//         LowerString(ext);
//
//         if(aft<=aftNone||aft>=aftEnd)
//         {
//             if(strcmp(ext,u".ogg")==0)aft=aftOGG;else
//             {
//                 PutError(u"未支持的音频文件类型！AudioFileType:%d",aft);
//                 return(false);
//             }
//         }
//
//         stream=hac->LoadFile(filename);
//
//         if(stream)
//         {
//             result=Load(stream,aft);
//
//             delete stream;
//
//             return(result);
//         }
//
//         return(false);
//     }

    void AudioPlayer::Clear()
    {
        Stop();

        if(decode&&audio_ptr)
            decode->Close(audio_ptr);

        SAFE_CLEAR_ARRAY(audio_data);
        SAFE_CLEAR_ARRAY(audio_buffer);

        audio_ptr=nullptr;

        total_time=0;
    }

    bool AudioPlayer::IsLoop()
    {
        lock.Lock();
        bool rv=loop;
        lock.Unlock();

        return(rv);
    }

    void AudioPlayer::SetLoop(bool val)
    {
        lock.Lock();
        loop=val;
        lock.Unlock();
    }

    bool AudioPlayer::ReadData(ALuint n)
    {
        if(!decode)return(false);

        uint size;

        size=decode->Read(audio_ptr,audio_buffer,audio_buffer_size);

        if(size)
        {
            alBufferData(n,format,audio_buffer,size,rate);

            if(alLastError())return(false);

            return(true);
        }

        return(false);
    }

    bool AudioPlayer::Playback()
    {
        if(!audio_data)return(false);
        if(!decode)return(false);

        alSourceStop(source);
        ClearBuffer();
        decode->Restart(audio_ptr);

        int count=0;

        audio_buffer_count=0;

        if(ReadData(buffer[0]))
        {
            count++;

            if(ReadData(buffer[1]))                //以免有些音效太短，在这里直接失败
                count++;

            if(ReadData(buffer[2]))                //以免有些音效太短，在这里直接失败
                count++;

            alSourceQueueBuffers(source,count,buffer);
            alSourcePlay(source);
            start_time=GetDoubleTime();

            ps=PlayState::Play;
            return(true);
        }
        else
        {
            ps=PlayState::Exit;

            return(false);
        }
    }

    /**
    * 开始播放
    * @param _loop 是否循环播放
    */
    void AudioPlayer::Play(bool _loop)
    {
        if(!audio_data)return;

        lock.Lock();

        loop=_loop;

        if(ps==PlayState::None||ps==PlayState::Pause)      //未启动线程
            Start();

        Playback();            //Execute执行有检测Lock，所以不必担心该操作会引起线程冲突

        lock.Unlock();
    }

    /**
    * 停止播放
    */
    void AudioPlayer::Stop()
    {
        if(!audio_data)return;

        bool thread_is_live=true;

        lock.Lock();

        if(Thread::IsLive())
            ps=PlayState::Exit;
        else
            thread_is_live=false;

        lock.Unlock();

        if(thread_is_live)
            Thread::WaitExit();

        ps=PlayState::None;
    }

    /**
    * 暂停播放
    */
    void AudioPlayer::Pause()
    {
        if(!audio_data)return;

        lock.Lock();

        if(ps==PlayState::Play)
            ps=PlayState::Pause;

        lock.Unlock();
    }

    /**
    * 继续播放
    */
    void AudioPlayer::Resume()
    {
        if(!audio_data)return;

        lock.Lock();

        if(ps==PlayState::Pause)
        {
            ps=PlayState::Play;

            Thread::Start();
        }

        lock.Unlock();
    }

    bool AudioPlayer::UpdateBuffer()
    {
        int processed=0;
        bool active=true;

        alGetSourcei(source,AL_BUFFERS_PROCESSED,&processed);        //取得处理结束的缓冲区数量

        if(processed<=0)return(true);

        const double cur_time=GetDoubleTime();

        if(cur_time-start_time<fade_in_time)        //淡入时间
        {
            audiosource.SetGain(((cur_time-start_time)/fade_in_time)*gain);
        }
        else
        if(cur_time-start_time>total_time-fade_out_time)    //淡出时间
        {
            audiosource.SetGain(((total_time-(cur_time-start_time))/fade_out_time)*gain);
        }

        if(auto_gain.open)
        {
            if(cur_time>=auto_gain.end.time)
            {
                auto_gain.open=false;

                SetGain(auto_gain.end.gain);

                if(auto_gain.end.gain<=0)
                    ps=PlayState::Exit;
            }
            else
            {
                SetGain(auto_gain.start.gain+auto_gain.gap*((cur_time-auto_gain.start.time)/auto_gain.time));
            }
        }

        while(processed--)
        {
            ALuint buffer;

            audio_buffer_count+=audio_buffer_size;

            alSourceUnqueueBuffers(source,1,&buffer);       //解除一个已处理完成的缓冲区
            alLastError();

            active=ReadData(buffer);                        //解码数据到这个缓冲区

            if(active)
            {
                alSourceQueueBuffers(source,1,&buffer);     //重新将这个缓冲区加入队列
                alLastError();
            }
            else
                return(false);
        }

        return(true);
    }

    void AudioPlayer::ClearBuffer()
    {
        int queued;
        ALuint buffer;

        alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);

        while(queued--)
            alSourceUnqueueBuffers(source, 1, &buffer);
    }

    bool AudioPlayer::Execute()
    {
        if(!audio_data)return(false);

        while(true)
        {
            lock.Lock();

            if(ps==PlayState::Play)    //被要求播放
            {
                if(!UpdateBuffer())
                {
                    if(loop)        //被要求循环播放
                    {
                        if(GetSourceState()!=AL_STOPPED)               //等它放完
                            Playback();
                    }
                    else
                    {
                        //退出
                        lock.Unlock();

                        ps=PlayState::None;
                        return(false);
                    }
                }
                else
                {
                    if(GetSourceState()!=AL_PLAYING)
                        alSourcePlay(source);
                }
            }
            else
            if(ps==PlayState::Pause)        //被要求暂停
            {
                alSourcePause(source);

                lock.Unlock();
                return(false);
            }
            else
            if(ps==PlayState::Exit)      //被要求暂停或退出
            {
                alSourceStop(source);
                alSourcei(source,AL_BUFFER,0);
                ClearBuffer();

                lock.Unlock();
                return(false);
            }

            lock.Unlock();

            WaitTime(wait_time);      //以让线程空出CPU时间片
        }
    }

    double AudioPlayer::GetPlayTime()
    {
        if(!audio_data)return(0);

        uint base=audio_buffer_count;
        int off;

        lock.Lock();

        alGetSourcei(source,AL_BYTE_OFFSET,&off);

        lock.Unlock();

        return AudioDataTime(base+off,format,rate);
    }

    /**
    * 自动调整增益
    * @param target_gain 目标增益
    * @param adjust_time 到达目标增益要经过的时间
    * @param cur_time 当前时间
    */
    void AudioPlayer::AutoGain(float target_gain,double adjust_time,const double cur_time)
    {
        if(!audio_data)return;

        lock.Lock();
            auto_gain.start.gain=GetGain();
            auto_gain.start.time=cur_time;
            auto_gain.end.gain=target_gain;
            auto_gain.end.time=auto_gain.start.time+adjust_time;

            auto_gain.time=adjust_time;
            auto_gain.gap=target_gain-auto_gain.start.gain;

            auto_gain.open=true;
        lock.Unlock();
    }

    void AudioPlayer::SetFadeTime(double in,double out)
    {
        fade_in_time=in;
        fade_out_time=out;
    }
}//namespace hgl
