/*
 * @Copyright (c) Huawei Technologies Co., Ltd. 2022-2024. All rights reserved.
 */

/**
 * @file
 * The file declars the MP4Parser class.
 */
package mp4parser


/**
 * The class is MP4Parser
 * @author fiture
 * @since 0.32.5
 */
public class MP4Parser {

    /**
     * The Function is init constructor
     *
     * @since 0.32.5
     */
    public init() {}

    private var files = FileUtils()

    /**
     * The Function is videoClip
     *
     * @param startTime of String
     * @param endTime of String
     * @param sourcePath of String
     * @param outPath of String
     * @since 0.32.5
     */
    public func videoClip(startTime: String, endTime: String, sourcePath: String, outPath: String): Int32 {
        let fileClip1 = files.isFilePathValid(sourcePath)
        let fileClip2 = files.isFilePathValid(outPath)
        if(fileClip1[1] != "mp4") {
            throw Exception("${fileClip1[1]}" + " file format is not mp4")
        }
        if(fileClip2[1] != "mp4") {
            throw Exception("${fileClip2[1]}" + " file format is not mp4")
        }
        try {
            spawn {
                ffmpeg_exec("ffmpeg -y" + " -ss " + startTime + " -i " + fileClip1[0] + " -t " + endTime + " -c copy " + fileClip2[0] + " -y")
            }
            return 1
        } catch (e: Exception) {
            return 0
        }
    }

    /**
     * The Function is videoMultMerge
     *
     * @param sourcePath of String
     * @param outPath of String
     * @since 0.32.5
     */
    public func videoMultMerge(sourcePath: String, outPath: String): Int32 {
        let filename1 = files.isFilePathValid(sourcePath)
        let filename2 = files.isFilePathValid(outPath)
        if(filename1[1] != "txt") {
            throw Exception("${filename1[1]}" + " file format is not txt")
        }
        if(filename2[1] != "mp4") {
            throw Exception("${filename2[1]}" + " file format is not mp4")
        }
        try {
            spawn {
                ffmpeg_exec("ffmpeg -f concat -i " + filename1[0] + " -c copy " + filename2[0] + " -y")
            }
            return 1
        } catch (e: Exception) {
            return 0
        }
    }

    /**
     * The Function is videoMerge
     *
     * @param sourcePath of String
     * @param outPath of String
     * @since 0.32.5
     */
    public func videoMerge(sourcePath: String, outPath: String): Int32 {
        let fileMerge1 = files.isFilePathValid(sourcePath)
        let fileMerge2 = files.isFilePathValid(outPath)
        if(fileMerge1[1] != "mp4") {
            throw Exception("${fileMerge1[1]}" + " file format is not mp4")
        }
        if(fileMerge2[1] != "mp4") {
            throw Exception("${fileMerge2[1]}" + " file format is not mp4")
        }
        try {
            spawn {
                ffmpeg_exec("ffmpeg -i " + fileMerge1[0] + " -c copy " + fileMerge2[0] + " -y")
            }
            return 1
        } catch (e: Exception) {
            return 0
        }
    }

    /**
     * The Function is audioMultMerge
     *
     * @param sourcePath of String
     * @param outPath of String
     * @since 0.32.5
     */
    public func audioMultMerge(sourcePath: String, outPath: String): Int32 {
        let multMerge1 = files.isFilePathValid(sourcePath)
        let multMerge2 = files.isFilePathValid(outPath)
        if(multMerge1[1] != "txt") {
            throw Exception("${multMerge1[1]}" + " file format is not txt")
        }
        if(multMerge2[1] != "mp3") {
            throw Exception("${multMerge2[1]}" + " file format is not mp3")
        }
        try {
            spawn {
                ffmpeg_exec("ffmpeg -f concat -i " + multMerge1[0] + " -c copy " + multMerge2[0] + " -y")
            }
            return 1
        } catch (e: Exception) {
            return 0
        }
    }

    /**
     * The Function is audioMerge
     *
     * @param sourcePath of String
     * @param outPath of String
     * @since 0.32.5
     */
    public func audioMerge(sourcePath: String, outPath: String): Int32 {
        let audioMerge1 = files.isFilePathValid(sourcePath)
        let audioMerge2 = files.isFilePathValid(outPath)
        if(audioMerge1[1] != "mp3") {
            throw Exception("${audioMerge1[1]}" + " file format is not mp3")
        }
        if(audioMerge2[1] != "mp3") {
            throw Exception("${audioMerge2[1]}" + " file format is not mp3")
        }
        try {
            spawn {
                ffmpeg_exec("ffmpeg -i " + audioMerge1[0] + " -c copy " + audioMerge2[0] + " -y")
            }
            return 1
        } catch (e: Exception) {
            return 0
        }
    }

    /**
     * The Function is audioClip
     *
     * @param startTime of String
     * @param endTime of String
     * @param sourcePath of String
     * @param outPath of String
     * @since 0.32.5
     */
    public func audioClip(startTime: String, endTime: String, sourcePath: String, outPath: String): Int32 {
        let audio1 = files.isFilePathValid(sourcePath)
        let audio2 = files.isFilePathValid(outPath)
        if(audio1[1] != "mp3") {
            throw Exception("${audio1[1]}" + " file format is not mp3")
        }
        if(audio2[1] != "mp3") {
            throw Exception("${audio2[1]}" + " file format is not mp3")
        }
        try {
            spawn {
                ffmpeg_exec("ffmpeg -y -i " + audio1[0] + " -ss " + startTime + " -t " + endTime + " -c copy " + audio2[0] + " -y")
            }
            return 1
        } catch (e: Exception) {
            return 0
        }
    }
}

/*
 * The Function is c_ffmpeg_exec
 *
 * @param str of CString
 *
 * @return Type of Int32
 * @since 0.32.5
 */
foreign func create_string(size: Int32): CPointer<CString>
foreign func exec_input(size: Int32,str: CPointer<CString>): Int32
foreign func free_string_array(size: Int32,str: CPointer<CString>): Unit

/**
 * The Function is ffmpeg_exec
 *
 * @param str of String
 *
 * @return Type of Int32
 * @since 0.32.5
 */
func ffmpeg_exec(str: String): Int32 {
    let arr = str.split(" ")
    unsafe {
        let ptr = create_string(Int32(arr.size))
        for (i in 0..arr.size) {
            ptr.write(i, LibC.mallocCString(arr[i]))
        }
        var ret = exec_input(Int32(arr.size),ptr)
        free_string_array(Int32(arr.size),ptr)
        return ret
    }
}