package cn.tee3.avd;
/**
 * Created by ming.ren on 2017/1/12.
 */
import java.io.File;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Nullable;

/**
 * 本地录制天模块接口.
 *
 * 本地录制。
 */
public class MLocalRecord extends Module {
    private static final String TAG = "MLocalRecord";

    /**
     * 录制中录制音视频流回调接口.
     */
    public static interface StreamOutListener {
        /** 视频流回调接口
         *
         * @param[in] recId 录制Id。
         * @param[in] timestamp_ns 时间戳, nanos second
         * @param[in] w 图像宽度
         * @param[in] h 图像高度
         * @param[in] data 图像内容数据指针
         * @param[in] len  图像内容大小
         * @note 视频流的数据格式为h264或者vp8等编码后格式，具体由视频发布端发布时确定。
         * @sa avd_localrecord_createRecorder
         */
        public void videoStreamOut(String recId, long timestamp_ns, int w, int h, boolean isKeyFrame, byte[] data, int len);
        /** 音频流回调接口
         *
         * @param[in] recId 录制Id。
         * @param[in] timestamp_ns 时间戳, nanos second。
         * @param[in] sampleRate 音频采样率
         * @param[in] channels 音频采集通道数
         * @param[in] data 音频内容数据指针
         * @param[in] len  音频内容大小
         * @note 音频流的数据格式为PCM 16位。
         * @sa avd_localrecord_createRecorder
         */
        public void audioStreamOut(String recId, long timestamp_ns, int sampleRate, int channels, byte[] data, int len);
    }

    ///
    /** 获取房间内本地录制模块接口
     *
     * @param[in] room 房间对象。
     * @return 本地录制模块接口。
     * @sa Room
     */
    @Nullable public static MLocalRecord getRecord(Room room) {
        return (MLocalRecord)room.getModule(Type.localrecord);
    }
	private boolean invaldString(String value){
        if (value == null || value.isEmpty() || value.equals("")){
           return true;
        }
        return  false;
    }
    protected MLocalRecord(Room room) {
        super(room, Type.localrecord, room.nativegetMLocalRecord());
        recId2StreamOuts = new LinkedHashMap<String, Long>();
        Tlog.d(TAG, "MLocalRecord, nativeLocalRecord:" + this.nativeobj);
    }
    @Override
    protected void dispose() {
        this.nativeobj = 0;
        Tlog.i(TAG, "dispose, no free streamouts:"+this.recId2StreamOuts.size());
    }

    private Map<String, Long> recId2StreamOuts;
    /** 创建一个录制容器
     *
     * @param[in] out 录制内容输出接口指针。
     * @param[in] inputRecorderId 外部分配录制ID，必须保证房间内该录制模块中具有唯一性，如果是null或""将内部分配一个UUID，并通过return 返回。
     * @param[in] continueDecode SDK是否继续内部解码（若要用SDK内部的视频渲染等功能，则需要解码）。
     * @return 有效的本地录制ID，如果返回null或者""，标示创建失败。
     */
    public String createRecorder2(StreamOutListener out, String inputRecorderId, boolean continueDecode) {
        Tlog.i(TAG,"createRecorder2, out:"+out+" inputRecorderId:"+inputRecorderId+" continueDecode:"+continueDecode);
        if (null == out) {
            Tlog.e(TAG, "createRecorder2, out is null, failed");
            return "";
        }
        long nativestreamout = nativeCreateStreamOutListener(out);
        if (0 == nativestreamout) {
            Tlog.e(TAG, "createRecorder2, nativeCreateStreamOutListener failed");
            return "";
        }
        if (invaldString(inputRecorderId)){
            Tlog.i(TAG,"createRecorder2, inputRecorderId is invalid,so create a uuid .");
            inputRecorderId = UUID.randomUUID().toString();
        }
        int rv = nativecreateRecorder2(nativestreamout, inputRecorderId, continueDecode);
        if (rv == 0){
            recId2StreamOuts.put(inputRecorderId, nativestreamout);
            return  inputRecorderId;
        }
        nativeFreeStreamOutListener(nativestreamout);
        Tlog.e(TAG, "createRecorder2, nativecreateRecorder2 failed, rv="+rv);
        return "";
    }

    /** 创建一个录制容器
     *
     * @param[in] filePath 录制文件地址。
     * @param[in] inputRecorderId 外部分配录制ID，必须保证房间内该录制模块中具有唯一性，如果是null或""将内部分配一个UUID，并通过return 返回。
     * @return 有效的本地录制ID，如果返回null或者""，标示创建失败。
     */
     public String createRecorder(String filePath, String inputRecorderId) {
        Tlog.i(TAG,"createRecorder, filePath:"+filePath+" inputRecorderId:"+inputRecorderId);
        if (invaldString(filePath)){
            Tlog.e(TAG,"createRecorder, filePath is invalid .");
            return "";
        }
        File destFile = new File(filePath);
        if (!destFile.exists()) {
            File dirParent = new File(destFile.getParent());
            if(!dirParent.mkdirs() && !dirParent.isDirectory()){
                Tlog.e(TAG,"create directory error,dir: " + destFile.getParent());
                return "";
            }
            try{
                destFile.createNewFile();
            }catch (IOException e) {
                Tlog.e(TAG,"create file error,IOException: " + e.toString());
                return "";
            }
        }else if (destFile.isDirectory()){
            Tlog.e(TAG,"file path already exists,but it's a directory.");
            return "";
        }

        if (invaldString(inputRecorderId)){
            Tlog.i(TAG,"createRecorder, inputRecorderId is invalid,so create a uuid .");
            inputRecorderId = UUID.randomUUID().toString();
        }
        int rv = nativecreateRecorder(filePath, inputRecorderId);
        if (rv == 0){
            return  inputRecorderId;
        }
        Tlog.e(TAG, "createRecorder failed, return empty string .");
        return "";
    }

	/** 为录制容器选择房间内的某路视频
     *
     * @param[in] recorderId 录制ID。
     * @param[in] deviceId 视频所对应的设备ID。
     *
     * @return 返回错误代码。
     */
    public int selectVideo4Recorder(String recorderId, String deviceId){
        Tlog.i(TAG,"selectVideo4Recorder, recorderId:"+recorderId+" deviceId:"+deviceId);
        if (invaldString(recorderId)){
            Tlog.e(TAG,"selectVideo4Recorder, recorderId is invalid.");
            return -1;
        }
        if (invaldString(deviceId)){
            Tlog.e(TAG,"selectVideo4Recorder, deviceId is invalid.");
            return -1;
        }

        return  nativeselectVideo4Recorder(recorderId, deviceId);
    }

    /** 为录制容器选择房间内的某路音频
     *
     * @param[in] recorderId 录制ID。
     * @param[in] userId 音频所属的用户ID。
     *
     * @return 返回错误代码。
     */
    public int selectAudio4Recorder(String recorderId, String userId){
        Tlog.i(TAG,"selectAudio4Recorder, recorderId:"+recorderId+" userId:"+userId);
        if (invaldString(recorderId)){
            Tlog.e(TAG,"selectAudio4Recorder, recorderId is invalid.");
            return -1;
        }

        return  nativeselectAudio4Recorder(recorderId, userId);
    }

    /** 为某个录制容器选择录制房间内的所有音频
     *
     * @param[in] recorderId 录制ID。
     *
     * @return 返回错误代码。
     */
    public int selectAllAudio4Recorder(String recorderId){
        Tlog.i(TAG,"selectAllAudio4Recorder, recorderId:"+recorderId);
        if (invaldString(recorderId)){
            Tlog.e(TAG,"selectAllAudio4Recorder, recorderId is invalid.");
            return -1;
        }
        return  nativeselectAllAudio4Recorder(recorderId);
    }

    /** 为某个录制容器选择录制房间内的除了我自己外的所有音频
     *
     * @param[in] recorderId 录制ID。
     *
     * @return 返回错误代码。
     */
    public int selectAllAudioWithoutMe4Recorder(String recorderId) {
        Tlog.i(TAG,"selectAllAudioWithoutMe4Recorder, recorderId:"+recorderId);
        if (invaldString(recorderId)){
            Tlog.e(TAG,"selectAllAudioWithoutMe4Recorder, recorderId is invalid.");
            return -1;
        }
        return  nativeselectAllAudioWithoutMe4Recorder(recorderId);
    }

    /** 停止该录制模块中的某个录制
     *
     * @param[in] recorderId 录制ID。
     *
     * @return 返回消息列表。
     */
    public int stopRecorder(String recorderId){
        Tlog.i(TAG,"stopRecorder, recorderId:"+recorderId);
        if (invaldString(recorderId)){
            Tlog.e(TAG,"stopRecorder, recorderId is invalid.");
            return -1;
        }

        int ret = nativestopRecorder(recorderId);
        if (!recId2StreamOuts.containsKey(recorderId)) {
            return ret;
        }
        long nativestreamout = recId2StreamOuts.get(recorderId);
        if (0 != nativestreamout) {
            nativeFreeStreamOutListener(nativestreamout);
        }
        recId2StreamOuts.remove(recorderId);
        return ret;
    }

    /** 停止该录制模块中所有录制
     *
     * @return 返回错误代码。
     */
    public int stopRecorderAll(){
        Tlog.i(TAG,"stopRecorderAll");
        int ret = nativestopRecorderAll();
        for (Map.Entry<String, Long> entry : recId2StreamOuts.entrySet()) {
            nativeFreeStreamOutListener(entry.getValue());
        }
        recId2StreamOuts.clear();
        return ret;
    }
    /// native function
    private native int nativecreateRecorder (String filePath, String recorderId);
	private native int nativeselectVideo4Recorder(String recorderId, String deviceId);
	private native int nativeselectAudio4Recorder(String recorderId, String userId);
	private native int nativeselectAllAudio4Recorder(String recorderId);
    private native int nativeselectAllAudioWithoutMe4Recorder(String recorderId);
	private native int nativestopRecorder(String recorderId);
	private native int nativestopRecorderAll();
    //
    private static native long nativeCreateStreamOutListener(StreamOutListener listener);
    private static native void nativeFreeStreamOutListener(long nativeListener);
    private native int  nativecreateRecorder2(long nativeListener, String recorderId, boolean continueDecode);
}
