package com.fdkankan.model.utils;

import cn.hutool.core.io.FileUtil;
import com.fdkankan.model.constants.ConstantCmd;
import com.fdkankan.model.constants.ConstantFileName;
import com.fdkankan.model.constants.ConstantFilePath;
import com.fdkankan.model.proto.BigSceneProto;
import com.fdkankan.model.proto.Common;
import com.fdkankan.model.proto.Visionmodeldata;
import com.fdkankan.model.proto.format.JsonFormat;
import com.google.protobuf.TextFormat;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CreateObjUtil {

//	private static Logger log = LoggerFactory.getLogger(CreateObjUtil.class);

	public void saveuploadImgs(String folderName) throws IOException, Exception
	{
		log.info("开始计算");
		String command = "bash /home/ubuntu/photoscan-pro/build_model.sh "+folderName;
		callshell(command);
		boolean flag = false;
		String sPath =  ConstantFilePath.CREATE_MODEL_PATH+folderName+File.separator+"mesh"+File.separator+"mesh.obj";
		while(!flag)
		{
			flag = isModel(sPath,folderName);
		}
		log.info("计算完毕");
	}

	public void saveuploadImgs2(String folderName) throws IOException, Exception
	{
		log.info("开始计算");
		String command = "bash /home/ubuntu/photoscan-pro/build_bigscene.sh "+folderName;
		callshell(command);
		boolean flag = false;
		String sPath = ConstantFilePath.CREATE_BIG_SCENE_PATH+folderName+File.separator+"mesh"+File.separator+"mesh.obj";
		while(!flag)
		{
			flag = isModel(sPath,folderName);
		}
		log.info("计算完毕");
		log.info("obj和camera转换成大场景要的格式");
		convertobjTotxt( folderName);

	}

	//开始建模
	public static void unRar(String rarPath,String dataPath) throws Exception{
		log.info("解压rar开始");
		String command = "unrar e " + rarPath + " " + dataPath;
		callshell(command);
		log.info("解压rar完毕：" + command);
	}

	public static void unRarWithPath(String rarPath,String dataPath) throws Exception{
		log.info("解压rar开始");
		String command = "unrar x " + rarPath + " " + dataPath;
		callshell(command);
		log.info("解压rar完毕：" + command);
	}

	public static void unZip(String zipPath,String dataPath) throws Exception{
		log.info("解压zip开始");
		String command = "unzip -O GBK/GB18030CP936 " + zipPath + " -d " + dataPath;
		callshell(command);
		log.info("解压zip完毕：" + command);
	}

	//开始建模
	public static void build3dModel(String folderName,String isModel) throws Exception{
		log.info("开始建模");
		String command = ConstantCmd.BUILD_MODEL_COMMAND+folderName;
		callshell(command);
		log.info("计算完毕：" + command);
	}

	//开始建模
	public static void build3dModel2(String folderName,String isModel) throws Exception{
		log.info("开始建模");
		String command = ConstantCmd.BUILD_MODEL_COMMAND2+folderName;
		callshell(command);
		log.info("计算完毕：" + command);
	}

	//开始建模
	public static void build3dModelOld(String folderName,String isModel) throws Exception{
		log.info("开始v2建模");
		String command = ConstantCmd.BUILD_MODEL_OLD_COMMAND+folderName;
		callshell(command);
		log.info("计算v2完毕：" + command);
	}

	public static void killMainLoader(){
		log.info("开始杀掉算法进程");
		String command = "sudo ps -ef | grep 'MainLoader.exe' | grep -v grep | awk '{print $2}' | xargs kill -9";
		callshell(command);
		log.info("开始杀掉算法完毕");
	}

	//开始建模
	public static void translateHoustfloorJSONFile(String filePath,String outputPath) throws Exception{
		log.info("开始转换houst_floor.json");
		String command = ConstantCmd.TRANSLATE_HOUST_FLOOR + filePath + " " + outputPath;
		callshell(command);
		log.info("转换houst_floor.json 结束");
	}

	//激光相机复制资源
	public static void cpfile(String filepathOld,String filepathNew) throws Exception{
		log.info("开始复制");
		String command = ConstantCmd.CP_JG_EXTRA+ " " + filepathOld + " " + filepathNew;
		callshell(command);
		log.info("复制完毕：" + command);
	}


	//激光相机复制资源laser下的全部资源
	public static void cplaserfile(String filepathOld,String filepathNew) throws Exception{
		log.info("开始复制");
		String command = ConstantCmd.CP_JG_ALL+ " " + filepathOld + " " + filepathNew;
		callshell(command);
		log.info("复制完毕：" + command);
	}

	//开始建模
	public void build3dModelSFM(String folderName,String isModel) throws Exception{
		log.info("开始建模");
		String command = ConstantCmd.BUILD_MODEL_SFM_COMMAND+folderName+" "+isModel;
		callshell(command);
		log.info("计算完毕");
	}

	//obj文件转换问txt
	public static void objToTxt(String folderName,String isModel) throws Exception{
		log.info("obj2txt开始转换");
		String command = ConstantCmd.OBJ_TO_TXT+folderName;
		callshell(command);
		log.info("转换完毕：" + command);
	}

	public void rebuildModelFllor(String folderName, String isModel) {
		try{
			log.info("开始建模");
			String command = ConstantCmd.REBUILD_MODEL_FLLOR+folderName+" "+isModel;
			callshell(command);
			log.info("计算完毕");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	//切图
	public void cutImgs(String[] imgNames ,String folderName)
	{
		try{
			log.info("开始切图");
			for(int i=0;i<imgNames.length;++i)
			{
				String imgName=imgNames[i].replace(".jpg", "");
				String command = ConstantCmd.CUT_IMG_COMMAND+folderName+" "+imgName;
				callshell(command);
			}
			log.info("切图完毕");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	//调整切图
	public void adjustImgs(String folderName)
	{
		try{
			String command = ConstantCmd.ADJUST_IMG_COMMAND + folderName;
			log.info("开始调整图片");
			callshell(command);
			log.info("调整图片完毕");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	//obj和camera转换成大场景要的格式
	public void convertobjTotxt(String folderName) throws Exception
	{
		//obj
		String command = "/home/ubuntu/photoscan-pro/main/mesh/mesh "+folderName;
		callshell(command);
		//camera
		command = "/home/ubuntu/photoscan-pro/main/read_camera/read_camera "+folderName;
		callshell(command);

		String prefix = ConstantFilePath.CREATE_BIG_SCENE_PATH+folderName+File.separator+"data"+File.separator;
		String srcpath = prefix +"mesh.txt";
		String despath = prefix +"dacf7dfa24ae47fab8fcebfe4dc41ab9_50k.dam";

		convertTxtToDam( srcpath, despath);
		//dam转换成lzma
		command = "lzma /home/ubuntu/photo_data/bigscene/"+folderName+"/data/dacf7dfa24ae47fab8fcebfe4dc41ab9_50k.dam";
		callshell(command);

		srcpath = prefix +"vision.txt";
		despath = prefix +"vision.modeldata";
		convertTxtToVisionmodeldata( srcpath, despath);
	}

	public static void convertDamToLzma(String folderName)throws Exception
	{
		try
		{
			String command = "lzma "+ folderName+ ConstantFileName.modelUUID+"_50k.dam";
			log.info("开始转换lzma");
			callshell(command);
			log.info("转换lzma完毕");
		}
		catch(Exception e)
		{
			StringWriter trace=new StringWriter();
			e.printStackTrace(new PrintWriter(trace));
			log.error(trace.toString());
		}

	}

	public static void convertDamToLzmaByAbsolutePath(String path)throws Exception
	{
		try
		{
			String command = "lzma "+ path;
			log.info("开始转换lzma");
			callshell(command);
			log.info("转换lzma完毕");
		}
		catch(Exception e)
		{
			StringWriter trace=new StringWriter();
			e.printStackTrace(new PrintWriter(trace));
			log.error(trace.toString());
		}

	}

	public static void convertDamToLzma2(String folderName)throws Exception
	{
		try
		{
			String command = "lzma "+ folderName+File.separator+ ConstantFileName.modelUUID+"_50k2.dam";
			log.info("开始转换lzma");
			callshell(command);
			log.info("转换lzma完毕");
		}
		catch(Exception e)
		{
			StringWriter trace=new StringWriter();
			e.printStackTrace(new PrintWriter(trace));
			log.error(trace.toString());
		}

	}

	public static void convertTxtToDam(String srcpath,String despath)throws Exception{
		InputStream inputStream = null;
		InputStreamReader reader = null;
		ByteArrayInputStream stream = null;
		BufferedOutputStream bos = null;
		BufferedInputStream bis = null;
		try{
			BigSceneProto.binary_mesh.Builder builder = BigSceneProto.binary_mesh.newBuilder();
			inputStream = new FileInputStream(srcpath);
			reader = new InputStreamReader(inputStream, "ASCII");
			TextFormat.merge(reader, builder);
			byte[] buf = builder.build().toByteArray();

			//把序列化后的数据写入本地磁盘
			stream = new ByteArrayInputStream(buf);
			bos = new BufferedOutputStream(new FileOutputStream(despath));//设置输出路径
			bis = new BufferedInputStream(stream);
			int b = -1;
			while ((b = bis.read()) != -1) {
				bos.write(b);
			}
		}catch (Exception e){
			log.error("txt转dam出错，srcpath:{}, despath:{}",srcpath, despath);
			throw e;
		}finally {
			if(inputStream != null){
				inputStream.close();
			}
			if(reader != null){
				reader.close();
			}
			if(stream != null){
				stream.close();
			}
			if(bos != null){
				bos.close();
			}
			if(bis != null){
				bis.close();
			}
		}

	}

	public static void convertDamToTxt(String srcpath,String despath) throws IOException {
		FileInputStream fis= null;
		ByteArrayInputStream stream = null;
		BufferedOutputStream bos = null;
		BufferedInputStream bis = null;
		try {
			fis=new FileInputStream(new File(srcpath));
			BigSceneProto.binary_mesh data_NavigationInfo = BigSceneProto.binary_mesh.parseFrom(fis);
			String jsonFormat1 = JsonFormat.printToString(data_NavigationInfo);
			stream = new ByteArrayInputStream(jsonFormat1.getBytes());
			bos = new BufferedOutputStream(new FileOutputStream(despath));//设置输出路径
			bis = new BufferedInputStream(stream);
			int b = -1;
			while ((b = bis.read()) != -1) {
				bos.write(b);
			}

		}finally{
			try {
				if(bis != null){
					bis.close();
				}
				if(bos != null){
					bos.close();
				}
				if(fis != null){
					fis.close();
				}
			}catch (Exception e){
				log.error("关闭文件流报错", e);
			}
		}
	}

	public static void main(String[] args) throws Exception {

//		convertVisionmodeldataToTxt("D:\\test\\test\\vision.modeldata", "D:\\test\\test\\vision.txt");
//		FileUtil.del("D:\\test\\test");

		convertTxtToVisionmodeldata("D:\\test\\vision(7).txt", "D:\\test\\vision.modeldata");

	}

	public static void convertVisionmodeldataToTxt(String srcpath,String despath)throws Exception {
		try (FileInputStream fis = new FileInputStream(srcpath)){
			Visionmodeldata.NavigationInfo data_NavigationInfo = Visionmodeldata.NavigationInfo.parseFrom(fis);
			String jsonFormat1 = JsonFormat.printToString(data_NavigationInfo);
			try (
				ByteArrayInputStream stream = new ByteArrayInputStream(jsonFormat1.getBytes());
				BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(despath));//设置输出路径
				BufferedInputStream bis = new BufferedInputStream(stream)
			){
				int b = -1;
				while ((b = bis.read()) != -1) {
					bos.write(b);
				}
			}
		}
	}

	public static void convertTxtToVisionmodeldata(String srcpath,String despath)throws Exception
	{
		try{
			Visionmodeldata.NavigationInfo.Builder builder = Visionmodeldata.NavigationInfo.newBuilder();
			String jsonFormat = readTxtFileToJson(srcpath);
			JsonFormat.merge(jsonFormat, builder);
			byte[] buf= builder.build().toByteArray();

			//把序列化后的数据写入本地磁盘
	        ByteArrayInputStream stream = new ByteArrayInputStream(buf);
	        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(despath));//设置输出路径
	        BufferedInputStream bis = new BufferedInputStream(stream);
	        int b = -1;
	        while ((b = bis.read()) != -1) {
	           bos.write(b);
	        }
	        bis.close();
	        bos.close();
		}
		catch(Exception e)
		{
			StringWriter trace=new StringWriter();
			e.printStackTrace(new PrintWriter(trace));
			log.error(trace.toString());
		}
	}

	public static void convertVisionmodeldataToTxtCommon(String srcpath,String despath)throws Exception
	{
		try
		{
			File file = new File(srcpath);
			FileInputStream fis=new FileInputStream(file);

			Common.NavigationInfo data_NavigationInfo = Common.NavigationInfo.parseFrom(fis);

			//PrintStream out = new PrintStream(despath);
			String jsonFormat1 = JsonFormat.printToString(data_NavigationInfo);
			ByteArrayInputStream stream = new ByteArrayInputStream(jsonFormat1.getBytes());
			BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(despath));//设置输出路径
			BufferedInputStream bis = new BufferedInputStream(stream);
			int b = -1;
			while ((b = bis.read()) != -1) {
				bos.write(b);
			}
			//out.close();
			bis.close();
			bos.close();
		}
		catch(Exception e)
		{
			StringWriter trace=new StringWriter();
			e.printStackTrace(new PrintWriter(trace));
			log.error(trace.toString());
		}
	}

	public static void convertTxtToVisionmodeldataCommon(String srcpath,String despath)throws Exception
	{
		try
		{
			Common.NavigationInfo.Builder builder = Common.NavigationInfo.newBuilder();
			String jsonFormat = readTxtFileToJson(srcpath);
			JsonFormat.merge(jsonFormat, builder);
			byte[] buf= builder.build().toByteArray();

			//把序列化后的数据写入本地磁盘
			ByteArrayInputStream stream = new ByteArrayInputStream(buf);
			BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(despath));//设置输出路径
			BufferedInputStream bis = new BufferedInputStream(stream);
			int b = -1;
			while ((b = bis.read()) != -1) {
				bos.write(b);
			}
			bis.close();
			bos.close();
		}
		catch(Exception e)
		{
			StringWriter trace=new StringWriter();
			e.printStackTrace(new PrintWriter(trace));
			log.error(trace.toString());
		}
	}

	public static void callshell(String command){
        try {
			 Long start = System.currentTimeMillis();
			 Process process = Runtime.getRuntime().exec(command);
        	 StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR");
             errorGobbler.start();
             StreamGobbler outGobbler = new StreamGobbler(process.getInputStream(), "STDOUT");
             outGobbler.start();
             process.waitFor();
			log.info("脚本{}执行完毕,用时：{}ms",command,System.currentTimeMillis()-start);
        } catch (Exception e) {
            e.printStackTrace();
        }
	}

	public static int doWaitFor(Process process) {
		  InputStream in = null;
		  InputStream err = null;
		  int exitValue = -1; // returned to caller when p is finished
		  try {
		    in = process.getInputStream();
		    err = process.getErrorStream();
		    boolean finished = false; // Set to true when p is finished
		    while (!finished) {
		      try {
		        while (in.available() > 0) {
		          // Print the output of our system call
		          Character c = new Character((char) in.read());
		          System.out.print(c);
		        }
		        while (err.available() > 0) {
		          // Print the output of our system call
		          Character c = new Character((char) err.read());
		          System.out.print(c);
		        }
		        // Ask the process for its exitValue. If the process
		        // is not finished, an IllegalThreadStateException
		        // is thrown. If it is finished, we fall through and
		        // the variable finished is set to true.
		        exitValue = process.exitValue();
		        finished = true;
		      } catch (IllegalThreadStateException e) {
		        // Process is not finished yet;
		        // Sleep a little to save on CPU cycles
		        Thread.currentThread().sleep(500);
		      }
		    }
		  } catch (Exception e) {
		    e.printStackTrace();
		  } finally {
		    try {
		      if (in != null) {
		        in.close();
		      }
		    } catch (IOException e) {
		      e.printStackTrace();
		    }
		    if (err != null) {
		      try {
		        err.close();
		      } catch (IOException e) {
		        e.printStackTrace();
		      }
		    }
		  }
		  return exitValue;
		}


	private boolean isModel(String sPath,String folderName)
	{
		boolean flag = false;
		File file = new File(sPath);
	    if (file.isFile() && file.exists()) {
	        flag = true;
	    }
	    log.info("等待...");
	    return flag;
	}

	public static String readTxtFileToJson(String filePath){
        try {
                String encoding="UTF-8";
                File file=new File(filePath);
                if(file.isFile() && file.exists()){
                    InputStreamReader read = new InputStreamReader(
                    new FileInputStream(file),encoding);
                    BufferedReader bufferedReader = new BufferedReader(read);
                    String lineTxt = null;
                    String result="";
                    while((lineTxt = bufferedReader.readLine()) != null){
                    	result+=lineTxt;
                        //log.info(lineTxt);
                    }
                    read.close();
                    return result;
        }else{
            return null;
        }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

	public Map<String,String> getAllFile(String dPath,String prefix)
	{
		File dirFile = new File(dPath);
	    if (!dirFile.isDirectory()) {
        }
	    Map<String,String> map = new HashMap<String,String>();
	    File[] files = dirFile.listFiles();
	    for (int i = 0; i < files.length; i++) {
            if (files[i].isFile()) {
            	String path = files[i].getPath();
            	map.put(path, prefix+path.substring(path.lastIndexOf("/")+1));
            }
        }
	    return map;
	}

	public Map<String,String> getchildFile(String dPath,String prefix,String childname)
	{
		File dirFile = new File(dPath+File.separator+childname);
	    if (!dirFile.isDirectory()) {
	    	return null;
        }
	    Map<String,String> map = new HashMap<String,String>();
	    File[] files = dirFile.listFiles();
	    for (int i = 0; i < files.length; i++) {
            if (files[i].isFile()) {
            	String path = files[i].getPath();
            	map.put(path, prefix+childname+path.substring(path.lastIndexOf("/")));
            }
        }
	    return map;
	}

	//转台拼图
	public void buildPanoramicImgs(String folderName)throws Exception
	{
		String command = ConstantCmd.BUILD_PANORAMA + folderName;
		log.info("开始拼全景图");
		callshell(command);
		log.info("全景图拼接完毕");
	}

	//六目拼图、切图，计算
	public void buildForSix(String folderName)throws Exception
	{
		String command = ConstantCmd.BUILD_FOR_SIX + folderName;
		log.info("开始处理数据（六目）");
		callshell(command);
		log.info("数据处理完毕（六目）");
	}

	public static void createSoftConnection(String source, String target) {
		String command = "ln -s " + source + " " + target;
		log.info("开始创建文件夹软连接");
		callshell(command);
		log.info("数据处理完毕（六目）：" + command);
	}

	//合并音频
	public static void mergeVideo(String oldVideo , String newVideo, String targetVideo) throws Exception{
		String command = ConstantCmd.MERGE_VIDEO + " " + oldVideo + " " + newVideo + " " + targetVideo + " -y";
		log.info("开始合并视频");
		callshell(command);
		log.info("合并视频完毕：" + command);
	}

	//生成一段静音音频
	public static void createMuteViode(double time , String targetVideo) throws Exception{
		String command = ConstantCmd.CREATE_MUTE_VIDEO + " " + time + " " + targetVideo + " -y";
		log.info("开始生成一段静音音频");
		callshell(command);
		log.info("生成一段静音音频完毕：" + command);
	}

	//mp4文件转换成flv文件
	public static void mp4ToFlv(String oldVideo, String newVideo) throws Exception{
		String command = ConstantCmd.MP4_TO_FLV + " " + oldVideo + " " + newVideo;
		log.info("mp4文件转换成flv文件");
		callshell(command);
		log.info("mp4文件转换成flv文件完毕：" + command);
	}

	public static void formatMp4(String oldVideo, String newVideo) throws Exception{
		String command = ConstantCmd.FORMAT_MP4 + " " + oldVideo + " " + newVideo;
		log.info("mp4格式转换开始:{}", command);
		callshell(command);
		log.info("mp4格式转换完毕:{}", command);
	}

	//删除/mnt/data/下的数据
	public static void deleteFile(String filePath) throws Exception{
		String command = ConstantCmd.DELETE_FILE + " " + filePath;
		log.info("删除/mnt/data/下的数据");
		callshell(command);
		log.info("删除/mnt/data/下的数据完毕：" + command);
	}

	public static void ossUtilCp(String fileUrl , String path) throws Exception{
		String command = ConstantCmd.OSS_UTIL_CP + " " + fileUrl + " " + path;
		Long start = System.currentTimeMillis();
		log.info("开始oss下载文件：" + command);
		callshell(command);
		log.info("oss下载文件完成,时间为：" + (System.currentTimeMillis() - start));
	}

	/**
	 * oss文件下载，支持目录或者单个文件下载
	 * @param fyunType oss类型（oss, aws）
	 * @param bucket oss桶名
	 * @param remoteFilePath	key
	 * @param path		本地路径
	 * @throws Exception
	 */
	public static void ossDownload(String fyunType, String bucket, String remoteFilePath , String path) throws Exception{
		String optType = remoteFilePath.contains(".") ? "file" : "folder";
		String command = String.format(ConstantCmd.FYUN_DOWNLOAD, bucket, remoteFilePath, path, fyunType, optType);
		Long start = System.currentTimeMillis();
		log.info("开始oss下载文件：" + command);
		callshell(command);
		log.info("oss下载文件完成,时间为：" + (System.currentTimeMillis() - start));
	}

	/**
	 * oss文件上传，支持目录或者单个文件上传
	 * @param fyunType oss类型（oss, aws）
	 * @param bucket oss桶名
	 * @param remoteFilePath	key
	 * @param path		本地路径
	 * @throws Exception
	 */
	public static void ossUpload(String fyunType, String bucket, String remoteFilePath , String path) throws Exception{
		String optType = remoteFilePath.contains(".") ? "file" : "folder";
		String command = String.format(ConstantCmd.FYUN_UPLOAD, bucket, path, remoteFilePath, fyunType, optType);
		Long start = System.currentTimeMillis();
		log.info("开始oss上传文件：" + command);
		callshell(command);
		log.info("oss上传文件完成,时间为：" + (System.currentTimeMillis() - start));
	}

	public static void ossFileCp(String fileUrl , String path) throws Exception{
		String command = ConstantCmd.OSS_FILE_CP + " " + fileUrl + " " + path;
		Long start = System.currentTimeMillis();
		log.info("开始s3文件下载文件：" + command);
		callshell(command);
		log.info("s3文件下载文件完成,时间为：" + (System.currentTimeMillis() - start));
	}

	/**
	 * matterpro场景获取阿里云的切图数据
	 * @param path
	 * @throws Exception
     */
	public static void matterproCutImg(String num , String path) throws Exception{
		String command = ConstantCmd.MATTERPRO_CUT_IMG + " -s " + num + " -d " + path;
		Long start = System.currentTimeMillis();
		log.info("开始matterpro获取阿里云图片方法：" + command);
		callshell(command);
		log.info("matterpro获取阿里云图片方法完成,时间为：" + (System.currentTimeMillis() - start));
	}


}
