package com.ylcm.sys.aliyun;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import com.ylcm.sys.common.MyThreadPool;
import com.ylcm.sys.common.RarUtil;
import com.ylcm.sys.common.Util;

/**
 * aliyun 图片上传
 * @author fengyu
 *
 */
public class OSSUtil {

	private static final String ACCESS_ID = OssConfig.ACCESS_ID.val;
	private static final String ACCESS_KEY = OssConfig.ACCESS_KEY.val;

	private static final String OSS_ENDPOINT = OssConfig.OSS_ENDPOINT.val;
	
	private static final String BUCKET = OssConfig.BUCKET.val;
	
	private static Logger logger = Logger.getLogger(OSSUtil.class);
	
	/**
	 * 上传文件
	 * @param imgInput				上传文件
	 * @param key						上传文件oss地址
	 * @param size						文件大小
	 * @param contentType				文件类型
	 * @throws Exception
	 */
	public static void uploadFile(InputStream imgInput,String key, long size, String contentType)throws Exception{
		// 可以使用ClientConfiguration对象设置代理服务器、最大重试次数等参数。
        ClientConfiguration config = new ClientConfiguration();
        OSSClient client = new OSSClient(OSS_ENDPOINT, ACCESS_ID, ACCESS_KEY, config);

        try {

            // 创建上传Object的Metadata
            ObjectMetadata meta = new ObjectMetadata();
            // 必须设置ContentLength
            meta.setContentLength(size);
            meta.setContentType(contentType);
            
            // 上传Object.
            PutObjectResult result = client.putObject(BUCKET, key, imgInput, meta);
            logger.debug(result.getETag());
            
        } catch (Exception e){
            // 清理测试资源
            logger.error(e.getMessage());
            throw new Exception(e);
        }
	}
	
	/**
	 * 上传目录下的文件
	 * @param target			目标目录
	 * @param key				上传文件目录
	 * @param pkey				进度条id
	 * @param session
	 */
	public static void uploadFilesForDiv(String target, String key, String pkey, HttpSession session){
		
		List<File> list = null;
		try {
			if (Util.isNotNull(target)) {
				list = RarUtil.readfile(target);
				if(Util.isNotNull(list)){
					session.setAttribute(pkey+"_all",list.size());
					session.setAttribute(pkey+"_ok",0);
					//最多5个线程同时上传
					ExecutorService executorService = Executors.newFixedThreadPool(5);
					for (File file : list) {
						executorService.execute(new FileUpload(file, key,pkey,session));
					}
					/*当上传完成时删除目录*/
					MyThreadPool.getInstance().execute(new DeleteFilesRunnable(target, pkey, list.size(), session));
				}else{
					/*删除目录*/
					RarUtil.deletefile(target);
				}
				
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 更新进度
	 * @param pkey
	 * @param num
	 */
	public static synchronized void updateProgress(String pkey, Integer num, HttpSession session){
		try {
			Integer value= (Integer) session.getAttribute(pkey+"_ok");
			value = Util.isNotNull(value) ? value:0;
			session.setAttribute(pkey+"_ok",value+num);
		} catch (Exception e) {
			session.setAttribute(pkey+"_ok", 0);
		}
		
	}
	
	/**
	 * 获取上传进度
	 * @param pkey
	 * @param request
	 * @return
	 */
	public static Double getProgress(String pkey, HttpServletRequest request){
		Double progress = 0d;
		try {
			HttpSession session = request.getSession();
			
			Integer all = (Integer) session.getAttribute(pkey+"_all");
			Integer ok = (Integer) session.getAttribute(pkey+"_ok");
			
			if(Util.isNotNull(all) && all > 0){
				ok = Util.isNotNull(ok) ? ok : 0;
				
				progress = ok*1.0/all;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return progress;
	}
	
	/**
	 * 文件上传runnable类
	 * @author zhoucong
	 *
	 */
	private static class FileUpload implements Runnable{
		private File file;
		private String contentType;
		private String key;
		private String pkey;
		private HttpSession session;
		public FileUpload(File file, String key, String pkey, HttpSession session) {
			this.file = file;
	        try {
	        	this.key = key + file.getName();
	        	Path path = Paths.get(file.getAbsolutePath());  
	        	this.contentType = Files.probeContentType(path);
			} catch (IOException e) {
				e.printStackTrace();
			}
	        this.pkey = pkey;
	        this.session = session;
		}
		@Override
		public void run() {
			FileInputStream is = null;
			try {
				logger.info("路径:"+key);
				// 可以使用ClientConfiguration对象设置代理服务器、最大重试次数等参数。
		        ClientConfiguration config = new ClientConfiguration();
		        OSSClient client = new OSSClient(OSS_ENDPOINT, ACCESS_ID, ACCESS_KEY, config);
				if (!client.doesObjectExist(BUCKET, key)) {
					is = new FileInputStream(file);
					// 创建上传Object的Metadata
					ObjectMetadata meta = new ObjectMetadata();
					// 必须设置ContentLength
					meta.setContentLength(is.available());
					meta.setContentType(contentType);
					
					// 上传Object.
					PutObjectResult result = client.putObject(BUCKET, key, is, meta);
					
				}
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}finally {
				updateProgress(pkey, 1, session);
				if(is != null){
					try {
						is.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
	
	/**
	 * 删除目标目录下的所有文件
	 * @author zhoucong
	 *
	 */
	private static class DeleteFilesRunnable implements Runnable {
		private String target;
		private String pkey;
		private HttpSession session;
		private Integer total;
		
		public DeleteFilesRunnable(String target, String pkey, Integer total, HttpSession session) {
			this.target = target;
			this.pkey = pkey;
			this.session = session;
			this.total = total;
		}
		
		public void run() {
			try {
				Integer value= (Integer) session.getAttribute(pkey+"_ok");
				value = Util.isNull(value) ? 0:value;
				while(value < total){
					Thread.sleep(1000);
					value= (Integer) session.getAttribute(pkey+"_ok");
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					RarUtil.deletefile(target);
				} catch (FileNotFoundException e1) {
					e1.printStackTrace();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}
	}

}