package com.bcxin.survey.service.oss;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.comm.Protocol;
import com.aliyun.oss.model.CopyObjectRequest;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.bcxin.survey.utils.Const;
import com.bcxin.survey.utils.GlobalResources;

public class OSSServiceExecutor implements OSSService {

	private String server;
	private final String PROTOCOL_STRING = Protocol.HTTP + "://";
	private static final Logger logger = LoggerFactory.getLogger(OSSServiceExecutor.class);

	public OSSServiceExecutor(boolean isImgFile) {
		if ( isImgFile ) {
			String extranet = GlobalResources.OSS_SERVERADDRESSS_extranet;
			if ( GlobalResources.is_windows_envi ) {
				extranet = GlobalResources.OSS_SERVERADDRESSS;
			}
			GlobalResources.OSS_SERVERADDRESSS = extranet;
		}
		server = this.PROTOCOL_STRING + GlobalResources.OSS_BUCKETNAME + "." + GlobalResources.OSS_SERVERADDRESSS+ Const.SLASH;
	}


	@Override
	public OSSClient getClient() {
		return new OSSClient(GlobalResources.OSS_SERVERADDRESSS, GlobalResources.OSS_ACCESSID, GlobalResources.OSS_ACCESSKEY);
	}

	public String getServer(){
		return this.server;
	}

	@Override
	public OSSResultInfo createDirectory(String directoryName) {
		ObjectMetadata objectMeta = new ObjectMetadata();
		objectMeta.setContentLength(0L);
		byte[] buffer = new byte[0];
		ByteArrayInputStream in = new ByteArrayInputStream(buffer);
		OSS ossClient = getClient();
		PutObjectResult result = ossClient.putObject(GlobalResources.OSS_BUCKETNAME, directoryName
				+ "/", in, objectMeta);
		OSSResultInfo resultInfo = new OSSResultInfo();
		resultInfo.setBucketName(GlobalResources.OSS_BUCKETNAME);
		resultInfo.setName(directoryName);
		resultInfo.setTag(result.getETag());
		resultInfo.setUrl(formatUrl(this.PROTOCOL_STRING + GlobalResources.OSS_BUCKETNAME + "."
					+ GlobalResources.OSS_SERVERADDRESSS + Const.SLASH + directoryName + Const.SLASH));
		return resultInfo;
	}

	@Override
	public OSSResultInfo createDirectory(String directoryName,
			ObjectMetadata meta) {
		ObjectMetadata objectMeta = new ObjectMetadata();
		objectMeta.setContentLength(0L);
		byte[] buffer = new byte[0];
		ByteArrayInputStream in = new ByteArrayInputStream(buffer);
		OSS ossClient = getClient();
		PutObjectResult result = ossClient.putObject(GlobalResources.OSS_BUCKETNAME, directoryName
				+ Const.SLASH, in, objectMeta);
		OSSResultInfo resultInfo = new OSSResultInfo();
		resultInfo.setBucketName(GlobalResources.OSS_BUCKETNAME);
		resultInfo.setName(directoryName);
		resultInfo.setTag(result.getETag());
		resultInfo.setUrl(formatUrl(this.PROTOCOL_STRING + GlobalResources.OSS_BUCKETNAME + Const.DOT
					+ GlobalResources.OSS_SERVERADDRESSS + Const.SLASH + directoryName + Const.SLASH));
		return resultInfo;
	}

	@Override
	public boolean deleteDirectory(String directoryName) {
		OSS ossClient = getClient();
		try {
			if (directoryName.lastIndexOf("/") != directoryName.length() - 1) {
				ossClient.deleteObject(GlobalResources.OSS_BUCKETNAME, directoryName + "/");
			} else {
				ossClient.deleteObject(GlobalResources.OSS_BUCKETNAME, directoryName);
			}
			return true;
		} catch (OSSException e) {
			if (e.getErrorCode().equals("NoSuchKey")) {
				return true;
			}
			throw new OSSException("", e);
		}
	}

	@Override
	public boolean deleteFile(String fileName) {
		OSS ossClient = getClient();
		try {
			ossClient.deleteObject(GlobalResources.OSS_BUCKETNAME, fileName);
			return true;
		} catch (OSSException e) {
			if (e.getErrorCode().equals("NoSuchKey")) {
				return true;
			}
			throw new OSSException("", e);
		}
	}

	@Override
	public boolean isExitsDirectory(String directoryName) {
		OSS ossClient = getClient();
		boolean result;
		if (directoryName.lastIndexOf("/") != directoryName.length() - 1) {
			result = ossClient.doesObjectExist(GlobalResources.OSS_BUCKETNAME, directoryName + "/");
		} else {
			result = ossClient.doesObjectExist(GlobalResources.OSS_BUCKETNAME, directoryName);
		}
		return result;
	}

	@Override
	public boolean isExitsFile(String file) {
		return getClient().doesObjectExist(GlobalResources.OSS_BUCKETNAME, file);
	}

	@Override
	public OSSResultInfo put(String url, File file, boolean isCover) {
		try {
			return put(url, new FileInputStream(file), isCover);
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public OSSResultInfo put(String url, File file, ObjectMetadata meta,
			boolean isCover) {
		try {
			return put(url, new FileInputStream(file), meta, isCover);
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public OSSResultInfo put(String url, InputStream input, ObjectMetadata meta) {
		return put(url, input, meta, false);
	}

	@Override
	public OSSResultInfo put(String url, InputStream input, boolean isCover) {
		return put(url, input, null, isCover);
	}

	@Override
	public OSSResultInfo put(String url, InputStream input,
			ObjectMetadata meta, boolean isCover) {
		return putObject(url, input, meta, isCover);
	}


	private OSSResultInfo putObject(String url, InputStream input,
			ObjectMetadata meta, boolean isCover) {
		OSSClient ossClient = getClient();
		try {
			url = url.indexOf("/") == 0 ? url.substring(1) : url;
			boolean condition = (url.contains("https://"))
					|| (url.contains("http://"));
			String tmpServer = !condition ? null : url.replace("https://", "")
					.replace("http://", "").replace("//", "/").split("/")[0];
			String key = url.replace(server, "").replace("//", "/");
			if ((tmpServer == null) || (server.contains(tmpServer))) {
				if ((!isCover) && (isExitsFile(key))) {
					throw new OSSException("OSS错误，该文件已经存在！无法覆盖");
				}
				ObjectMetadata objMeta = OSSUtil.getObjectMetadata(key);
	
				String fileFix = url.split("\\.")[0];
	
				fileFix = fileFix != "" ? "." + fileFix : "";
				if (meta != null) {
					objMeta = meta;
				}
				PutObjectRequest obj = new PutObjectRequest(GlobalResources.OSS_BUCKETNAME, key, input,
						objMeta);
				logger.debug("执行文件OSS文件上传");
				PutObjectResult result = ossClient.putObject(obj);
				logger.debug("执行文件OSS文件上传成功:" + result.toString());
				try {
					input.close();
				} catch (IOException e) {
					throw new RuntimeException("关闭上传文件流失败", e);
				}
				OSSResultInfo resultInfo = new OSSResultInfo();
				resultInfo.setBucketName(GlobalResources.OSS_BUCKETNAME);
				resultInfo.setName(key);
				resultInfo.setTag(result.getETag());
				resultInfo.setUrl(formatUrl(server + key));
				resultInfo.setServerAddress(GlobalResources.OSS_SERVERADDRESSS);
				resultInfo.setHttpUrl(resultInfo.getUrl().replace("https://",
						"http://"));
				logger.debug("文件上传成功！URL：" + resultInfo.getUrl());
				return resultInfo;
			}
		} catch(Exception e){
			e.printStackTrace();
			logger.debug("exception:传入的URL地址与当前服务器地址或bucketName不一致");
		} finally {
			ossClient.shutdown();
		}
		return null;
	}

	@Override
	public File get(String url, String saveFileName) {
		String key = url.replace(server, "").replace("//", "/");
		File file = new File(saveFileName);
		OSS ossClient = getClient();
		ossClient.getObject(new GetObjectRequest(GlobalResources.OSS_BUCKETNAME, key), file);
		return file;
	}

	@Override
	public OSSResultObject get(String url) {
		url = url.indexOf("/") == 0 ? url.substring(1) : url;
		boolean condition = (url.contains("https://"))
				|| (url.contains("http://"));
		String tmpServer = !condition ? null : url.replace("https://", "")
				.replace("http://", "").replace("//", "/").split("/")[0];
		String key = url.replace(server, "").replace("//", "/");
		if ((tmpServer == null) || (server.contains(tmpServer))) {
			OSSObject obj = getClient().getObject(GlobalResources.OSS_BUCKETNAME, key);
			OSSResultObject subobj = new OSSResultObject();
			subobj.setBucketName(obj.getBucketName());
			subobj.setKey(key);
			subobj.setFileType(OSSUtil.getFileType(url));
			subobj.setName(OSSUtil.getName(url));
			subobj.setObjectContent(obj.getObjectContent());
			subobj.setMetadata(obj.getObjectMetadata());
			subobj.setUrl(formatUrl(server + key));
			subobj.setServerAddress(GlobalResources.OSS_SERVERADDRESSS);
			subobj.setHttpUrl(subobj.getUrl().replace("https://", "http://"));
			
			return subobj;
		}
		
		throw new OSSException("传入的URL地址与当前服务器地址或bucketName不一致:" + tmpServer);
	}

	@Override
	public ObjectMetadata getFileMetadata(String url) {
		OSS ossClient = getClient();
		url = url.indexOf("/") == 0 ? url.substring(1) : url;
		boolean condition = (url.contains("https://"))
				|| (url.contains("http://"));
		String tmpServer = !condition ? null : url.replace("https://", "")
				.replace("http://", "").replace("//", "/").split("/")[0];
		String key = url.replace(server, "").replace("//", "/");
		if ((tmpServer == null) || (server.contains(tmpServer))) {
			ObjectMetadata objMeta = ossClient.getObjectMetadata(GlobalResources.OSS_BUCKETNAME,
					key);
			
			return objMeta;
		}
		
		throw new OSSException("传入的URL地址与当前服务器地址或bucketName不一致:" + tmpServer);
	}


	@Override
	public String getBucketUrl() {
		return GlobalResources.OSS_BUCKETNAME + "." + GlobalResources.OSS_SERVERADDRESSS;
	}

	@Override
	public void copy(String srcPath, String desPath) {
		getClient().copyObject(GlobalResources.OSS_BUCKETNAME, getKey(srcPath), GlobalResources.OSS_BUCKETNAME,
				getKey(desPath));
	}

	@Override
	public void copy(String srcPath, String desPath, ObjectMetadata newMeta) {
		OSS ossClient = getClient();
		CopyObjectRequest obj = new CopyObjectRequest(GlobalResources.OSS_BUCKETNAME,
				getKey(srcPath), GlobalResources.OSS_BUCKETNAME, getKey(desPath));
		obj.setNewObjectMetadata(newMeta);
		ossClient.copyObject(obj);
	}

	@Override
	public void upMeta(String url, ObjectMetadata meta) {
		copy(url, url, meta);
	}

	private String formatUrl(String url) {
		return this.PROTOCOL_STRING
				+ url.replace(this.PROTOCOL_STRING, "").replace("http://", "")
						.replace("//", "/");
	}

	private String getKey(String url) {
		url = url.indexOf("/") == 0 ? url.substring(1) : url;
		String key = url.replace(server, "").replace("//", "/");
		return key;
	}
}
