var request = require('request');
var fs = require('fs');
var ffmpeg = require('fluent-ffmpeg');
var ljConst = require("../common/LjConst.js");
var path = require('path');
var logHelper = require("./LjLogHelper");
var apiHelper = require("../helper/LjApiHelper");
var httpHelper = require("../helper/LjHttpHelper");
var os = require('os');


/**
 * The helper of file
 */
class LjFileHelper
{
    /**
     * Download file
     * @param fileUrl the file url
     * @returns {boolean}
     */
    static downloadFile(fileUrl, opt)
    {
        if(fileUrl == null || fileUrl=="")
        {
            return "";
        }

        //获取文件属性对象
        var filePropObj = this.getFileProperty(fileUrl);
        if (filePropObj == null)
        {
            return false;
        }

        //视频处理
        if (filePropObj.fileType == ljConst.VIDEO_TYPE_M3U8)
        {
            //未加密视频本地存储路径
            var localFileDir = filePropObj.folderDir + filePropObj.fileName + ".mp4"

            //M3U8视频转换MP4
            ffmpeg(fileUrl).format(ljConst.VIDEO_TYPE_MP4)
                .on('start', function (err)
                {
                    logHelper.info("【"+opt.lessonId+"】","Starting down video:" + fileUrl);
                })
                .on('error', function (err)
                {
                    logHelper.error("【"+opt.lessonId+"】","Failed to down video[" + fileUrl + "]: " + err.message);
                })
                .on('end', function ()
                {
                    //加密视频存储路径
                    let localFileDirNew = filePropObj.folderDir + filePropObj.fileName + "_new" + ".mp4"
                    logHelper.info("【"+opt.lessonId+"】","Succeeded to down video：" + localFileDirNew);

                    //加密存储
                    LjFileHelper.writeEncryptedStream(localFileDir, localFileDirNew, function ()
                    {
                        LjFileHelper.updateDownloadResSize(opt);
                    });

                    //删除文件（加密存储完成后删除未加密文件）
                    fs.unlink(localFileDir, function (err)
                    {
                        if (err)
                        {
                            //删除失败
                            logHelper.error("【"+opt.lessonId+"】","Failed to delete video[" + err.message + "]：" + localFileDir);
                            throw err;
                        }
                        else
                        {
                            logHelper.info("【"+opt.lessonId+"】",'Succeeded to delete video：' + localFileDir)
                        }
                    })
                })
                .save(localFileDir);
        }//有声读物处理
        else if (filePropObj.fileType == ljConst.VIDEO_TYPE_MP3)
        {
            //未加密有声读物本地存储地址
            var localFileDir = filePropObj.folderDir + filePropObj.fileName + "." + filePropObj.fileType;

            //读取有声读物
            request(fileUrl).pipe(fs.createWriteStream(localFileDir)).on('close', function ()
            {
                //加密有声读物存储地址
                var localFileDirNew = filePropObj.folderDir + filePropObj.fileName + "_new." + filePropObj.fileType;
                logHelper.info("【"+opt.lessonId+"】","Succeeded to down audio：" + localFileDirNew);

                //加密有声读物
                LjFileHelper.writeEncryptedStream(localFileDir, localFileDirNew, function ()
                {
                    /*//获取文件基本信息
                    fs.stat(localFileDirNew, function (err, stats)
                    {
                        if (err == null)
                        {
                            //文件大小
                            var fileSize = stats.size;
                            LjFileHelper.updateDownloadResSize(opt);
                            logHelper.info("Succeeded to encrypt audio：" + localFileDirNew + " with file size[" + fileSize + "]");
                        }
                    });*/
                    LjFileHelper.updateDownloadResSize(opt);
                });

                //删除文件（加密存储完成后删除未加密文件）
                fs.unlink(localFileDir, function (err)
                {
                    if (err)
                    {
                        //删除失败
                        logHelper.erro("【"+opt.lessonId+"】","Failed to delete audio[" + err.message + "]：" + localFileDir);
                        throw err;
                    }
                    else
                    {
                        logHelper.info("【"+opt.lessonId+"】",'Succeeded to delete audio：' + localFileDir)
                    }
                })
            });
        }//图片处理
        else
        {
            //未加密图片本地存储地址
            var localFileDir = filePropObj.folderDir + filePropObj.fileName + "." + filePropObj.fileType;

            //读取图片
            request(fileUrl).pipe(fs.createWriteStream(localFileDir)).on('close', function ()
            {
                //加密图片存储地址
                var localFileDirNew = filePropObj.folderDir + filePropObj.fileName + "_new." + filePropObj.fileType;
                logHelper.info("【"+opt.lessonId+"】","Succeeded to down image：" + localFileDirNew);

                //加密图片
                LjFileHelper.writeEncryptedStream(localFileDir, localFileDirNew, function ()
                {
                   /* //获取文件基本信息
                    fs.stat(localFileDirNew, function (err, stats)
                    {
                        if (err == null)
                        {
                            //文件大小
                            var fileSize = stats.size;
                            LjFileHelper.updateDownloadResSize(opt);

                            logHelper.info("Succeeded to encrypt image：" + localFileDirNew + " with file size[" + fileSize + "]");
                        }
                    });*/
                    LjFileHelper.updateDownloadResSize(opt);
                });


                //删除文件（加密存储完成后删除未加密文件）
                fs.unlink(localFileDir, function (err)
                {
                    if (err)
                    {
                        //删除失败
                        logHelper.error("【"+opt.lessonId+"】","Failed to delete image[" + err.message + "]：" + localFileDir);
                        throw err;
                    }
                    else
                    {
                        logHelper.info("【"+opt.lessonId+"】",'Succeeded to delete image：' + localFileDir)
                    }
                })
            });
        }
    }

    /**
     * Delete file
     * @param fileUrl the file url
     * @returns {boolean}
     */
    static delFile(fileUrl)
    {
        //获取文件属性对象
        var filePropObj = this.getFileProperty(fileUrl);
        if (filePropObj == null)
        {
            return false;
        }
        //视频处理
        if (filePropObj.fileType == ljConst.VIDEO_TYPE_M3U8)
        {
            //加密视频存储路径
            let localFileDirNew = filePropObj.folderDir + filePropObj.fileName + "_new" + ".mp4"

            //删除加密文件
            fs.unlink(localFileDirNew, function (err)
            {
                if (err)
                {
                    //删除失败
                    logHelper.info("Failed to delete video[" + err.message + "]：" + localFileDir);
                    throw err;
                }
                else
                {
                    logHelper.info('Succeeded to delete video：' + localFileDir)
                }
            })
        }//有声读物处理
        else if (filePropObj.fileType == ljConst.VIDEO_TYPE_MP3)
        {
            //未加密有声读物本地存储地址
            var localFileDir = filePropObj.folderDir + filePropObj.fileName + "." + filePropObj.fileType;

            //读取有声读物
            request(fileUrl).pipe(fs.createWriteStream(localFileDir)).on('close', function ()
            {
                //加密有声读物存储地址
                var localFileDirNew = filePropObj.folderDir + filePropObj.fileName + "_new." + filePropObj.fileType;

                //删除文件（加密存储完成后删除未加密文件）
                fs.unlink(localFileDirNew, function (err)
                {
                    if (err)
                    {
                        //删除失败
                        logHelper.erro("【"+opt.lessonId+"】","Failed to delete audio[" + err.message + "]：" + localFileDir);
                        throw err;
                    }
                    else
                    {
                        logHelper.info("【"+opt.lessonId+"】",'Succeeded to delete audio：' + localFileDir)
                    }
                })
            });
        }//图片处理
        else
        {
            //加密图片存储地址
            var localFileDirNew = filePropObj.folderDir + filePropObj.fileName + "_new." + filePropObj.fileType;

            //删除加密文件
            fs.unlink(localFileDirNew, function (err)
            {
                if (err)
                {
                    //删除失败
                    logHelper.erro("Failed to delete image[" + err.message + "]：" + localFileDir);
                    throw err;
                }
                else
                {
                    logHelper.info('Succeeded to delete image：' + localFileDir)
                }
            })
        }
    }

    /**
     * Gets file directory
     * @param fileName the file name
     * @returns {*|string} the file directory
     */
    static getFileDir(fileName)
    {
        var fileType = fileName.split(".")[1]

        var newFileDir = "";

        var platform = os.platform();
        if (platform == "win32")
        {
            if (fileType == "m3u8")
            {
                fileName = fileName.replace(".m3u8", "_new.mp4")
                newFileDir = ljConst.BASE_DIR + fileName.replace(/\*/g, '\\');
            }
            else
            {
                fileName = fileName.replace(".", "_new.")
                newFileDir = ljConst.BASE_DIR + fileName.replace(/\*/g, '\\');
            }
        }
        else if (platform == "darwin")
        {
            if (fileType == "m3u8")
            {
                fileName = fileName.replace(".m3u8", "_new.mp4")
                newFileDir = ljConst.BASE_DIR + fileName.replace(/\*/g, '/');
            }
            else
            {
                fileName = fileName.replace(".", "_new.")
                newFileDir = ljConst.BASE_DIR + fileName.replace(/\*/g, '/');
            }
        }


        return newFileDir;
    }

    /**
     * Makes directory
     * @param dirname the directory name
     * @returns {boolean} true or false
     */
    static mkdirsSync(dirname)
    {
        if (fs.existsSync(dirname))
        {
            return true;
        }
        else
        {
            if (this.mkdirsSync(path.dirname(dirname)))
            {
                fs.mkdirSync(dirname);
                return true;
            }
        }
    }

    /**
     * Gets the file property object
     * @param fileUrl the file URL
     * @returns {null}
     */
    static getFileProperty(fileUrl)
    {
        /*--文件夹目录-Begin--*/
        var folderDir = ljConst.BASE_DIR;

        var splitArr = fileUrl.split('/')
        var arrLen = splitArr.length;
        var platform = os.platform();
        if (platform == "win32")
        {

            for (var i = 3; i < arrLen - 1; i++)
            {
                folderDir += splitArr[i] + "\\";
            }
        }
        else if(platform == "darwin")
        {
            for (var i = 3; i < arrLen - 1; i++)
            {
                folderDir += splitArr[i] + "/";
            }
        }
        //创建文件夹目录
        this.mkdirsSync(folderDir);

        var filePropObj = {};
        filePropObj.folderDir = folderDir;
        //获取文件名称
        filePropObj.fileName = splitArr[arrLen - 1].split(".")[0];
        //获取文件类型
        filePropObj.fileType = splitArr[arrLen - 1].split(".")[1];
        /*--文件夹目录-Begin--*/

        return filePropObj;
    }

    /**
     * Gets the file property object
     * @param fileUrl the file URL
     * @returns {null}
     */
    static getFilePropertyNoMkdir(fileUrl)
    {
        if(fileUrl == null)
        {
            return;
        }
        /*--文件夹目录-Begin--*/
        var folderDir = ljConst.BASE_DIR;

        var splitArr = fileUrl.split('/')
        var arrLen = splitArr.length;
        var platform = os.platform();
        if (platform == "win32")
        {
            for (var i = 3; i < arrLen - 1; i++)
            {
                folderDir += splitArr[i] + "\\";
            }
        }
        else if(platform == "darwin")
        {
            for (var i = 3; i < arrLen - 1; i++)
            {
                folderDir += splitArr[i] + "/";
            }
        }

        var filePropObj = {};
        filePropObj.folderDir = folderDir;
        //获取文件名称
        filePropObj.fileName = splitArr[arrLen - 1].split(".")[0];
        //获取文件类型
        filePropObj.fileType = splitArr[arrLen - 1].split(".")[1];
        /*--文件夹目录-Begin--*/

        return filePropObj;

    }

    static Encrypted(c)
    {
        var b = '';
        for (var i = 0; i < c.length; i++)
        {
            var ch = c[i];
            if (ch == '0')
            {
                ch = 'f';
            }
            else if (ch == 'f')
            {
                ch = '0';
            }
            b = b + ch;
            //console.log(ch);
        }
        return b;
    }

    static Decrypted(c)
    {
        var b = '';
        for (var i = 0; i < c.length; i++)
        {
            var ch = c[i];
            if (ch == 'f')
            {
                ch = '0';
            }
            else if (ch == '0')
            {
                ch = 'f';
            }
            b = b + ch;
            //console.log(ch);
        }
        return b;
    }

    /**
     * Writes encrypted content, which is read from given source file, into given dest file
     * @param fSrc the source file
     * @param fDest the dest file
     */
    static writeEncryptedStream(fSrc, fDest, callback)
    {
        var rs = fs.createReadStream(fSrc);
        var ws = fs.createWriteStream(fDest);
        rs.on('data', function (chunk)
        {
            let b = new Buffer(chunk, 'hex');
            //console.log(b);

            let c = b.toString('hex');
            c = LjFileHelper.encryptedContent(c);
            let d = Buffer.from(c, 'hex');

            ws.write(d);
        });

        rs.on('end', function ()
        {
            ws.end();
            logHelper.info('Succeeded in writing into encrypted stream[' + fDest + '].');
            callback();
        });

        rs.on('error', function (err)
        {
            logHelper.error(err.stack);
        });
    }

    /**
     * Encrypts the content
     * @param c the content to be encrypted
     * @return the encrypted content
     */
    static encryptedContent(c)
    {
        var b = '';
        for (var i = 0; i < c.length; i++)
        {
            var ch = c[i];
            if (ch == '0')
            {
                ch = 'f';
            }
            else if (ch == 'f')
            {
                ch = '0';
            }
            else if (ch == '1')
            {
                ch = 'e';
            }
            else if (ch == 'e')
            {
                ch = '1';
            }
            else if (ch == '2')
            {
                ch = 'd';
            }
            else if (ch == 'd')
            {
                ch = '2';
            }
            else if (ch == '3')
            {
                ch = 'c';
            }
            else if (ch == 'c')
            {
                ch = '3';
            }
            b = b + ch;
            //console.log(ch);
        }
        return b;
    }

    /**
     * Decrypts the encrypted content
     * @param c the encrypted content
     * @return the decrypted content
     */
    static decryptedContent(c)
    {
        var b = '';
        for (var i = 0; i < c.length; i++)
        {
            var ch = c[i];
            if (ch == 'f')
            {
                ch = '0';
            }
            else if (ch == '0')
            {
                ch = 'f';
            }
            else if (ch == 'e')
            {
                ch = '1';
            }
            else if (ch == '1')
            {
                ch = 'e';
            }
            else if (ch == 'd')
            {
                ch = '2';
            }
            else if (ch == '2')
            {
                ch = 'd';
            }
            else if (ch == 'c')
            {
                ch = '3';
            }
            else if (ch == '3')
            {
                ch = 'c';
            }
            b = b + ch;
            //console.log(ch);
        }
        return b;
    }

    /**
     * Reads decrypted content, which is read from given encrypted file, into HTTP response stream
     * @param res the HTTP response stream
     * @param fDest the encrypted file
     */
    static readDecryptedStream(res, fDest, contentType)
    {
        res.writeHead(200, {'Content-Type': contentType});
        var rs = fs.createReadStream(fDest);
        rs.on('data', function (chunk)
        {
            let b = new Buffer(chunk, 'hex');

            let c = b.toString('hex');
            c = LjFileHelper.decryptedContent(c);

            let d = Buffer.from(c, 'hex');

            res.write(d);
        });

        rs.on('end', function ()
        {
            res.end();
            logHelper.log('Succeeded in reading from decrypted stream[' + fDest + '].');
        });

        rs.on('error', function (err)
        {
            logHelper.log(err.stack);
        });
    }

    static updateDownloadResSize(opt)
    {
        //return false;
        opt.url = apiHelper.getApiForUpdateResSize(opt.lessonId);
        opt.method = "PUT";
        opt.path = "/callback/download/update/resource/size";

        httpHelper.request(opt, function (error, res, body)
        {
            var retObj = JSON.parse(body);

            if (retObj.code == 200)
            {
                logHelper.info("Succeed to call api[" + opt.path + "]");
                return true;
            }
            else
            {
                logHelper.error("Failed to call api[" + opt.path + "],caused by error[" + retObj.message + "]");
                return false;
            }
        });
    }

    /**
     * Is video
     * @param dir the directory
     * @returns {boolean}
     */
    isVideo(dir)
    {
        if (dir == "")
        {
            return false;
        }
        var fileType = dir.split(".")[1];
        if ("m3u8" == fileType)
        {
            return true;
        }
        return false;
    }
}

module.exports = LjFileHelper;
