package com.bassmedia;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.un4seen.bass.BASS;
import com.un4seen.bass.BASSMIDI;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BassMusicPlay {
    static private BassMusicPlay instance = null;
    /**
     * 全声道通道
     */
    private int midi = -1;

    /**
     * 音色文件
     */
    int soundFont;

    public static BassMusicPlay getInstance() {
        if (instance == null) {
            instance = new BassMusicPlay();
        }
        return instance;
    }


    public boolean Load(Context context, String pathMusic) {
        // setup recording device (using default device)
        if (mFmlHandler == null)
            mFmlHandler = new FmlHandler(context.getMainLooper());
        if (mSingleExecutor == null)
            mSingleExecutor = Executors.newSingleThreadExecutor();
        if (midi != 0) {
            BASS.BASS_StreamFree(midi);
        }
        if (!BASS.BASS_Init(-1, 44100, 0)) {
            Error("Can't initialize device");
            return false;
        } else {
            //使用音色,需要基于bassmidi配置
            midi = BASSMIDI.BASS_MIDI_StreamCreateFile(pathMusic, 0L, 0L, BASSMIDI.BASS_MIDI_NOSYSRESET, 1);
            if (midi == 0) {
                Error("Can't initialize BASS_StreamCreateFile");
                return false;
            }
//            SetCompletionListener();
            CallPrepareListener();
            return true;
        }
    }

    /**
     * 根据通道设置声音
     *
     * @param track
     * @param volume 0~1 0 = silent, 1.0 = normal/default.
     * @return
     */
    public boolean SetTrackVolume2(int track, float volume) {
        try {
            return BASS.BASS_ChannelSetAttribute(midi, BASSMIDI.BASS_ATTRIB_MIDI_TRACK_VOL + track, volume);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    public float GetTrackVolume(int track) {
        try {
            BASS.FloatValue vol = new BASS.FloatValue();
            BASS.BASS_ChannelGetAttribute(midi, BASSMIDI.BASS_ATTRIB_MIDI_TRACK_VOL + track, vol);
            return vol.value;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }

    }

    /**
     * 加载音色文件，需要在sd卡中
     *
     * @param path
     * @return
     */
    public boolean LoadSoundFont(String path) {
        SetCompletionListener();
        int newfont = BASSMIDI.BASS_MIDI_FontInit(path, 0);
        if (newfont == 0) {
            Log.i("Bass", "Can't load the file");
            return false;
        } else {
            BASSMIDI.BASS_MIDI_FONT[] sf = {new BASSMIDI.BASS_MIDI_FONT()};
            sf[0].font = newfont;
            sf[0].preset = -1; // use all presets
            sf[0].bank = 0; // use default bank(s)
//            BASSMIDI.BASS_MIDI_StreamSetFonts(0, sf, 1); // set default
            BASSMIDI.BASS_MIDI_StreamSetFonts(midi, sf, 1); // set for current
            // // stream too
            BASSMIDI.BASS_MIDI_FontFree(soundFont); // free old soundfont
            soundFont = newfont;
            return true;
        }
    }

    /**
     * 快进或快退到某进度
     *
     * @param position
     */
    public void Seek(long position) {
//        long postion = BASS.BASS_ChannelSeconds2Bytes(midi, second);
        BASS.BASS_ChannelSetPosition(midi, position, BASS.BASS_POS_BYTE);
    }

    /**
     * 全局声音
     *
     * @param volume
     */
    public void SetVolume(float volume) {
        if (volume > 1) {
            volume = 1;
        }
        if (volume < 0) {
            volume = 0;
        }
        BASS.BASS_SetConfig(BASS.BASS_CONFIG_GVOL_STREAM, (int) (volume * 10000));
    }

    /**
     * 是否在播放
     *
     * @return
     */
    public boolean IsPlaying() {
        return (BASS.BASS_ChannelIsActive(midi) == BASS.BASS_ACTIVE_PLAYING);
    }

    /**
     * 是否暂停
     *
     * @return
     */
    public boolean IsPause() {
        return (BASS.BASS_ChannelIsActive(midi) == BASS.BASS_ACTIVE_PAUSED);
    }

    /**
     * 是否暂停
     *
     * @return
     */
    public boolean IsStop() {
        return (BASS.BASS_ChannelIsActive(midi) == BASS.BASS_ACTIVE_STOPPED);
    }
    /**
     *
     * @param speed 1表示原速
     */
    public void setSpeed(float speed){
        BASS.BASS_ChannelSetAttribute(midi, BASSMIDI.BASS_ATTRIB_MIDI_SPEED, speed);
    }
    /**
     * 播放
     */
    public void Play() {
        //设置音分，模拟频率变化
//        for(int k=0; k< 30 ; k++){
//            BASSMIDI.BASS_MIDI_StreamEvent(midi, k, BASSMIDI.MIDI_EVENT_FINETUNE, BASS.Utils.LOWORD(8192 + 643));
//        }
        BASS.BASS_ChannelPlay(midi, false); // play the recorded data
    }

    /**
     * 根据目标hz计算当前音分的偏移值
     * 由于音源sf2为440基准
     * 如果大于440，则为正数
     * 如果小于440，为复数
     * @param targetHz 415 ~ 466
     * @return
     */
    private int calculateFineTune(int targetHz){
        return (int) ((Math.log((double)targetHz / 440d) * 3986 +100) * 8192 / 100);
    }

    /**
     * 设置音分偏移
     * @param trackNum
     * @param targetHz
     */
    public boolean setNoteFineTune(int trackNum, int targetHz){
        return BASSMIDI.BASS_MIDI_StreamEvent(midi, trackNum, BASSMIDI.MIDI_EVENT_FINETUNE, BASS.Utils.LOWORD(calculateFineTune(targetHz)));
    }
    /**
     * 暂停
     */
    public void Pause() {
        BASS.BASS_ChannelPause(midi);
    }

    /**
     * 恢复播放
     */
    public void Resume() {
        BASS.BASS_ChannelPlay(midi, false); // play the recorded data
    }

    /**
     * 停止并释放
     */
    public void Stop() {
        BASS.BASS_ChannelStop(midi);
        BASS.BASS_StreamFree(midi);
        BASS.BASS_Stop();
        BASS.BASS_Free();
    }

    /**
     * 获取当前播放进度，为了追求进度，返回byte位置
     *
     * @return
     */
    public long GetCurrentPosition() {
        return BASS.BASS_ChannelGetPosition(midi, BASS.BASS_POS_BYTE);
    }

    /**
     * 获取总长度，为了追求进度，返回byte位置
     * BASS_ChannelBytes2Seconds 方法会丢失进度
     *
     * @return
     */
    public long GetTotalLength() {
        return BASS.BASS_ChannelGetLength(midi, BASS.BASS_POS_BYTE);
    }

    public double getTotalLength2Second(){
        return BASS.BASS_ChannelBytes2Seconds(midi,  BASS.BASS_ChannelGetLength(midi, BASS.BASS_POS_BYTE));
    }

    /**
     * Handler
     */
    private FmlHandler mFmlHandler;
    /**
     * 创建一个单线程-线程池，用于网络异步加载
     */
    private ExecutorService mSingleExecutor;
    /**
     * 播放/解码完成监听
     */
    private PlayerListener.OnCompletionListener mCompletionListener;
    /**
     * 错误监听
     */
    private PlayerListener.OnErrorListener mErrorListener;
    /**
     * 加载完毕监听
     */
    private PlayerListener.OnPreparedListener mPreparedListener;
    /**
     * 同步调用，channel到了播放（解码）末端时调起
     */
    private final BASS.SYNCPROC mEndSync = new BASS.SYNCPROC() {
        @Override
        public void SYNCPROC(int handle, int channel, int data, Object user) {
            if (mCompletionListener != null)
                mFmlHandler.sendEmptyMessage(FmlHandler.MSG_COMPLETION);
        }
    };
    /**
     * 设置EndSync后得到的对应的句柄，0为设置失败
     */
    private int mEndSyncHandle = 0;

    /**
     * 调用错误监听
     */
    private void CallErrorListener() {
        if (mErrorListener != null) {
            int errorCode = BASS.BASS_ErrorGetCode();
            if (errorCode != 0) {//不成功
                mFmlHandler.obtainMessage(FmlHandler.MSG_ERROR, errorCode, 0).sendToTarget();
            }
        }
    }

    /**
     * 调用预备完毕监听
     */
    private void CallPrepareListener() {
        if (mPreparedListener != null) {
            mFmlHandler.obtainMessage(FmlHandler.MSG_PREPARED).sendToTarget();
        }
    }

    /**
     * 设置播放结束监听
     */
    private void SetCompletionListener() {
        if (mCompletionListener != null) {
            mEndSyncHandle = BASS.BASS_ChannelSetSync(midi, BASS.BASS_SYNC_END, 0, mEndSync, 0);
            if (mEndSyncHandle == 0)
                CallErrorListener();
        }
    }

    /**
     * @param listener
     */
    public void SetOnCompletionListener(PlayerListener.OnCompletionListener listener) {
        this.mCompletionListener = listener;
    }

    public void SetOnErrorListener(PlayerListener.OnErrorListener listener) {
        this.mErrorListener = listener;
    }

    public void SetOnPreparedListener(PlayerListener.OnPreparedListener listener) {
        this.mPreparedListener = listener;
    }


    // display error messages
    void Error(String es) {
        // get error code in current thread for display in UI thread
        String s = String.format("%s\n(error code: %d)", es, BASS.BASS_ErrorGetCode());
        Log.e("BassMusicPlay", s);
    }

    private class FmlHandler extends Handler {
        public static final int MSG_ERROR = 0x01;
        public static final int MSG_PREPARED = MSG_ERROR + 0x02;
        public static final int MSG_COMPLETION = MSG_PREPARED + 0x02;

        public FmlHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_ERROR:
                    if (mErrorListener != null)
                        mErrorListener.onError(BassMusicPlay.this, msg.arg1);
                    break;
                case MSG_PREPARED:
                    if (mPreparedListener != null)
                        mPreparedListener.OnPrepared(BassMusicPlay.this);
                    break;
                case MSG_COMPLETION:
                    if (mCompletionListener != null)
                        mCompletionListener.onCompletion(BassMusicPlay.this);
                    break;
            }
        }
    }
}
