package com.fdkankan.model.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fdkankan.common.constant.ErrorCode;
import com.fdkankan.common.exception.BusinessException;
import com.fdkankan.common.util.FileUtils;
import com.fdkankan.model.constants.ConstantFilePath;
import com.fdkankan.model.constants.UploadFilePath;
import com.fdkankan.model.enums.ModelTypeEnums;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
 * 生成场景和计算场景
 * Created by Hb_zzZ on 2019/5/8.
 */
public class ComputerUtil {

    private static Logger log = LoggerFactory.getLogger(ComputerUtil.class.getName());

    public static void computer(String projectNum, String path, String buildType) throws Exception{

        Map<String,String> map = new HashMap<String,String>();
        path = path.replace("//", "/");
        log.info("开始建模："+projectNum);
        //构建算法isModel去掉，因此改成空字符串
        if("V2".equals(buildType)){
            CreateObjUtil.build3dModelOld(path, "");
        }
        if("V3".equals(buildType)){
            CreateObjUtil.build3dModel(path, "");
        }
        log.info("建模完成转换数据："+projectNum);

        boolean vision2 = false;
        //读取upload文件，检验需要上传的文件是否存在
        String uploadJsonPath = path + File.separator + "results" +File.separator+"upload.json";
        String uploadData = FileUtils.readFile(uploadJsonPath);
        log.info("upload.json 文件路径：{}, 内容：{}" , uploadJsonPath, uploadData);
        JSONObject uploadJson = null;
        JSONArray array = null;
        if(uploadData!=null) {
            uploadJson = JSONObject.parseObject(uploadData);
            array = uploadJson.getJSONArray("upload");
        }
        if(array == null){
            String instanceId = FileUtils.readFile("/opt/hosts/hosts.txt");
            FileUtils.writeFile(path + File.separator + "javaErrorNow.log", instanceId + ":计算错误！");

            Thread.sleep(10000L);
            FileUtils.writeFile(path + File.separator + "javaError.log", instanceId + ":计算错误！");
            throw new Exception("upload.json数据出错");
        }
    }

    public static Map<String,String> computerRebuildVideo(String projectNum, String path) throws Exception{

        String videosPath = String.format(UploadFilePath.VIDEOS_VIEW_PATH, projectNum);     //新版本文件路径

        Map<String,String> map = new HashMap<String,String>();
        path = path.replace("//", "/");

        log.info("开始建模："+projectNum);
        //构建算法isModel去掉，因此改成空字符串
        CreateObjUtil.build3dModel(path, "");
        log.info("建模完成转换数据："+projectNum);

        boolean vision2 = false;
        //读取upload文件，检验需要上传的文件是否存在
        String uploadData = FileUtils.readFile(path + File.separator + "results" +File.separator+"upload.json");
        JSONObject uploadJson = null;
        JSONArray array = null;
        if(uploadData!=null) {
            uploadJson = JSONObject.parseObject(uploadData);
            array = uploadJson.getJSONArray("upload");
        }

        if(array == null){
            String instanceId = FileUtils.readFile("/opt/hosts/hosts.txt");
            FileUtils.writeFile(path + File.separator + "javaErrorNow.log", instanceId + ":计算错误！");

            Thread.sleep(10000L);
            FileUtils.writeFile(path + File.separator + "javaError.log", instanceId + ":计算错误！");
            throw new Exception("upload.json数据出错");
        }

        JSONObject fileJson = null;
        String fileName = "";
        for(int i = 0, len = array.size(); i < len; i++) {
            fileJson = array.getJSONObject(i);
            fileName = fileJson.getString("file");
            //文件不存在抛出异常
            if (!new File(path + File.separator + "results" + File.separator + fileName).exists()) {
                throw new Exception(path + File.separator + "results" + File.separator + fileName + "文件不存在");
            }

            //video视频文件或封面图
            if (fileJson.getIntValue("clazz") == 20) {
                if (fileName.contains(".flv")) {
                    map.put(path + File.separator + "results" + File.separator + fileName,
                            "video/video" + projectNum + File.separator + fileName.replace("videos/", ""));
                    //todo 待删除oldPath
                    map.put(path + File.separator + "results" + File.separator + fileName,
                            videosPath + fileName.replace("videos/", ""));
                }

                if (fileName.contains(".mp4")) {
                    map.put(path + File.separator + "results" + File.separator + fileName,
                            "video/video" + projectNum + File.separator + fileName.replace("videos/", ""));

                    map.put(path + File.separator + "results" + File.separator + fileName,
                            videosPath+ fileName.replace("videos/", ""));
                }
            }
        }

        log.info("准备上传文件到oss："+projectNum);
        return map;
    }

    /**
     *  标定算法
     * @param path
     * @throws Exception
     */
    public static Map<String,String> computerCalibration(String path) throws Exception{

        Map<String,String> map = new HashMap<String,String>();

        log.info("开始标定：" );
        //构建算法isModel去掉，因此改成空字符串
        CreateObjUtil.build3dModel(path, "");
//        CreateObjUtil.build3dModel(unicode, "");
        log.info("标定完成转换数据：" );

        boolean vision2 = false;
        //读取upload文件，检验需要上传的文件是否存在
        String uploadData = FileUtils.readFile(path + File.separator + "results" +File.separator+"upload.json");
        JSONObject uploadJson = null;
        JSONArray array = null;
        if(uploadData!=null) {
            uploadJson = JSONObject.parseObject(uploadData);
            array = uploadJson.getJSONArray("upload");
        }
        if(array == null){
            throw new Exception("upload.json数据出错");
        }
        JSONObject fileJson = null;
        String fileName = "";
        for(int i = 0, len = array.size(); i < len; i++) {
            fileJson = array.getJSONObject(i);
            fileName = fileJson.getString("file");
            //文件不存在抛出异常
            if (!new File(path + File.separator + "results" + File.separator + fileName).exists()) {
                throw new Exception(path + File.separator + "results" + File.separator + fileName + "文件不存在");
            }

            if(fileJson.getIntValue("clazz") == 13 || fileJson.getIntValue("clazz") == 14){
                map.put(path + File.separator + "results" +File.separator+ fileName,
                        ConstantFilePath.OSS_PREFIX + path.replace(ConstantFilePath.BUILD_MODEL_PATH, "") +
                                File.separator + fileName);
            }
        }
        return map;
    }

    public static void createProjectAndDataFile(String path, String sceneNum, String splitType, String skyboxType,
                                                Map<String, Object> projectExtras, Map<String, Object> dataExtras) {
        JSONObject projectJson = new JSONObject();
        if (!ObjectUtils.isEmpty(projectExtras)) {
            projectJson.putAll(projectExtras);
        }
        projectJson.put("sceneNum", sceneNum);
        FileUtils.writeFile(path + File.separator + "project.json", projectJson.toString());

        JSONObject dataJson = new JSONObject();
        if (!ObjectUtils.isEmpty(dataExtras)) {
            dataJson.putAll(dataExtras);
        }
        dataJson.put("split_type", splitType);
        dataJson.put("skybox_type", skyboxType);
        dataJson.put("extras", null);
        FileUtils.writeFile(path + File.separator + "data.json", dataJson.toString());
    }

    public static void createExtras(String rebuildParam, String hdrParam, String path) throws Exception {

        FileUtils.writeFile( path + File.separator + "extras" + File.separator + "videos_hdr_param.json", hdrParam);

        FileUtils.writeFile( path + File.separator + "extras" + File.separator + "required_videos.json", rebuildParam);

    }

    public static void createExtras(String rebuildParam,String path) throws Exception {
        FileUtils.writeFile( path + File.separator + "extras" + File.separator + "image-ROI.json", rebuildParam);
    }

    /**
     * 生成标定数据
     * @param calPath
     * @param prefix
     * @throws Exception
     */
    public static void createCalibrationData(String calPath, String prefix) throws Exception{
        File calFile = new File(calPath);
        if(calFile.exists()){
            calFile.mkdirs();
        }
        //删除results和capture文件夹
        FileUtils.deleteDirectory(calPath + "/capture");
        FileUtils.deleteDirectory(calPath + "/results");

//        CreateObjUtil.ossUtilCp(ConstantFilePath.OSS_PREFIX + prefix, calPath + "/capture");
        for(File oldFile : new File(prefix).listFiles()){
            FileUtils.copyFile(oldFile.getAbsolutePath(), calPath + "/capture/" + oldFile.getName(), true);
        }
        JSONObject dataJson = new JSONObject();
        dataJson.put("split_type", "SPLIT_V7");
        dataJson.put("skybox_type", "SKYBOX_V5");
        FileUtils.writeFile(calPath + "/data.json", dataJson.toString());
    }

    public static Map<String, String> getTypeString(String cameraType, String algorithm, String resolution,JSONObject fdageData){
        Map<String, String> map = new HashMap<>();
        String splitType = "";
        String skyboxType = "";
        String dataDescribe = "";
        if(Integer.parseInt(cameraType) >= 4){
            if("0".equals(resolution)){
//            skyboxType = "SKYBOX_V4";  //tiles
//            skyboxType = "SKYBOX_V6";    //high,low,4k
                skyboxType = "SKYBOX_V7";    //high,low,2k
            }else {
                skyboxType = "SKYBOX_V1";
            }
            splitType = "SPLIT_V1";
//            skyboxType = "SKYBOX_V4";  //tiles
            dataDescribe = "double spherical";

            if(Integer.parseInt(cameraType) == 5 ){
                //新双目相机
//              skyboxType = "SKYBOX_V9";
                splitType = "SPLIT_V9";
                skyboxType = "SKYBOX_V1";
            }
            if(Integer.parseInt(cameraType) == 6){
                //小红屋新双目相机
//                    skyboxType = "SKYBOX_V9";
                splitType = "SPLIT_V3";
                skyboxType = "SKYBOX_V7";
            }

            if(Integer.parseInt(cameraType) == 13){
                //转台相机
                skyboxType = "SKYBOX_V6";
                splitType = "SPLIT_V12";
            }

            if(Integer.parseInt(cameraType) == 14){
                //转台相机
                log.info("激光转台相机调用算法");
                skyboxType = "SKYBOX_V11";
                splitType = "SPLIT_V14";
                if (!ObjectUtils.isEmpty(fdageData)) {
                    if (fdageData.containsKey("exportMeshObj") && fdageData.getIntValue("exportMeshObj") == 1) {
                        splitType = "SPLIT_V22";
                    }
                    if (fdageData.containsKey("OnlyExportMeshObj")) {
                        splitType = "SPLIT_V20";
                    }
                }
            }

        }else {
            if("sfm".equals(algorithm)){
                splitType = "SPLIT_V2";
                skyboxType = "SKYBOX_V1";
                dataDescribe = "old sfm";
            }else {
                splitType = "SPLIT_V3";
                skyboxType = "SKYBOX_V1";
                dataDescribe = "old slam";
            }
        }
        if (!ObjectUtils.isEmpty(fdageData) && !ObjectUtils.isEmpty(fdageData.getString("modelType"))) {
            switch (fdageData.getString("modelType")){
                case ModelTypeEnums.TILE_CODE:
                    if(skyboxType.equals("SKYBOX_V6")){
                        skyboxType = "SKYBOX_V14";
                    }else{
                        skyboxType = "SKYBOX_V13";
                    }
            }
        }
        map.put("splitType", splitType);
        map.put("skyboxType", skyboxType);
        map.put("dataDescribe", dataDescribe);
        return map;
    }

    /**
     * 循环检测算法是否计算成功
     * @param uploadJsonPath uploadjson路径
     * @param maxCheckTimes 循环次数
     * @param waitTime 每次检测间隔时间，毫秒
     * @return boolean
     * @throws Exception
     */
    public static boolean checkComputeCompleted(String uploadJsonPath, int maxCheckTimes, long waitTime) throws Exception{
        int checkTimes = 1;
        boolean exist = false;
        do {
            if(new File(uploadJsonPath).exists()){
                exist = true;
                break;
            }
            Thread.sleep(waitTime);
            ++checkTimes;
        }while (checkTimes <= maxCheckTimes);

        return exist;
    }

    /**
     * 获取计算完需要上传的文件数组
     * @param uploadJsonPath uploadjson路径
     * @param maxCheckTimes 校验upload.json文件是否存在循环次数
     * @param waitTime 每次检测间隔时间，毫秒
     * @return boolean
     * @throws Exception
     */
    public static JSONArray getUploadArray(String uploadJsonPath, int maxCheckTimes, long waitTime) throws Exception{
        boolean buildCompeleted = ComputerUtil.checkComputeCompleted(uploadJsonPath, maxCheckTimes, waitTime);
        if(!buildCompeleted){
            throw new BusinessException(ErrorCode.FAILURE_CODE_7013);
        }
        String uploadData = FileUtil.readUtf8String(uploadJsonPath);
        JSONObject uploadJson;
        JSONArray array = null;
        if(StrUtil.isNotEmpty(uploadData)) {
            uploadJson = JSONObject.parseObject(uploadData);
            array = uploadJson.getJSONArray("upload");
        }
        if(CollUtil.isEmpty(array)){
            throw new BusinessException(ErrorCode.FAILURE_CODE_7013);
        }
        return array;
    }
}
