package com.wechat.common.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Files;

import org.apache.commons.codec.binary.Base64;
import org.springframework.web.multipart.MultipartFile;

import com.wechat.global.CustomException;
import com.wechat.global.message.InfoMsg;

import net.coobird.thumbnailator.Thumbnails;
import sun.misc.BASE64Decoder;

public class LocalFileUtil extends BaseUtils{
	
	/**
     * 上传文件
     * @param file
     * @param basePackagePath 系统默认路径
     * @return
     * @throws IOException
     */
    public static String transferToFile(MultipartFile file,String basePackagePath) throws IOException {
    	// 获取新的文件名称
        String fileName = getNewFileName(file.getOriginalFilename());
        // 创建接受文件
        File targetFile = doFile(basePackagePath,fileName);
        file.transferTo(targetFile);
        return fileName;
    }
    
    /**
     * 上传图片
     * @param file
     * @param basePackagePath 系统默认路径
     * @param pack 自定义文件上传路径  如: test/
     * @return
     * @throws IOException
     */
    public static String transferToImageFile(MultipartFile file,String basePackagePath,String pack) throws IOException {
    	String rest = "";
    	if(!file.isEmpty() && file.getSize()> 0) {
    		// 获取新的文件名称
        	String fileName = getNewFileName(file.getOriginalFilename());
        	//验证图片格式
        	if(checkImage(fileName))
        	{
    	        pack = StringsUtils.isEmpty(pack)? "" : pack;
    	        if(pack.length()>0) {
    	        	pack =  pack.indexOf("/") < 0 ?  pack + "/":pack;
    	        }
    	        // 创建接受文件
    	        File targetFile = doFile(basePackagePath+pack,fileName);
    	        file.transferTo(targetFile);
    	        rest =  pack+fileName;//targetFile.getPath().replace("\\","/");
        	}
    	}
    	
    	return rest;
    }
    
    
    /**
     * 上传文件
     * @param file
     * @param basePackagePath 系统默认路径
     * @param pack 自定义文件上传路径  如: test/
     * @return
     * @throws IOException
     */
    public static String transferToFile(MultipartFile file,String basePackagePath,String pack) throws IOException {
    	// 获取新的文件名称
    	String fileName = getNewFileName(file.getOriginalFilename());

        pack = StringsUtils.isEmpty(pack)? "" : pack;
        if(pack.length()>0) {
        	pack =  pack.indexOf("/") < 0 ?  pack + "/":pack;
        }
        // 创建接受文件
        File targetFile = doFile(basePackagePath+pack,fileName);
        file.transferTo(targetFile);
        return  pack+fileName;//targetFile.getPath().replace("\\","/");

    }
    
    
    private static String getNewFileName(String filename) {
        long startTime = System.currentTimeMillis();
        String newName = startTime + StringsUtils.getRandomString(5)+ filename.substring(filename.lastIndexOf("."));
        return newName;
    }
    private static File doFile(String path,String fileName) {
    	//指定上传目录,不指定盘符会自动保存到你的项目所在盘符
    	File fileDir = new File(path);
        //目录不存在则生成目录
        if (!fileDir.isDirectory()) {
            fileDir.mkdirs();
        }
        return new File(fileDir, fileName);
    }
    /**
     * 删除单个文件
     * @param fileUrl
     * @return
     */
    public static boolean deleteLocalFile(String fileUrl) {
    	File file = new File(fileUrl);
		if (file.exists() && file.isFile()) {
			if (file.delete()) {
				return true;
			} else {
				return false;
			}
		} else {
			return true;
		}
    }
    /**
     * 上传头像 并生成缩略图
     * @param file
     * @param basePackagePath
     * @return
     */
    public static String transferHeadProtrait(MultipartFile file,String basePackagePath,String baseImagePackagePath,int imageSize) throws IOException{
    	return solvePictureUpload(file, basePackagePath, baseImagePackagePath, null, null, null, null);
    }
    
    /**
     * 将图片转换成Base64编码
     * @param imgFile 待处理图片
     * @return
     */
    public static String getImgBase64Str(String imgFile) {
        // 将图片文件转化为字节数组字符串，并对其进行Base64编码处理
        InputStream in = null;
        byte[] data = null;
        // 读取图片字节数组
        try {
            in = new FileInputStream(imgFile);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Base64.encodeBase64String(data);
    }
    
    
    /**
	 * base64字符串转化成图片
	 * 
	 * @return
	 */
	public static boolean generateImage(String imgStr,String filePackagePath,String fileName) {// 对字节数组字符串进行Base64解码并生成图片
		if (imgStr == null) // 图像数据为空
		{
			return false;
		}else {
			String[] img = imgStr.split("base64,",2);
			if(img.length > 1) {
				imgStr = img[1];
			}
		}

		BASE64Decoder decoder = new sun.misc.BASE64Decoder();
		try {
			//Base64解码
			byte[] b = decoder.decodeBuffer(imgStr);
			for (int i = 0; i < b.length; ++i) {
				if (b[i] < 0) {// 调整异常数据
					b[i] += 256;
				}
			}
	    	//指定上传目录,不指定盘符会自动保存到你的项目所在盘符
	    	File fileDir = new File(filePackagePath);
	        //目录不存在则生成目录
	        if (!fileDir.isDirectory()) {
	            fileDir.mkdirs();
	        }
			//生成图片至指定路径
			OutputStream out = new FileOutputStream(filePackagePath+fileName);
			out.write(b);
			out.flush();
			out.close();
			return true;
		} catch (Exception e) {
			log.error("Base64解析异常",e);
			return false;
		}
	}

    
    /**
     * 上传头像 并生成缩略图 base64上传
     * @param file
     * @param basePackagePath
     * @return
     */
    public static String transferHeadProtraitForBase64(String imgStr,String basePackagePath,String baseImagePackagePath,String pre) throws IOException{
    	Integer imageWidthOrHeightSize = 400;
    	Float quality = 0.8f;
		String suf = ".jpg";
		String finalName = pre + suf;
    	if(generateImage(imgStr, basePackagePath+baseImagePackagePath,finalName))
		{
    		String fileUrl = basePackagePath+baseImagePackagePath+finalName;
    		File mid = doFile(basePackagePath + baseImagePackagePath, pre + "_mid" + suf);
    		File mini = doFile(basePackagePath + baseImagePackagePath, pre + "_mini" + suf);
    		Thumbnails.of(fileUrl).size(imageWidthOrHeightSize, imageWidthOrHeightSize).outputQuality(quality).toFile(mid);// 中等尺寸
    		Thumbnails.of(fileUrl).size(200, 200).outputQuality(quality).toFile(mini);// 最小尺寸
    		//删除原图
    		new File(fileUrl).delete();
    		return baseImagePackagePath + pre + "_mini" + suf;
		}else {
			return null;
		}

		
    }
    /**
     * 
     * @param file 上传的文件名称
     * @param basePackagePath 根路径
     * @param baseImagePackagePath 文件地址的相对路径
     * @param limitKilobyte 大小限制 默认200K
     * @param imageWidthOrHeightSize 图片长宽限制 默认 400
     * @param quality 图片质量限制 默认0.8f
     * @param finalName 给定图片名称
     * @return
     * @throws IOException
     */
	public static String solvePictureUpload(MultipartFile file, String basePackagePath, String baseImagePackagePath,
			Integer limitKilobyte, Integer imageWidthOrHeightSize, Float quality, String finalName) throws IOException {
		if (imageWidthOrHeightSize == null)
			imageWidthOrHeightSize = 400;
		if (quality == null)
			quality = 0.8f;
		if (finalName == null)
			finalName = getNewFileName(file.getOriginalFilename());
		String pre = finalName.substring(0, finalName.lastIndexOf("."));
		String suf = finalName.substring(finalName.lastIndexOf("."));

		File mid = doFile(basePackagePath + baseImagePackagePath, pre + "_mid" + suf);
		File mini = doFile(basePackagePath + baseImagePackagePath, pre + "_mini" + suf);

		Thumbnails.of(file.getInputStream()).size(imageWidthOrHeightSize, imageWidthOrHeightSize).outputQuality(quality)
				.toFile(mid);// 中等尺寸
		Thumbnails.of(file.getInputStream()).size(200, 200).outputQuality(quality).toFile(mini);// 最小尺寸
		// 压缩图片
		if (limitKilobyte != null) {
			commpressPicCycle(basePackagePath + baseImagePackagePath + pre + "_mini" + suf, new Long(limitKilobyte),
					quality);
			commpressPicCycle(basePackagePath + baseImagePackagePath + pre + "_mid" + suf, new Long(limitKilobyte),
					quality);
		}
		return baseImagePackagePath + pre + "_mini" + suf;
	}
    /**
     * 图片保真上传
     * @param file
     * @param basePackagePath
     * @param baseImagePackagePath
     * @return
     * @throws IOException
     */
    public static String uploadFileWithoutLimit(
    		MultipartFile file,
    		String basePackagePath,
    		String baseImagePackagePath)  throws IOException 
    {
    	String finalName = getNewFileName(file.getOriginalFilename());
    	String pre = finalName.substring(0,finalName.lastIndexOf("."));
    	String suf = finalName.substring(finalName.lastIndexOf("."));
    	File mini = doFile(basePackagePath+baseImagePackagePath,pre+"_mini"+suf);
    	Thumbnails.of(file.getInputStream()).scale(1).toFile(mini);//最小尺寸

    	return baseImagePackagePath+pre+"_mini"+suf;
    }
    
    /**
     * 上传头像 并生成缩略图
     * @param file
     * @param basePackagePath
     * @param destFileName 目标文件名称 xxx.jpg
     * @return
     */
    public static String saveHeadProtrait(MultipartFile file,String basePackagePath,String baseImagePackagePath,int imageSize, String destFileName) throws IOException{
    	return solvePictureUpload(file, basePackagePath, baseImagePackagePath, null, null, null, destFileName);
    	// 获取新的文件名称
//        String pre = destFileName.substring(0,destFileName.lastIndexOf("."));
//        String suf = destFileName.substring(destFileName.lastIndexOf("."));
//        
////        File max = doFile(basePackagePath+baseImagePackagePath,pre+"_max"+suf);
//        File mid = doFile(basePackagePath+baseImagePackagePath,pre+"_mid"+suf);
//    	File mini = doFile(basePackagePath+baseImagePackagePath,pre+"_mini"+suf);
//        
//    	Thumbnails.of(file.getInputStream()).size(400,400).outputQuality(0.8f).toFile(mid);//中等尺寸
//    	Thumbnails.of(file.getInputStream()).size(200,200).outputQuality(0.8f).toFile(mini);//最小尺寸
//    	return baseImagePackagePath+pre+"_mini"+suf;
    }
    
    /**
	 * 压缩图片
	 * @param desPath 文件路径 (绝对路径)
	 * @param desFileSize 目标大小 kb
	 * @param accuracy 图片质量 例如: 0.8d
	 * @throws IOException
	 */
    public static void commpressPicCycle(String desPath, long desFileSize,  double accuracy) throws IOException {
        FileInputStream in = new FileInputStream(desPath);
        byte[] imgByte = new byte[in.available()];
        in.read(imgByte);
        imgByte = compressPicForScale(imgByte,desFileSize);
        FileOutputStream out = new FileOutputStream(desPath);
        out.write(imgByte);
        if(in != null) {
        	in.close();
        }
        if(out != null) {
        	out.close();
        }
    }

	public static String transferDefaultImageToDest(String basePackagePath, String basePackagePathImage, String fileName) {
		String pre = fileName.substring(0,fileName.lastIndexOf("."));
        String suf = fileName.substring(fileName.lastIndexOf("."));
        File mid = doFile(basePackagePath+basePackagePathImage,pre+"_mid"+suf);
    	File mini = doFile(basePackagePath+basePackagePathImage,pre+"_mini"+suf);
    	URL in = LocalFileUtil.class.getClassLoader().getResource("/template/person-add.png");
    	File f = new File(in.getPath());
        if(f.exists()) {
        	try {
				Files.copy(f.toPath(), mid.toPath());
				Files.copy(f.toPath(), mini.toPath()); 
				return basePackagePathImage+pre+"_mini"+suf;
			} catch (IOException e) {
				log.error("图片压缩异常",e);
				e.printStackTrace();
			} 
        }
        return null;
	}
	
	
	
	/**
     * 根据指定大小压缩图片
     *
     * @param imageBytes  源图片字节数组
     * @param desFileSize 指定图片大小，单位kb
     * @param imageId     影像编号
     * @return 压缩质量后的图片字节数组
     */
    public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize) {
        if (imageBytes == null || imageBytes.length <= 0 || imageBytes.length < desFileSize * 1024) {
            return imageBytes;
        }
        long srcSize = imageBytes.length;
        double accuracy = getAccuracy(srcSize / 1024);
        try {
            while (imageBytes.length > desFileSize * 1024) {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                Thumbnails.of(inputStream)
                        .scale(accuracy)
                        .outputQuality(accuracy)
                        .toOutputStream(outputStream);
                imageBytes = outputStream.toByteArray();
            }
        } catch (Exception e) {
        	log.error("图片指定大小压缩异常",e);
        	throw new CustomException(InfoMsg.ERROR_UPLOAD_FIELD);
        }
        return imageBytes;
    }
 
    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < 900) {
            accuracy = 0.85;
        } else if (size < 2047) {
            accuracy = 0.6;
        } else if (size < 3275) {
            accuracy = 0.44;
        } else {
            accuracy = 0.4;
        }
        return accuracy;
    }
    
    /**
     * 判断是否为允许的上传文件类型,true表示允许
     */
    public static boolean checkImage(String fileName) {
        //设置允许上传文件类型
        String suffixList = "jpg,gif,png,jpeg";
        // 获取文件后缀
        String suffix = fileName.substring(fileName.lastIndexOf(".")
                + 1, fileName.length());
        if (suffixList.contains(suffix.trim().toLowerCase())) {
            return true;
        }
        return false;
    }

}
