package com.bocloud.ims.service.resource;

import com.bocloud.cmp.driver.storage.ObjectStorageDriver;
import com.bocloud.cmp.model.ObjectStorageContainerModel;
import com.bocloud.cmp.model.ObjectStorageItemModel;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.ObjectStorageContainer;
import com.bocloud.ims.entity.resource.ObjectStorageItem;
import com.bocloud.ims.interfaces.resource.ObjectStorageService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.ObjectStorageContainerRepository;
import com.bocloud.ims.repository.resource.ObjectStorageItemRepository;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by Administrator on 2017/9/4.
 */
@Service("objectStorageService")
public class ObjectStorageServiceImpl implements ObjectStorageService {

	Logger logger = LoggerFactory.getLogger(this.getClass().getName());

	Pattern pattern = Pattern.compile("^[\\d]+_");

	@Autowired
	private ObjectStorageDriver objectStorageDriver;

	@Autowired
	private ObjectStorageContainerRepository objectStorageContainerRepository;

	@Autowired
	private ObjectStorageItemRepository objectStorageItemRepository;

	@Autowired
	private CloudVendorRepository cloudVendorRepository;

	@Autowired
	private ResourceEventPublisher resourceEventPublisher;

	@Override
	public BocloudResult<List<Map<String, Object>>> listContainer(Pager pager, RequestContext context) {
		List<Map<String, Object>> retVal = Lists.newArrayList();
		try {
			int page = pager.getPage();
			int rows = pager.getRows();
			List<Param> params = pager.getParams();
			Map<String, String> sorter = pager.getSorter();
			boolean simple = pager.getSimple();

			List<ObjectStorageContainer> queryList = objectStorageContainerRepository
					.listContainer(context.getTarget());

			if (!ListTool.isEmpty(queryList)) {
				// 处理名字，因为openstack那边，是用名称来表示容器的，所以给那边传的container名称是用户id+"_"+名称,这边需要去掉
				for (ObjectStorageContainer objectStorageContainer : queryList) {
					Matcher matcher = pattern.matcher(objectStorageContainer.getName());
					objectStorageContainer.setName(matcher.replaceFirst(""));
				}
				Map<Long, List<ObjectStorageContainer>> vendorIdAndConstainerList = Maps.newHashMap();
				for (ObjectStorageContainer container : queryList) {
					if (container.getVendorId() == null) {
						continue;
					}
					List<ObjectStorageContainer> containerList = null;
					if (vendorIdAndConstainerList.containsKey(container.getVendorId())) {
						containerList = vendorIdAndConstainerList.get(container.getVendorId());
					} else {
						containerList = new ArrayList<>();
						vendorIdAndConstainerList.put(container.getVendorId(), containerList);
					}
					containerList.add(container);
				}
				Set<Long> ids = vendorIdAndConstainerList.keySet();

				for (Long id : ids) {
					Map<String, Object> map = Maps.newHashMap();
					map.put("id", id);
					List<ObjectStorageContainer> objectStorageContainers = vendorIdAndConstainerList.get(id);
					map.put("name", objectStorageContainers.get(0).getVendorName());
					map.put("list", objectStorageContainers);
					retVal.add(map);
				}

			}

		} catch (Exception e) {
			logger.error("查询出错", e);
			return new BocloudResult<>(false, "查询失败");
		}
		return new BocloudResult<>(true, retVal, "查询成功");
	}

	@Override
	public BocloudResult create(ObjectStorageContainer container, RequestContext context) {
		try {
			String containerName = context.getTarget() + "_" + container.getName();
			ObjectStorageContainer queryResult = objectStorageContainerRepository.getByName(containerName);
			if (queryResult != null) {
				return new BocloudResult<>(false, "该名称已经存在");
			}
			CloudVendor cloudVendor = cloudVendorRepository.query(container.getVendorId());
			if (null == cloudVendor) {
				return new BocloudResult<>(false, "云平台不存在");
			}
			String uuid = cloudVendor.getUuid();
			container.setVendorId(cloudVendor.getId());
			container.setVendorName(cloudVendor.getName());
			container.setCreatorId(context.getTarget());
			container.setName(containerName);
			container.setOwnerId(context.getTarget());
			objectStorageContainerRepository.save(container);
			ObjectStorageContainerModel containerModel = new ObjectStorageContainerModel();
			BeanUtils.copyProperties(container, containerModel);
			BocloudResult result = objectStorageDriver.create(containerModel, uuid, null);
			if (result.isSuccess()) {
				BocloudResult detail = objectStorageDriver.detail(containerModel, uuid, null);
				ObjectStorageContainer newContainer = (ObjectStorageContainer) detail.getData();
				container.setItemCount(newContainer.getItemCount());
				container.setSize(newContainer.getSize());
				container.setCreateTime(newContainer.getCreateTime());
				objectStorageContainerRepository.update(container);
				return new BocloudResult<>(true, result, "创建成功");
			}
		} catch (Exception e) {
			logger.error("创建失败", e);
			return new BocloudResult<>(false, "创建失败");
		}
		return new BocloudResult<>(false, "创建失败");
	}

	@Override
	public BocloudResult<ObjectStorageContainer> detailContainer(Long containerId, RequestContext context) {
		try {
			ObjectStorageContainer container = objectStorageContainerRepository.get(ObjectStorageContainer.class,
					containerId, context.getTarget());
			if (container != null) {
				return new BocloudResult<>(true, container, "查询成功");
			}
		} catch (Exception e) {
			logger.error("创建失败", e);
			return new BocloudResult<>(false, "创建失败");
		}
		return new BocloudResult<>(false, "创建失败");
	}

	@Override
	public BocloudResult removeContainer(Long id, RequestContext context) {
		ObjectStorageContainer container = null;
		BocloudResult result = null;
		try {
			container = objectStorageContainerRepository.get(ObjectStorageContainer.class, id, context.getTarget());
			if (container == null) {
				return new BocloudResult<>(false, "容器不存在");
			}
			CloudVendor cloudVendor = cloudVendorRepository.query(container.getVendorId());
			if (null == cloudVendor) {
				return new BocloudResult<>(false, "云平台不存在");
			}

			List<ObjectStorageItem> objectStorageItems = objectStorageItemRepository
					.listByContainerId(container.getId(), "", context.getTarget());
			if (!ListTool.isEmpty(objectStorageItems)) {
				return new BocloudResult<>(false, "容器非空，不能删除");
			}

			ObjectStorageContainerModel containerModel = new ObjectStorageContainerModel();
			BeanUtils.copyProperties(container, containerModel);
			result = objectStorageDriver.remove(containerModel, cloudVendor.getUuid(), null);
		} catch (Exception e) {
			logger.error("远程删除失败", e);
			return new BocloudResult<>(false, "删除失败");
		}
		if (result.isSuccess()) {
			boolean deleted = false;
			try {
				deleted = objectStorageContainerRepository.delete(id, context.getTarget());
			} catch (Exception e) {
				logger.error("删除失败", e);
			}
			if (deleted) {
				return new BocloudResult<>(true, "删除成功");
			} else {
				return new BocloudResult<>(false, "远程删除成功，本地数据库删除失败");
			}
		} else {
			return new BocloudResult<>(false, "删除失败");
		}
	}

	@Override
	public BocloudResult<List<ObjectStorageItem>> listItems(Long containerId, String name, RequestContext context) {
		try {
			List<ObjectStorageItem> objectStorageItems = objectStorageItemRepository.listByContainerId(containerId,
					name, context.getTarget());
			return new BocloudResult<>(true, objectStorageItems, "查询成功");
		} catch (Exception e) {
			logger.error("查询失败", e);
			return new BocloudResult<>(false, "查询失败");
		}
	}

	@Override
	public BocloudResult create(ObjectStorageItem item, RequestContext context, String invokerPath) {
		CloudVendor cloudVendor = null;
		BocloudResult result = null;
		try {
			if (item.getIsDirectory() == 0) {
				item.setName(checkFilePath(item.getName()));
			} else {
				item.setName(checkDirectoryPath(item.getName()));
			}
			Long containerId = item.getContainerId();
			ObjectStorageContainer container = objectStorageContainerRepository.get(ObjectStorageContainer.class,
					containerId, context.getTarget());
			// 判断是否存在
			ObjectStorageItem itemByQuery = objectStorageItemRepository.getByName(item.getName(), containerId);
			if (itemByQuery != null) {
				return new BocloudResult<>(false, "该对象已存在");
			}
			if (container == null) {
				return new BocloudResult<>(false, "对象容器不存在");
			}
			cloudVendor = cloudVendorRepository.query(container.getVendorId());
			if (null == cloudVendor) {
				return new BocloudResult<>(false, "云平台不存在");
			}
			Long vendorId = cloudVendor.getId();
			String uuid = cloudVendor.getUuid();
			item.setVendorId(vendorId);
			item.setCreatorId(context.getTarget());
			item.setUpdateTime(new Date());
			item.setOwnerId(context.getTarget());
			item.setOrigFilename(item.getUploadUrl());
			item.setContainerName(context.getTarget() + "_" + item.getContainerName());
			ObjectStorageItemModel itemModel = new ObjectStorageItemModel();
			BeanUtils.copyProperties(item, itemModel);
			result = objectStorageDriver.create(itemModel, uuid, null, invokerPath);
			if (result.isSuccess()) {
				if (result.getData() != null) {
					ObjectStorageItemModel retModel = (ObjectStorageItemModel) result.getData();
					item.setContentType(retModel.getContentType());
					item.setUploadUrl(retModel.getUploadUrl());
					item.setHash(retModel.getHash());
					item.setSize(retModel.getSize());
					item.setOrigFilename(retModel.getOrigFilename());
					item.setIsDirectory(retModel.getIsDirectory());
					item.setUpdateTime(retModel.getUpdateTime());
					objectStorageItemRepository.save(item);
				}
				updateContainerInfo(containerId, item.getContainerName(), item.getOwnerId(), vendorId, uuid);
				if (item.getId() != null) {
					result = new BocloudResult<>(true, result, "对象存储创建成功");
					sendCreateMessage(cloudVendor, result, context);
					return result;
				} else {
					result = new BocloudResult<>(true, result, "对象存储远程创建成功,本地存储失败,请同步");
					sendCreateMessage(cloudVendor, result, context);
					return result;
				}
			} else {
				result = new BocloudResult<>(true, result, "创建对象存储失败");
				sendCreateMessage(cloudVendor, result, context);
				return new BocloudResult<>(false, "创建失败");
			}
		} catch (Exception e) {
			logger.error("创建失败", e);
			if (null != cloudVendor && null != result) {
				sendCreateMessage(cloudVendor, result, context);
			}
			return new BocloudResult<>(false, "创建失败");
		}
	}

	private void updateContainerInfo(Long containerId, String containerName, Long userId, Long vendorId,
			String vendorUUid) throws Exception {
		ObjectStorageContainer container = new ObjectStorageContainer();
		ObjectStorageContainerModel model = new ObjectStorageContainerModel();
		container.setId(containerId);
		container.setName(containerName);
		container.setVendorId(vendorId);
		container.setCreatorId(userId);
		container.setOwnerId(userId);
		model.setName(containerName);
		BocloudResult detail = objectStorageDriver.detail(model, vendorUUid, null);
		if (detail.isSuccess()) {
			ObjectStorageContainer newContainer = (ObjectStorageContainer) detail.getData();
			container.setItemCount(newContainer.getItemCount());
			container.setSize(newContainer.getSize());
			container.setCreateTime(newContainer.getCreateTime());
			container.setVendorId(vendorId);
			objectStorageContainerRepository.update(container);
		}
	}

	private void sendCreateMessage(CloudVendor vendor, BocloudResult result, RequestContext context) {
		String type = vendor.getType();
		String operate = type.toLowerCase() + ".objectstorage";
		try {
			resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
					MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
					context));
		} catch (Exception e) {
			logger.error("发送消息失败", e);
		}
	}

	@Override
	public BocloudResult<ObjectStorageItem> detailItem(Long itemId, RequestContext context) {
		try {
			ObjectStorageItem item = objectStorageItemRepository.get(ObjectStorageItem.class, itemId);
			Long containerId = item.getContainerId();
			ObjectStorageContainer container = objectStorageContainerRepository.get(ObjectStorageContainer.class,
					containerId, context.getTarget());
			if (container == null) {
				return new BocloudResult<>(false, "对象不存在");
			}
			return new BocloudResult<>(true, item, "查询成功");
		} catch (Exception e) {
			logger.error("创建失败", e);
			return new BocloudResult<>(false, "创建失败");
		}

	}

	@Override
	public BocloudResult removeItem(Long id, Long reqContainerId, String path, RequestContext context) {
		ObjectStorageItem item = null;
		BocloudResult result = null;
		CloudVendor cloudVendor = null;
		try {
			if (id != null) {
				Long containerId = null;
				item = objectStorageItemRepository.get(ObjectStorageItem.class, id);
				containerId = item.getContainerId();
				ObjectStorageContainer container = objectStorageContainerRepository.get(ObjectStorageContainer.class,
						containerId, context.getTarget());
				if (container == null) {
					return new BocloudResult<>(false, "对象不存在");
				}
				ObjectStorageItemModel itemModel = new ObjectStorageItemModel();
				BeanUtils.copyProperties(item, itemModel);
				cloudVendor = cloudVendorRepository.get(CloudVendor.class, item.getVendorId());
				if (cloudVendor == null) {
					return new BocloudResult<>(false, "找不到vendor");
				}
				result = objectStorageDriver.remove(itemModel, cloudVendor.getUuid(), null);
				if (result.isSuccess()) {
					boolean deleted = false;
					try {
						deleted = objectStorageItemRepository.delete(id, context.getTarget());
						updateContainerInfo(containerId, item.getContainerName(), item.getOwnerId(),
								cloudVendor.getId(), cloudVendor.getUuid());
					} catch (Exception e) {
						logger.error("删除失败", e);
					}
					if (deleted) {
						return new BocloudResult<>(true, "删除成功");
					} else {
						return new BocloudResult<>(false, "远程删除成功，本地数据库删除失败");
					}
				}
			} else if (reqContainerId != null && StringUtils.isNotEmpty(path)) {
				List<ObjectStorageItem> objectStorageItems = objectStorageItemRepository
						.listByContainerId(reqContainerId, path, context.getTarget());
				if (!ListTool.isEmpty(objectStorageItems)) {
					ObjectStorageItem firstOne = objectStorageItems.get(0);
					Long vendorId = firstOne.getVendorId();
					String containerName = firstOne.getContainerName();
					cloudVendor = cloudVendorRepository.get(CloudVendor.class, vendorId);
					if (cloudVendor == null) {
						return new BocloudResult<>(false, "找不到vendor");
					}
					for (ObjectStorageItem objectStorageItem : objectStorageItems) {
						ObjectStorageItemModel itemModel = new ObjectStorageItemModel();
						BeanUtils.copyProperties(objectStorageItem, itemModel);
						result = objectStorageDriver.remove(itemModel, cloudVendor.getUuid(), null);
						if (result.isSuccess()) {
							objectStorageItemRepository.delete(objectStorageItem.getId(), context.getTarget());
						}
					}
					updateContainerInfo(reqContainerId, containerName, context.getTarget(), cloudVendor.getId(),
							cloudVendor.getUuid());
					return new BocloudResult<>(true, "删除成功");
				}

			}
		} catch (Exception e) {
			logger.error("远程删除失败", e);
			return new BocloudResult<>(false, "删除失败");
		}
		return new BocloudResult<>(false, "删除失败");
	}

	@SuppressWarnings("unchecked")
	@Override
	public BocloudResult<List<ObjectStorageItem>> getTreeView(Long containerId, String path, RequestContext context) {
		BocloudResult bocloudResult = listItems(containerId, path, context);
		if (bocloudResult.isSuccess()) {
			List<ObjectStorageItem> objectStorageItems = convertItemView(
					(List<ObjectStorageItem>) bocloudResult.getData(), path);
			replacePathInName(path, objectStorageItems);
			bocloudResult.setData(objectStorageItems);
		}
		return bocloudResult;
	}

	/**
	 * 后台返回的数据，name为 下面的结构 aasdf/ abc/ccc/ abc/ccc/frery ferry_obj 需要转换为 aasdf/ abc/
	 * (这个需要新增) abc/ccc/ abc/ccc/frery ferry_obj
	 *
	 * @param items
	 * @return
	 */
	private List<ObjectStorageItem> convertItemView(List<ObjectStorageItem> items, String path) {
		Map<String, ObjectStorageItem> directories = Maps.newHashMap();
		if (!ListTool.isEmpty(items)) {
			// 生成中间目录 aaa/bbb/ccc 转成 aaa/ aaa/bbb/
			for (ObjectStorageItem item : items) {
				parseToDirecotryItem(item, directories);
			}
			// 将元素放进目录
			for (ObjectStorageItem item : items) {
				if (item.getIsDirectory() == 0) {
					putItemIntoDirectory(item, directories);
				}
			}
			// 处理目录
			putDirectoryIntoDirectory(directories);
			List<ObjectStorageItem> result = Lists.newArrayList();
			result.addAll(directories.values());
			// 处理根目录的文件
			for (ObjectStorageItem item : items) {
				if (!item.getName().contains("/")) { // 没有 / 的在根目录下
					result.add(item);
				}
			}

			if (StringUtils.isNotEmpty(path) && result.size() > 0) {
				String[] leveledPath = path.split("/");
				return findMatchedChildren(leveledPath, result, 0);
			}
			return result;
		} else {
			return items;
		}
	}

	private int countChar(String str, Character theChar) {
		int occurs = 0;
		for (int i = 0; i < str.length(); i++) {
			if (theChar.equals(str.charAt(i))) {
				occurs++;
			}
		}
		return occurs;
	}

	private void parseToDirecotryItem(ObjectStorageItem item, Map<String, ObjectStorageItem> directories) {
		Set<String> keys = directories.keySet();
		String name = item.getName();
		Long containerId = item.getContainerId();
		boolean lastItemIsDirectory = item.getIsDirectory() == 1;
		if (name.contains("/")) { // 说明有目录
			String[] split = name.split("/");
			String tempName = "";
			for (int i = 0; i < split.length; i++) { // 将item的所有的目录解析出来,放到map里
				tempName = tempName + split[i] + "/";
				if (keys.contains(tempName)) {
					continue;
				} else if ((i != split.length - 1) || (i == split.length - 1 && lastItemIsDirectory)) {
					ObjectStorageItem newItem = new ObjectStorageItem();
					newItem.setName(tempName);
					newItem.setIsDirectory(1);
					newItem.setContainerId(containerId);
					directories.put(tempName, newItem);
				}
			}
		}
	}

	private void putItemIntoDirectory(ObjectStorageItem item, Map<String, ObjectStorageItem> directories) {
		String name = item.getName();
		Set<String> directoryPaths = directories.keySet();
		for (String directoryPath : directoryPaths) {
			if (name.indexOf(directoryPath) == 0 && name.lastIndexOf("/") == directoryPath.lastIndexOf("/")) {
				ObjectStorageItem objectStorageItem = directories.get(directoryPath);
				List<ObjectStorageItem> children = objectStorageItem.getChildren() == null ? Lists.newArrayList()
						: objectStorageItem.getChildren();
				children.add(item);
				objectStorageItem.setChildren(children);
			}
		}
	}

	private void putDirectoryIntoDirectory(Map<String, ObjectStorageItem> directories) {
		List<String> keysToRemove = Lists.newArrayList();
		Set<String> keys = directories.keySet();
		for (String childKey : keys) {
			Iterator<String> iterator = keys.iterator();
			while (iterator.hasNext()) {
				String parentKey = iterator.next();
				if (childKey.indexOf(parentKey) == 0 && countChar(childKey, '/') == countChar(parentKey, '/') + 1) {
					ObjectStorageItem son = directories.get(childKey);
					ObjectStorageItem parent = directories.get(parentKey);
					List<ObjectStorageItem> children = parent.getChildren() == null ? Lists.newArrayList()
							: parent.getChildren();
					children.add(son);
					keysToRemove.add(childKey);
					parent.setChildren(children);
				}
			}
		}
		for (String rmKey : keysToRemove) {
			directories.remove(rmKey);
		}
	}

	private List<ObjectStorageItem> findMatchedChildren(String[] splitArray, List<ObjectStorageItem> items,
			int current) {
		String currentPath = "";
		if (splitArray.length > 0) {
			for (int i = 0; i <= current; i++) {
				currentPath = currentPath + splitArray[i] + "/";
			}
			for (ObjectStorageItem item : items) {
				if (item.getIsDirectory() == 1 && currentPath.equals(item.getName())
						&& !ListTool.isEmpty(item.getChildren())) {
					if (current == splitArray.length - 1) {
						return item.getChildren();
					} else {
						return findMatchedChildren(splitArray, item.getChildren(), current + 1);
					}
				}
			}
		}
		return Lists.newArrayList();
	}

	/**
	 * 去掉名称里面的path
	 *
	 * @param path
	 * @param items
	 */
	private void replacePathInName(String path, List<ObjectStorageItem> items) {
		if (StringUtils.isNotEmpty(path) && !ListTool.isEmpty(items)) {
			for (ObjectStorageItem item : items) {
				if (item.getName().indexOf(path) == 0) {
					item.setName(item.getName().replaceFirst(path, ""));
				}
			}
		}

	}

	/**
	 * 转换为目录路径
	 */
	private String checkDirectoryPath(String path) {
		path = path.replaceAll("[/]{2,}", "/");
		if (path.charAt((path.length() - 1)) != '/') {
			path = path + "/";
		}
		if (path.charAt(0) == '/') {
			path = path.substring(1);
		}
		return path;
	}

	/**
	 * 转换为文件路径
	 */
	private String checkFilePath(String path) {
		path = path.replaceAll("[/]{2,}", "/");
		if (path.charAt((path.length() - 1)) == '/') {
			path = path.substring(0, path.length() - 1);
		}
		if (path.charAt(0) == '/') {
			path = path.substring(1);
		}
		return path;
	}

	@Override
	public InputStream download(Long id, RequestContext context) {
		ObjectStorageItem item = null;
		try {
			item = objectStorageItemRepository.get(ObjectStorageItem.class, id);
		} catch (Exception e) {
			logger.error("查询存储失败", e);
			return null;
		}
		if (item == null) {
			return null;
		}
		ObjectStorageItemModel itemModel = new ObjectStorageItemModel();
		BeanUtils.copyProperties(item, itemModel);
		CloudVendor cloudVendor = null;
		try {
			cloudVendor = cloudVendorRepository.get(CloudVendor.class, item.getVendorId());
		} catch (Exception e) {
			logger.error("查询cloud vendor失败", e);
		}
		if (cloudVendor == null) {
			return null;
		}
		return objectStorageDriver.download(itemModel, cloudVendor.getUuid(), null);
	}

}
