package com.uas.report.axis;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.activation.DataSource;

import com.uas.report.SpecialProperties;
import com.uas.report.util.CollectionUtils;
import com.uas.report.util.ContextUtils;
import com.uas.report.util.FileUtils;
import com.uas.report.util.StringUtils;

public class BasicResourceHandler implements ResourceHandler {

	private SpecialProperties specialProperties = ContextUtils.getBean(SpecialProperties.class);

	private FileFilter filter = new FileFilter() {
		@Override
		public boolean accept(File file) {
			if (file == null || !file.exists()) {
				return false;
			}
			// 不支持查看、压缩：jasper文件、tmp路径
			String filePath = file.getPath();
			if (filePath.endsWith(".jasper") || filePath.endsWith("tmp") || filePath.contains("\\tmp\\")
					|| filePath.contains("/tmp/")) {
				return false;
			}
			return true;
		}
	};

	public List<Resource> listResource(String resourceURI) throws FileNotFoundException, IOException {
		File dir = new File(specialProperties.getLocalBaseDir() + Folder.SEPARATOR + resourceURI);
		if (!dir.exists() || !dir.isDirectory() || !filter.accept(dir)) {
			return null;
		}
		List<Resource> resources = new ArrayList<>();
		File[] files = dir.listFiles(filter);
		for (File file : files) {
			resources.add(locateResource(file));
		}
		return resources;
	}

	public Resource locateResource(String resourceURI) throws FileNotFoundException, IOException {
		return locateResource(getFile(resourceURI));
	}

	public ResourceDescriptor locateResourceDescriptor(String resourceURI) throws FileNotFoundException, IOException {
		return locateResourceDescriptor(getFile(resourceURI));
	}

	public ResourceDescriptor locateResourceDescriptor(File file) throws FileNotFoundException, IOException {
		return toResourceDescriptor(locateResource(file));
	}

	private Resource locateResource(File file) throws FileNotFoundException, IOException {
		if (file == null || !file.exists() || !filter.accept(file)) {
			return null;
		}
		Resource resource = null;
		if (file.isDirectory()) {
			resource = new Folder();
		} else {
			resource = locateFileResource(file);
		}
		resource.setCreationDate(new Date(file.lastModified()));
		resource.setUpdateDate(new Date(file.lastModified()));
		resource.setVersion(Resource.DEFAULT_VERSION);
		resource.setName(file.getName());
		resource.setLabel(file.getName());
		resource.setDescription(file.getName());
		resource.setUri(getResourceURI(file));
		return resource;
	}

	private FileResource locateFileResource(File file) throws FileNotFoundException, IOException {
		FileResource fileResource = new FileResource();
		String fileType = getFileType(file.getName());
		if (StringUtils.isEmpty(fileType)) {
			fileResource.setFileType(ResourceDescriptor.TYPE_UNKNOW);
		} else {
			if (fileType.equalsIgnoreCase(ResourceDescriptor.TYPE_JRXML)) {
				fileResource.setFileType(ResourceDescriptor.TYPE_JRXML);
			} else if (isImage(fileType)) {
				fileResource.setFileType(ResourceDescriptor.TYPE_IMAGE);
			} else {
				fileResource.setFileType(ResourceDescriptor.TYPE_UNKNOW);
			}
		}
		fileResource.readData(new FileInputStream(file));
		return fileResource;
	}

	private boolean isImage(String fileType) {
		return fileType.toLowerCase()
				.matches("^(gif|jpg|jpeg|png|bmp|tiff|pcx|tga|exif|fpx|svg|psd|cdr|pcd|dxf|ufo|eps|ai|raw)$");
	}

	protected File getFile(String resourceURI) {
		return new File(specialProperties.getLocalBaseDir() + "/" + resourceURI);
	}

	private String getResourceURI(File file) {
		String resourceURI = file.getPath();
		resourceURI = resourceURI.replace(new File(specialProperties.getLocalBaseDir()).getPath(), "");
		resourceURI = resourceURI.replace("\\", Folder.SEPARATOR);
		if (!resourceURI.startsWith(Folder.SEPARATOR)) {
			resourceURI = Folder.SEPARATOR + resourceURI;
		}
		return resourceURI;
	}

	private String getFileType(String fileName) {
		int index = fileName.lastIndexOf(".");
		if (index < 0) {
			return null;
		}
		return fileName.substring(index + 1);
	}

	public ResourceDescriptor toResourceDescriptor(Resource resource) {
		if (resource == null) {
			return null;
		}
		ResourceDescriptor resourceDescriptor = new ResourceDescriptor();
		if (resource instanceof Folder) {
			resourceDescriptor.setWsType(ResourceDescriptor.TYPE_FOLDER);
			resourceDescriptor.setHasData(false);
		} else if (resource instanceof FileResource) {
			FileResource fileResource = (FileResource) resource;
			resourceDescriptor.setWsType(fileResource.getFileType());
			resourceDescriptor.setHasData(fileResource.hasData());
		}
		resourceDescriptor.setUriString(resource.getURIString());
		resourceDescriptor.setName(resource.getName());
		resourceDescriptor.setLabel(resource.getLabel());
		resourceDescriptor.setDescription(resource.getDescription());
		resourceDescriptor.setResourceType(resource.getResourceType());
		resourceDescriptor.setParentFolder(resource.getParentUri());
		resourceDescriptor.setVersion(resource.getVersion());
		resourceDescriptor.setCreationDate(resource.getCreationDate());
		return resourceDescriptor;
	}

	public Resource toResource(ResourceDescriptor resourceDescriptor) {
		if (resourceDescriptor == null) {
			return null;
		}
		Resource resource = null;
		String wsType = resourceDescriptor.getWsType();
		if (wsType.equals(ResourceDescriptor.TYPE_FOLDER)) {
			resource = new Folder();
			resource.setUri(resourceDescriptor.getUriString());
		} else {
			resource = toFileResource(resourceDescriptor);
		}
		resource.setName(resourceDescriptor.getName());
		resource.setLabel(resourceDescriptor.getLabel());
		resource.setDescription(resourceDescriptor.getDescription());
		resource.setParentUri(resourceDescriptor.getParentFolder());
		resource.setVersion(resourceDescriptor.getVersion());
		return resource;
	}

	private FileResource toFileResource(ResourceDescriptor resourceDescriptor) {
		FileResource fileResource = new FileResource();
		String wsType = resourceDescriptor.getWsType();
		fileResource.setFileType(wsType);
		if (resourceDescriptor.hasData()) {
			fileResource.setData(resourceDescriptor.getData());
		}
		String uriString = resourceDescriptor.getUriString();
		if (!uriString.toLowerCase().matches("^[\\s\\S]+\\.[\\S]+$")) {
			// 针对以下类型，自动添加文件后缀
			if (wsType.equals(ResourceDescriptor.TYPE_JRXML) || wsType.equals(ResourceDescriptor.TYPE_JAR)
					|| wsType.equals(ResourceDescriptor.TYPE_XML) || wsType.equals(ResourceDescriptor.TYPE_JSON)
					|| wsType.equals(ResourceDescriptor.TYPE_CSS)) {
				uriString += "." + wsType;
			} else {
				throw new IllegalStateException("请指定文件后缀");
			}
		}
		fileResource.setUri(uriString);
		return fileResource;
	}

	/**
	 * Return a list of ResourceDescriptor(s)
	 * 
	 * @throws IOException
	 * @throws FileNotFoundException
	 * 
	 * @throws WSException
	 */
	public List<ResourceDescriptor> listResourceDescriptors(String uri) throws FileNotFoundException, IOException {
		List<ResourceDescriptor> returnedMaps = new ArrayList<>();

		List<Resource> resources = listResource(uri);
		if (CollectionUtils.isEmpty(resources)) {
			return returnedMaps;
		}
		for (Resource resource : resources) {
			returnedMaps.add(toResourceDescriptor(resource));
		}

		/*
		 * // This filters with object level security. // Will only get folders
		 * the user has access to
		 * 
		 * List<Resource> folders = getRepository().getSubFolders(null, uri);
		 * filterFolderList(folders);
		 * 
		 * if (folders == null) return returnedMaps;
		 * 
		 * for (int i = 0; i < folders.size(); ++i) { Resource folderRes =
		 * folders.get(i);
		 * returnedMaps.add(createResourceDescriptor(folderRes)); }
		 * 
		 * // create a criteria for finding things with a common parent folder.
		 * FilterCriteria filterCriteria = new FilterCriteria();
		 * filterCriteria.addFilterElement(FilterCriteria.
		 * createParentFolderFilter(uri));
		 * 
		 * // This filters with object level security // Will only get resources
		 * the user has access to
		 * 
		 * List units = getRepository().loadClientResources(filterCriteria);
		 * 
		 * if (units == null) return returnedMaps;
		 * 
		 * for (Iterator it = units.iterator(); units != null && it.hasNext();)
		 * { Resource fileRes = (Resource) it.next(); try {
		 * returnedMaps.add(createResourceDescriptor(fileRes)); } catch
		 * (Exception ex) { logger.error(ex); } }
		 */

		return returnedMaps;
	}

	public Class<?> getResourceType() {
		return null;
	}

	public ResourceDescriptor put(Request request) throws FileNotFoundException, IOException {
		ResourceDescriptor resourceDescriptor = request.getResourceDescriptor();
		Resource resource = toResource(resourceDescriptor);
		String resourceURI = resource.getURIString();
		File file = getFile(resourceURI);
		if (resourceDescriptor.isNew()) {
			if (resource instanceof Folder) {
				file.mkdirs();
			} else {
				if (file.exists()) {
					throw new IOException("文件已存在！");
				}
				FileResource fileResource = (FileResource) resource;
				FileUtils.write(file.getPath(), fileResource.getData());
			}
		} else {
			if (resource instanceof Folder) {
				// TODO
			} else {
				FileResource fileResource = (FileResource) resource;
				FileUtils.write(file.getPath(), fileResource.getData());
			}
		}
		resource = locateResource(file);
		resourceDescriptor = toResourceDescriptor(resource);
		return resourceDescriptor;
	}

	@Override
	public void delete(ResourceDescriptor descriptor) throws IOException {
		File file = checkFile(descriptor.getUriString());
		FileUtils.delete(file, true);
	}

	@Override
	public void move(ResourceDescriptor descriptor, String destinationURI) throws IOException {
		File file = checkFile(descriptor.getUriString());
		FileUtils.move(file, new File(getFile(destinationURI), file.getName()));
	}

	@Override
	public ResourceDescriptor copy(ResourceDescriptor descriptor, String destinationURI) throws IOException {
		File file = checkFile(descriptor.getUriString());
		// 与move操作的destinationURI不一样
		File dest = getFile(destinationURI);
		FileUtils.copy(file, dest);
		return locateResourceDescriptor(dest);
	}

	@Override
	public Map<String, DataSource> getAttachments(Map<String, String> arguments, ResourceDescriptor descriptor)
			throws WSException {
		// default implementation does nothing
		return null;
	}

	protected File checkFile(String uriString) throws IOException {
		// default implementation does nothing
		return null;
	}

	public String getDestinationURI(Request request) throws WSException {
		String destinationURI = request.getArgumentValue(Argument.DESTINATION_URI);
		if (destinationURI == null) {
			throw new WSException(WSException.GENERAL_REQUEST_ERROR, "未传递参数DESTINATION_URI");
		}
		return destinationURI;
	}
}
