package ${vhGrpcBuilder_packageName}.${vhGrpcBuilder_sprojectName}.util;

import com.google.protobuf.ByteString;
import com.viewhigh.vhsc.svc.utility.proto.DeleteReq;
import com.viewhigh.vhsc.svc.utility.proto.S3ServiceGrpc;
import com.viewhigh.vhsc.svc.utility.proto.UploadReq;
import com.viewhigh.vhsc.svc.utility.proto.UploadResp;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * Created by user on 2017/7/5.
 */
@Component
public class S3Util {

    private static final Logger logger = LoggerFactory.getLogger(S3Util.class);
    private static final String FILE_TYPE = "ffd8ffe0 ffd8ffe1 89504e47 47494638";

    @Value("${s3Gateway.bucket}")
    private String s3Bucket;
    @Value("${s3Gateway.url}")
    private String s3Url;
    
    private final int PUBLIC_ACCESS = 0;
    
	@Autowired
    private S3ServiceGrpc.S3ServiceBlockingStub s3Service;

	public String updateFileGetFullUrl(String fileName,byte[] filebytes,Long sid) {
    	String s3FileName = generateS3nameWithSidByFilename(fileName,sid);
		s3uploadWithS3nameAndBytes(s3FileName,filebytes,PUBLIC_ACCESS);
		if(!s3Url.endsWith("/")){
			s3Url = s3Url + "/";
		}
		return s3Url+s3FileName;
	}
	
	public String updateFileGetFullUrl(String fileName,byte[] filebytes,Long sid,int angle) {
    	//String s3FileName = generateS3nameWithSidByFilename(fileName,sid);
		s3uploadWithS3nameAndBytes(fileName,filebytes,PUBLIC_ACCESS,angle);
		if(!s3Url.endsWith("/")){
			s3Url = s3Url + "/";
		}
		return s3Url+fileName;
	}
	
    private String generateS3nameWithSidByFilename(String filename,Long sid){
        return StringUtils.join(sid.toString(),"/",generateS3nameByfilename(filename));
    }
    
    /**
     * generate a 18 words file name
     * with a MMddHHmm format suffix
     * @param filename
     * @return
     */
    private String generateS3nameByfilename(String filename){
        String suffix = FilenameUtils.getExtension(filename);
        return String.format("%s%s.%s",
                RandomStringUtils.randomAlphanumeric(10),
                new SimpleDateFormat("MMddHHmm").format(new Date()),
                suffix.toLowerCase()
        );
    }
    
    private String s3uploadWithS3nameAndBytes(String s3FileName,byte[] bytes,Integer isprivate) {
		UploadResp resp = s3Service.upload(
			UploadReq.newBuilder()
			.setBucket(s3Bucket)
			.setName(s3FileName)
			.setObj(ByteString.copyFrom(bytes))
			.setMode(isprivate)
			.build()
		);
		return resp.getName();
	}
    
    private String s3uploadWithS3nameAndBytes(String s3FileName,byte[] bytes,Integer isprivate,int angle) {
		UploadResp resp = s3Service.upload(
			UploadReq.newBuilder()
			.setBucket(s3Bucket)
			.setName(s3FileName)
			.setObj(ByteString.copyFrom(bytes))
			.setMode(isprivate).setAngle(angle)
			.build()
		);
		return resp.getName();
	}
    /**
     * 删除文件
     * @param fileList fileUrl s3文件全路径
     */
    public void deleteFiles(List<String> fileList){
        for (String fileUrl :fileList) {
            try {
                logger.info("begin to call s3 to delete {}",fileUrl);
                DeleteReq.Builder builder = DeleteReq.newBuilder();
                String s3FileName = "";
                if(s3Url.endsWith("/")){
                	s3FileName = fileUrl.substring(s3Url.length());
                }else{
                	s3FileName = fileUrl.substring(s3Url.length()+1);
                }
                builder.setBucket(s3Bucket).setName(s3FileName);
                s3Service.delete(builder.build());
                logger.info("file: {} deleted",fileUrl);
            } catch (Exception ex){
                logger.error("error when delete file: {}",fileUrl,ex);
            }
        }
    }
    
    /**
	 * 判断文件格式是否是有效的
	 *
	 * @return true ： 有效   false ：文件格式错误
	 */
	public boolean checkFileIsValid(MultipartFile file) {
	    String fileName = file.getOriginalFilename();// 文件名
	    String fileExtension = ""; // 文件扩展名 
	    fileExtension = fileName.substring(fileName.lastIndexOf("."));
	    if (".png".equals(fileExtension.toLowerCase())) {
	        return true;
	    } else if (".jpg".equals(fileExtension.toLowerCase())) {
	        return true;
	    }else if (".gif".equals(fileExtension.toLowerCase())) {
	        return true;
	    } else {
	        return false;
	    }
	}
	
    /**
     * 上传文件验证
     * 图片大小在2M以内，仅支持jpg、gif、png格式
     */
	public  int  validateType(MultipartFile fileTmp) {
		// 定义数值格式化
		DecimalFormat df = new DecimalFormat("#.0000");
		// 定义byte数组，存储文件路径
		byte[] b = null;
		// 定义文件类型是否正确属性
		int Validate = 0;
		// 定义文件大小
		double filesize;
		/* =============文件格式的校验================== */
		if (!fileTmp.isEmpty()) {
			try {
				b = fileTmp.getBytes();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}

		if (b != null) {
			// 文件长度
			int size = b.length;
			// 定义16进制变量
			String hex = null;
			// 定义变量存储文件头前四位信息
			StringBuilder contentType = new StringBuilder();
			for (int i = 0; i < size; i++) {
				// 循环获取前4位文件信息
				hex = Integer.toHexString(b[i] & 0xFF);
				if (hex.length() == 1) {
					hex = "0" + hex;
				}
				contentType.append(hex);
				// 获取完毕前4位，退出
				if (i > 2)
					break;
			}
			if (!(FILE_TYPE.indexOf(contentType.toString()) > -1)) {
				// 判断文件类型是否存在于预定义的FILE_TYPE类型中
			   Validate = 1;
			   return Validate;
			} else {
				boolean tf = checkFileIsValid(fileTmp);
				if (tf == false) {
					// 判断文件后缀名是否是png,jpg,gif
					Validate = 1;
					return Validate;
				}
			}
		}

		/* =============文件大小的校验================== */
		filesize = Double.parseDouble(df.format((double) (fileTmp.getSize()) / 1024 / 1024));
		// 判断文件大小，不能等于0M，不能大于2M
		if (!(filesize > 0 && filesize <= 2)) {
			Validate = 2;
			return Validate;
		}
		return Validate;
	}
	
}
