package com.persagy.framework.web.controller.entrance;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.core.type.TypeReference;
import com.persagy.core.component.JsonObjectMapper;
import com.persagy.core.constant.EMSConstant.Result;
import com.persagy.core.constant.SystemConstant;
import com.persagy.core.dto.interpreter.InterfaceResult;
import com.persagy.core.mvc.service.CoreService;
import com.persagy.core.utils.CommonUtils;
import com.persagy.core.utils.HttpUtils;
import com.persagy.ems.pojo.system.FileResource;
import com.persagy.framework.construct.RequestProcessor;
import com.persagy.framework.dto.ApiResult;
import com.persagy.framework.dto.DataQueryParam;
import com.persagy.framework.dto.FileConfigDTO;
import com.persagy.framework.dto.FileResourceExtension;
import com.persagy.framework.util.CommonToolUtils;
import com.persagy.functions.weather.constant.Const;
import com.persagy.functions.weather.constant.ConstBusinessStatic;
import com.persagy.functions.weather.constant.WeatherConstant;
import com.persagy.functions.weather.thread.RequestIpStatisticThread;

/**
 * 统一对外接口
 */
@CrossOrigin
@Scope("prototype")
@Controller("unifierController")
@RequestMapping("/unifier")
@SuppressWarnings({ "unchecked", "rawtypes" })
public class UnifierController {

	private static final Logger log = Logger.getLogger(UnifierController.class);

	public static final String HANDLE_TYPE = "handleType";
	public static final String JSON_STRING = "jsonString";

	@Resource(name="coreService")
	private CoreService coreService;
	
	@Resource(name = "objectMapper")
	protected JsonObjectMapper objectMapper;
	
	@Resource
	protected ApplicationContext context;
	
	@RequestMapping(value = "/dataQuery/{" + HANDLE_TYPE + "}")
	@ResponseBody
	public ApiResult businessHandle(@PathVariable(HANDLE_TYPE) String handleType, 
			@RequestBody Map<String, Object> paramMap, HttpServletRequest request) throws Exception {
		String ip = CommonToolUtils.getIpAddr(request);
		
		
		ConstBusinessStatic.add(ip, handleType);
		RequestIpStatisticThread.addupdateIpApiEndDateMap(ip, handleType);
		
		Long start = System.currentTimeMillis();
		
		Object serviceBean = null;
		try {
			serviceBean = context.getBean(handleType);
		}catch (Exception e) {
			// TODO: handle exception
		}
		
		ApiResult apiResult = ApiResult.instanceError(null);
		RequestProcessor businessService = null;
		
		if(null == serviceBean || !(serviceBean instanceof RequestProcessor)) {
			// 请求统计接口具体服务应1存在于spring容器；2实现了RequestProcessor接口
			apiResult.setMessage("request dataType unsupport!");
			return apiResult;
		}else {
			businessService = (RequestProcessor) serviceBean;
		}
		
		try {
			
			apiResult.setData(businessService.handle(new DataQueryParam(paramMap)));
			
			apiResult.setResult(ApiResult.result_success);
		} catch (Exception e) {
			apiResult.setResult(ApiResult.result_fail);
			apiResult.setMessage(e.getMessage());
		    log.error("Request Error! requesterIp="+ip+" API=" + handleType + ", Param=" + paramMap + ", Msg=" + e.getMessage(), e);
		}

		long end = System.currentTimeMillis();
	    long timeInterval = (end - start.longValue()) / 1000;
	    if (timeInterval > 5) {
	    	log.warn("TimeCost Warning! requesterIp=" +ip+ "timeCost=" +timeInterval + "s, API=" + handleType + ", Param=" + paramMap);
	    }
	    
	    return apiResult;
	}
	
	@RequestMapping(value = "/download/icon/{param}")
	public void iconDownload(@PathVariable("param") String param, HttpServletRequest request, HttpServletResponse response) throws Exception {
		String ip = CommonToolUtils.getIpAddr(request);
		ConstBusinessStatic.add(ip, "download-icon");
		RequestIpStatisticThread.addupdateIpApiEndDateMap(ip, "download-icon");
		
		String weatherCode = "", theme = "", size = "";
		if(param != null) {
			if(param.contains("-")) {
				String[] paramArray = param.split("-");
				weatherCode = paramArray[0];
				if(paramArray.length>1) {
					theme = paramArray[1];
				}
				if(paramArray.length>2) {
					size = paramArray[2];
				}
			}else {
				weatherCode = param;
			}
		}
		
		if(WeatherConstant.getStandCodeDesc().keySet().contains(weatherCode)) {
			if(null == theme || !Const.iconTheme.contains(theme)) {
				theme = Const.iconTheme.get(0);
			}
			size = size == null ? "" : size;
			if(!Const.iconSize.keySet().contains(size)) {
				size = Const.iconSize.lastEntry().getValue();
			}else {
				size = Const.iconSize.get(size);
			}
			
			String fileName = weatherCode + "@" + size + "x.png";
			String filePath = "/static/icon/" + theme + "/" + fileName;
			
			InputStream in = this.getClass().getResourceAsStream(filePath);
			
			byte[] body = null;
			ByteArrayOutputStream output = new ByteArrayOutputStream();
			if(null != in) {
			    byte[] buffer = new byte[4096];
			    int n = 0;
			    while (-1 != (n = in.read(buffer))) {
			        output.write(buffer, 0, n);
			    }
			    body = output.toByteArray();
			    in.close();
			    output.close();
			}

			response.setContentType("image/png");
			response.getOutputStream().write(body);
			// 设置浏览器访问下载
//			response.addHeader("Content-Disposition", "attachment;filename="+fileName);
		}
	}
	
	
	@RequestMapping(value = "/download/common")
	public ResponseEntity<byte[]> unifierDownload(@RequestParam(value = "resource") String resource) throws Exception {
		if (StringUtils.isBlank(resource)) {
			throw new Exception("resource 不能为空！");
		}

		Properties properties = new Properties();
		properties.load(UnifierController.class.getResourceAsStream("/config/system.properties"));
		String fileStorageDirectory = properties.getProperty("file.storage.directory");

		FileResource fileResource = new FileResource();
		fileResource.setId(resource);
		List<FileResource> list = coreService.query(fileResource);
		if (list.size() == 0) {
			throw new Exception("未找到resource对应的配置！");
		}

		fileResource = list.get(0);

		String filePath = fileStorageDirectory + fileResource.getSubdirectory() + "/" + resource;
		File f = new File(filePath);

		// 避免中文及URL特殊字符无法正常显示
		String fileName = fileResource.getName() + "." + fileResource.getSuffix();
		fileName = URLEncoder.encode(fileName, "UTF-8");
		// fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");

		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
		headers.setContentDispositionFormData("attachment", fileName);

		byte[] body = FileUtils.readFileToByteArray(f);

		ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(body, headers, HttpStatus.CREATED);

		return responseEntity;
	}

	@RequestMapping(value = "/upload/common")
	@ResponseBody
	public InterfaceResult unifierUpload(@RequestParam(value = JSON_STRING, required = true) String jsonString,
			@RequestParam(value = "file", required = true) MultipartFile[] files) throws Exception {
		InterfaceResult interfaceResult = CommonUtils.createInterfaceResult();
		try {
			jsonString = URLDecoder.decode(jsonString, "UTF-8");
			System.out.println(jsonString);
			List<FileConfigDTO> configList = SystemConstant.jsonMapper.readValue(jsonString,
					new TypeReference<List<FileConfigDTO>>() {
					});
			if (files.length != configList.size()) {
				throw new Exception("配置文件数：" + configList.size() + "，接收文件数：" + files.length + " 不一致！");
			}
			List<FileResourceExtension> resourceList = new ArrayList<FileResourceExtension>();
			List<FileResource> resourceList1 = new ArrayList<FileResource>();
			for (int i = 0; i < files.length; i++) {
				MultipartFile file = files[i];
				String originalFilename = file.getOriginalFilename();

				FileConfigDTO fileConfig = configList.get(i);
				String suffix = fileConfig.getFileSuffix();
				String name = fileConfig.getFileName();
				String subdirectory = fileConfig.getSubdirectory();

				if ((suffix == null || "".equals(suffix)) && originalFilename.indexOf(".") != -1) {
					int index = originalFilename.lastIndexOf(".");
					suffix = originalFilename.substring(index + 1);
				}
				if ((name == null || "".equals(name)) && originalFilename.indexOf(".") != -1) {
					int index = originalFilename.lastIndexOf(".");
					name = originalFilename.substring(0, index);
				} else if (name != null && !"".equals(name) && name.indexOf(".") != -1) {
					int index = name.lastIndexOf(".");
					suffix = name.substring(index + 1);
					name = name.substring(0, index);
				}

				if (subdirectory == null || "".equals(subdirectory)) {
					throw new Exception("subdirectory 不能为空！");
				}
				if (!subdirectory.startsWith("/")) {
					throw new Exception("subdirectory 必须以/开头！");
				}

				FileResource resource = new FileResource();
				resource.setId(UUID.randomUUID().toString());
				resource.setName(name);
				resource.setSuffix(suffix);
				resource.setSubdirectory(subdirectory);
				resourceList1.add(resource);

				Properties properties = new Properties();
				properties.load(UnifierController.class.getResourceAsStream("/config/system.properties"));
				String fileStorageDirectory = properties.getProperty("file.storage.directory");

				FileResourceExtension fileResourceExtension = new FileResourceExtension();
				fileResourceExtension.setBaseDictionary(fileStorageDirectory);
				BeanUtils.copyProperties(resource, fileResourceExtension);
				resourceList.add(fileResourceExtension);

				String directory = fileStorageDirectory + subdirectory;
				String filePath = directory + "/" + resource.getId();
				File f = new File(filePath);
				FileUtils.writeByteArrayToFile(f, file.getBytes());
			}

			for (FileResource item : resourceList1) {
				coreService.save(item);
			}
			interfaceResult.getContent().addAll(resourceList);
			interfaceResult.setResult(Result.SUCCESS);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			interfaceResult.setResult(Result.FAILURE);
			interfaceResult.setReason(CommonUtils.getExceptionStackTrace(e));
			interfaceResult.getContent().clear();
			e.printStackTrace();
		}

		return interfaceResult;
	}

	@RequestMapping(value = "/upload")
	@ResponseBody
	public InterfaceResult upload(@RequestParam(value = JSON_STRING, required = true) String jsonString,
			@RequestParam(value = "file", required = true) MultipartFile[] files) throws Exception {
		InterfaceResult interfaceResult = CommonUtils.createInterfaceResult();
		try {
			jsonString = URLDecoder.decode(jsonString, "UTF-8");
			
			List<FileConfigDTO> configList = SystemConstant.jsonMapper.readValue(jsonString,
					new TypeReference<List<FileConfigDTO>>() {
					});
			if (files.length != configList.size()) {
				throw new Exception("配置文件数：" + configList.size() + "，接收文件数：" + files.length + " 不一致！");
			}
			List<FileResourceExtension> resourceList = new ArrayList<FileResourceExtension>();
			List<FileResource> resourceList1 = new ArrayList<FileResource>();
			for (int i = 0; i < files.length; i++) {
				MultipartFile file = files[i];
				String originalFilename = file.getOriginalFilename();

				FileConfigDTO fileConfig = configList.get(i);
				String suffix = fileConfig.getFileSuffix();
				String name = fileConfig.getFileName();
				String subdirectory = fileConfig.getSubdirectory();

				if ((suffix == null || "".equals(suffix)) && originalFilename.indexOf(".") != -1) {
					int index = originalFilename.lastIndexOf(".");
					suffix = originalFilename.substring(index + 1);
				}
				if ((name == null || "".equals(name)) && originalFilename.indexOf(".") != -1) {
					int index = originalFilename.lastIndexOf(".");
					name = originalFilename.substring(0, index);
				} else if (name != null && !"".equals(name) && name.indexOf(".") != -1) {
					int index = name.lastIndexOf(".");
					suffix = name.substring(index + 1);
					name = name.substring(0, index);
				}

				if (subdirectory == null || "".equals(subdirectory)) {
					throw new Exception("subdirectory 不能为空！");
				}
				if (!subdirectory.startsWith("/")) {
					throw new Exception("subdirectory 必须以/开头！");
				}

				FileResource resource = new FileResource();
				resource.setId(UUID.randomUUID().toString());
				resource.setName(name);
				resource.setSuffix(suffix);
				resource.setSubdirectory(subdirectory);
				resourceList1.add(resource);

				Properties properties = new Properties();
				properties.load(UnifierController.class.getResourceAsStream("/config/system.properties"));
				String fileStorageDirectory = properties.getProperty("file.storage.directory");

				FileResourceExtension fileResourceExtension = new FileResourceExtension();
				fileResourceExtension.setBaseDictionary(fileStorageDirectory);
				BeanUtils.copyProperties(resource, fileResourceExtension);
				resourceList.add(fileResourceExtension);

				String directory = fileStorageDirectory + subdirectory;
				String filePath = directory + "/" + resource.getId();
				File f = new File(filePath);
				FileUtils.writeByteArrayToFile(f, file.getBytes());
			}

			coreService.save(resourceList1);
			interfaceResult.getContent().addAll(resourceList);
			interfaceResult.setResult(Result.SUCCESS);

		} catch (Exception e) {
			// TODO Auto-generated catch block
			interfaceResult.setResult(Result.FAILURE);
			interfaceResult.setReason(CommonUtils.getExceptionStackTrace(e));
			interfaceResult.getContent().clear();
			e.printStackTrace();
		}

		return interfaceResult;
	}

	@RequestMapping(value = "/download")
	public ResponseEntity<byte[]> download(@RequestParam(value = "resource", required = true) String resource)
			throws Exception {

		if (resource == null || "".equals(resource)) {
			throw new Exception("resource 不能为空！");
		}

		Properties properties = new Properties();
		properties.load(UnifierController.class.getResourceAsStream("/config/system.properties"));
		String fileStorageDirectory = properties.getProperty("file.storage.directory");

		FileResource fileResource = new FileResource();
		fileResource.setId(resource);
		List<FileResource> list = coreService.query(fileResource);
		if (list.size() == 0) {

			Map params = new LinkedHashMap<>();
			params.put("resource", resource);
			List<Map> remoteList = new ArrayList<>();
			if (remoteList == null || remoteList.size() == 0) {
				throw new Exception("未找到resource对应的配置！");
			} else {
				String realDomain = "";
				String context = "";

				if ((realDomain == null) || ("".equals(realDomain))) {
					throw new Exception("根据域名未找到真实地址和端口！");
				}

				String name = (String) remoteList.get(0).get("name");
				String suffix = (String) remoteList.get(0).get("suffix");
				String subdirectory = (String) remoteList.get(0).get("subdirectory");
				fileResource.setName(name);
				fileResource.setSuffix(suffix);
				fileResource.setSubdirectory(subdirectory);
				coreService.save(fileResource);

				String filePath = fileStorageDirectory + fileResource.getSubdirectory() + "/" + resource;
				String url = "http://" + realDomain + "/" + context + "/Spring/MVC/entrance/download";
				HttpUtils.postFile(url, params, filePath);
			}
		} else {
			fileResource = list.get(0);
		}

		String filePath = fileStorageDirectory + fileResource.getSubdirectory() + "/" + resource;
		File f = new File(filePath);

		// 避免中文及URL特殊字符无法正常显示
		String fileName = fileResource.getName() + "." + fileResource.getSuffix();
		// fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
		fileName = URLEncoder.encode(fileName, "UTF-8");
		fileName = fileName.replace("+", "%20");

		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
		headers.setContentDispositionFormData("attachment", fileName);

		byte[] body = FileUtils.readFileToByteArray(f);

		ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(body, headers, HttpStatus.CREATED);

		return responseEntity;
	}

	@RequestMapping(value = "/fileSynchronization")
	@ResponseBody
	public InterfaceResult fileSynchronization(@RequestParam(value = JSON_STRING, required = true) String jsonString,
			@RequestParam(value = "file", required = true) MultipartFile[] files) throws Exception {

		InterfaceResult interfaceResult = CommonUtils.createInterfaceResult();

		try {
			jsonString = URLDecoder.decode(jsonString, "UTF-8");
			List<FileResource> configList = SystemConstant.jsonMapper.readValue(jsonString,
					new TypeReference<List<FileResource>>() {
					});
			if (files.length != configList.size()) {
				throw new Exception("配置文件数：" + configList.size() + "，接收文件数：" + files.length + " 不一致！");
			}

			Properties properties = new Properties();
			properties.load(UnifierController.class.getResourceAsStream("/config/system.properties"));
			String fileStorageDirectory = properties.getProperty("file.storage.directory");

			for (int i = 0; i < files.length; i++) {
				MultipartFile file = files[i];
				FileResource fileResource = configList.get(i);
				coreService.save(fileResource);
				String directory = fileStorageDirectory + fileResource.getSubdirectory();
				String filePath = directory + "/" + fileResource.getId();
				File f = new File(filePath);
				FileUtils.writeByteArrayToFile(f, file.getBytes());
			}

			interfaceResult.setResult(Result.SUCCESS);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			interfaceResult.setResult(Result.FAILURE);
			interfaceResult.setReason(CommonUtils.getExceptionStackTrace(e));
			interfaceResult.getContent().clear();
			e.printStackTrace();
		}
		return interfaceResult;
	}

}
