package com.bocloud.ims.repository.resource;

import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.utils.MapTools;
import com.bocloud.database.utils.PageHelper;
import com.bocloud.ims.entity.resource.StorageGroup;
import com.bocloud.ims.entity.resource.StorageHost;
import com.bocloud.ims.entity.resource.StorageView;
import com.bocloud.ims.entity.resource.StorageViewDetail;
import com.bocloud.ims.entity.resource.Volume;
import com.bocloud.ims.repository.resource.common.EnhancedBaseRepository;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Repository("storageViewRepository")
public class StorageViewRepository extends EnhancedBaseRepository<StorageView, Long> {

	public void remove(long volumeGroupId, long hostGroupId) {
		String sql = "delete from storage_view where volume_group_id = :volumeGroupId and host_group_id = :hostGroupId";
		Map<String, Object> params = MapTools.simpleMap("volumeGroupId", volumeGroupId);
		params.put("hostGroupId", hostGroupId);
		this.update(sql, params);

	}

	public List<StorageView> listByStorage(long storageId) {
		String sql = "select a.* from storage_view a where a.storage_id = :storageId";
		Map<String, Object> params = MapTools.simpleMap("storageId", storageId);
		return this.list(StorageView.class, sql, params);
	}

	public StorageView getByVolumeGroupIdAndHostGroupId(long volumeGroupId, long hostGroupId) {
		String sql = "select a.* from storage_view a where a.volume_group_id = :volumeGroupId and a.host_group_id = :hostGroupId";
		Map<String, Object> params = MapTools.simpleMap("volumeGroupId", volumeGroupId);
		params.put("hostGroupId", hostGroupId);
		List<StorageView> list = this.list(StorageView.class, sql, params);
		return list == null || list.size() == 0 ? null : list.get(0);
	}

	public List<StorageView> listByGroupId(Long groupId) {
		String sql = "select a.* from storage_view a " +
				"where a.volume_group_id = :groupId " +
				"or a.host_group_id = :groupId " +
				"or a.port_group_id = :groupId ";
		Map<String, Object> params = new HashMap<>(8);
		params.put("groupId", groupId);
		return this.list(StorageView.class, sql, params);
	}

	public List<StorageView> listByGroupId(Long volumeGroupId, Long hostGroupId, Long portGroupId) {
		String sql = "select a.* from storage_view a where 1=1 ";
		Map<String, Object> params = new HashMap<>(8);
		if (volumeGroupId != null) {
			sql = sql + "and a.volume_group_id = :volumeGroupId ";
			params.put("volumeGroupId", volumeGroupId);
		}
		if (hostGroupId != null) {
			sql = sql + "and a.host_group_id = :hostGroupId ";
			params.put("hostGroupId", hostGroupId);
		}
		if (portGroupId != null) {
			sql = sql + "and a.port_group_id = :portGroupId ";
			params.put("portGroupId", portGroupId);
		}
		return this.list(StorageView.class, sql, params);
	}

	public int countByVolumeIdAndHostId(Long volumeId, Long hostId) {
		String sql = "select count(1) from storage_view a "
				+ "join storage_group_member b on a.volume_group_id = b.group_id "
				+ "join storage_group_member c on a.host_group_id = c.group_id " + "where 1=1 ";
		Map<String, Object> params = new HashMap<>(8);
		if (volumeId != null) {
			sql = sql + "and b.member_id = :volumeId ";
			params.put("volumeId", volumeId);
		}
		if (hostId != null) {
			sql = sql + "and c.member_id = :hostId ";
			params.put("hostId", hostId);
		}
		return this.countQuery(sql, params).intValue();
	}

	public List<StorageViewDetail> listViewDetail(Long volumeId, Long hostId, Long volumeGroupId, Long hostGroupId){
		String sql = "select d.id          as volume_id, " + "       d.name             as volume_name, "
				+ "       a.volume_group_id  as volume_group_id, " + "       f.name             as volume_group_name, "
				+ "       a.host_group_id    as host_group_id, " + "       g.name             as host_group_name, "
				+ "       e.id               as host_id, " + "       e.name             as host_name "
				+ "from storage_view a " + "       left join storage_group_member b on a.volume_group_id = b.group_id "
				+ "       left join storage_group_member c on a.host_group_id = c.group_id "
				+ "       left join volume d on b.member_id = d.id "
				+ "       left join storage_host e on c.member_id = e.id "
				+ "       join storage_group f on a.volume_group_id = f.id "
				+ "       join storage_group g on a.host_group_id = g.id " + "where 1 = 1 ";
		Map<String, Object> params = new HashMap<>(8);
		if (volumeId != null) {
			sql = sql + "and d.id = :volumeId ";
			params.put("volumeId", volumeId);
		}
		if (hostId != null) {
			sql = sql + "and e.id = :hostId ";
			params.put("hostId", hostId);
		}
		if (volumeGroupId != null) {
			sql = sql + "and a.volume_group_id = :volumeGroupId ";
			params.put("volumeGroupId", volumeGroupId);
		}
		if (hostGroupId != null) {
			sql = sql + "and a.host_group_id = :hostGroupId ";
			params.put("hostGroupId", hostGroupId);
		}
		List<Object> objects = this.queryForList(sql, params, StorageViewDetail.class);
		List<StorageViewDetail> details = new ArrayList<>();
		objects.forEach(o -> details.add((StorageViewDetail) o));
		return details;
	}

	public List<StorageHost> listHostByVolumeGroupId(long volumeGroupId) {
		String sql = "select a.* from storage_host a " + "join storage_group_member b on b.member_id = a.id "
				+ "join storage_group c on c.id = b.group_id "
				+ "where c.id in (select host_group_id from storage_view where volume_group_id =:volumeGroupId) and c.type = 'HG'";
		Map<String, Object> params = new HashMap<>(8);
		params.put("volumeGroupId", volumeGroupId);
		List<Object> objects = this.queryForList(sql, params, StorageHost.class);
		List<StorageHost> storageHosts = new ArrayList<>();
		objects.forEach(o -> storageHosts.add((StorageHost) o));
		return storageHosts;
	}

	public List<Volume> listVolumeByHostGroupId(long hostGroupId) {
		String sql = "select a.* from volume a " + "join storage_group_member c on c.member_id = a.id "
				+ "join storage_group b on b.id = c.group_id  "
				+ "where b.id in (select volume_group_id from storage_view where host_group_id = :hostGroupId) and b.type='VG'";
		Map<String, Object> params = new HashMap<>(8);
		params.put("hostGroupId", hostGroupId);
		List<Object> objects = this.queryForList(sql, params, Volume.class);
		List<Volume> volumes = new ArrayList<>();
		objects.forEach(o -> volumes.add((Volume) o));
		return volumes;
	}

	public List<Volume> listVolumeByHost(int page, int rows, long hostId, Map<String, Object> params,
			Map<String, String> sorter) {
		String sql = "select d.*, e.name as pool_name " + "from storage_view a "
				+ "            join storage_group_member b on a.volume_group_id = b.group_id "
				+ "            join storage_group_member c on a.host_group_id = c.group_id "
				+ "            left join volume d on b.member_id = d.id "
				+ "            left join volume_pool e on d.pool_id = e.id " + "where c.member_id = :hostId ";
		Map<String, Object> sqlParams = MapTools.simpleMap("hostId", hostId);
		if (params.containsKey("name")) {
			sql += " and d.name like :name ";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		sql += PageHelper.buildPageSql(page, rows);
		List<Object> objects = this.queryForList(sql, sqlParams, Volume.class);
		List<Volume> volumes = new ArrayList<>();
		objects.forEach(o -> volumes.add((Volume) o));
		return volumes;
	}

	public int countListVolumeByHost(long hostId, Map<String, Object> params) {
		String sql = "select count(1) " + "from storage_view a "
				+ "            join storage_group_member b on a.volume_group_id = b.group_id "
				+ "            join storage_group_member c on a.host_group_id = c.group_id "
				+ "            left join volume d on b.member_id = d.id "
				+ "            left join volume_pool e on d.pool_id = e.id " + "where c.member_id = :hostId ";
		Map<String, Object> sqlParams = MapTools.simpleMap("hostId", hostId);
		if (params.containsKey("name")) {
			sql += " and d.name like :name ";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		return this.countQuery(sql, sqlParams).intValue();
	}

	public List<StorageHost> listHostByVolume(int page, int rows, long volumeId, Map<String, Object> params,
			Map<String, String> sorter) {
		String sql = "select d.* " + "from storage_view a "
				+ "            left join storage_group_member b on a.volume_group_id = b.group_id "
				+ "            left join storage_group_member c on a.host_group_id = c.group_id "
				+ "            join storage_host d on c.member_id = d.id " + "where b.member_id = :volumeId ";
		Map<String, Object> sqlParams = MapTools.simpleMap("volumeId", volumeId);
		if (params.containsKey("name")) {
			sql += " and d.name like :name ";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		sql += PageHelper.buildPageSql(page, rows);
		List<Object> objects = this.queryForList(sql, sqlParams, StorageHost.class);
		List<StorageHost> volumes = new ArrayList<>();
		objects.forEach(o -> volumes.add((StorageHost) o));
		return volumes;
	}

	public int countListHostByVolume(long volumeId, Map<String, Object> params) {
		String sql = "select count(1) " + "from storage_view a "
				+ "            left join storage_group_member b on a.volume_group_id = b.group_id "
				+ "            left join storage_group_member c on a.host_group_id = c.group_id "
				+ "            join storage_host d on c.member_id = d.id " + "where b.member_id = :volumeId ";
		Map<String, Object> sqlParams = MapTools.simpleMap("volumeId", volumeId);
		if (params.containsKey("name")) {
			sql += " and d.name like :name ";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		return this.countQuery(sql, sqlParams).intValue();
	}

	public List<StorageView> listViewsByVolumeGroupId(int page, int rows, long volumeGroupId, Map<String, Object> params) {
		String sql = "select a.*, b.name as port_group_name, c.name as host_group_name, ifnull(d.host_count,0) as host_count "
				+ "from storage_view a "
				+ "  left join storage_group b on a.port_group_id = b.id "
				+ "  left join storage_group c on a.host_group_id = c.id "
				+ "  left join (select group_id, count(member_id) as host_count " +
				"               from storage_group_member group by group_id) d on d.group_id = c.id "
				+ "where a.volume_group_id =:volumeGroupId";
		Map<String, Object> sqlParams = MapTools.simpleMap("volumeGroupId", volumeGroupId);
		if (params.containsKey("hostGroupName")) {
			sql += " and c.name like :hostGroupName ";
			sqlParams.put("hostGroupName", "%" + params.get("hostGroupName") + "%");
		}
		if (params.containsKey("portGroupName")) {
			sql += " and b.name like :portGroupName ";
			sqlParams.put("portGroupName", "%" + params.get("portGroupName") + "%");
		}
		sql += PageHelper.buildPageSql(page, rows);
		List<Object> objects = this.queryForList(sql, sqlParams, StorageView.class);
		List<StorageView> views = new ArrayList<>();
		for (Object object : objects) {
			views.add((StorageView) object);
		}
		return views;
	}

	public int countViewsByVolumeGroupId(long groupId, Map<String, Object> params) {
		String sql = "select count(1) from storage_view a "
				+ "  left join storage_group b on a.port_group_id = b.id "
				+ "  left join storage_group c on a.host_group_id = c.id "
				+ "where a.volume_group_id =:groupId";
		Map<String, Object> sqlParams = MapTools.simpleMap("groupId", groupId);
		if (params.containsKey("hostGroupName")) {
			sql += " and c.name like :hostGroupName ";
			sqlParams.put("hostGroupName", "%" + params.get("hostGroupName") + "%");
		}
		if (params.containsKey("portGroupName")) {
			sql += " and b.name like :portGroupName ";
			sqlParams.put("portGroupName", "%" + params.get("portGroupName") + "%");
		}
		return this.countQuery(sql, sqlParams).intValue();
	}

	public List<StorageView> listViewsByHostGroupId(int page, int rows, long hostGroupId, Map<String, Object> params) {
		String sql = "select a.*, b.name as port_group_name, c.name as volume_group_name, ifnull(d.volume_count,0) as volume_count from storage_view a "
				+ "left join storage_group b on a.port_group_id = b.id "
				+ "left join storage_group c on a.volume_group_id = c.id "
				+ "left join (select group_id, count(member_id) as volume_count from storage_group_member group by group_id) d on d.group_id = c.id "
				+ "where a.host_group_id =:hostGroupId";
		Map<String, Object> sqlParams = MapTools.simpleMap("hostGroupId", hostGroupId);
		if (params.containsKey("volumeGroupName")) {
			sql += " and c.name like :volumeGroupName ";
			sqlParams.put("volumeGroupName", "%" + params.get("volumeGroupName") + "%");
		}
		if (params.containsKey("portGroupName")) {
			sql += " and b.name like :portGroupName ";
			sqlParams.put("portGroupName", "%" + params.get("portGroupName") + "%");
		}
		sql += PageHelper.buildPageSql(page, rows);
		List<Object> objects = this.queryForList(sql, sqlParams, StorageView.class);
		List<StorageView> views = new ArrayList<>();
		for (Object object : objects) {
			views.add((StorageView) object);
		}
		return views;
	}

	public int countViewsByHostGroupId(long groupId, Map<String, Object> params) {
		String sql = "select count(1) from storage_view a "
				+ "left join storage_group b on a.port_group_id = b.id "
				+ "left join storage_group c on a.volume_group_id = c.id "
				+ "where a.host_group_id =:groupId";
		Map<String, Object> sqlParams = MapTools.simpleMap("groupId", groupId);
		if (params.containsKey("volumeGroupName")) {
			sql += " and c.name like :volumeGroupName ";
			sqlParams.put("volumeGroupName", "%" + params.get("volumeGroupName") + "%");
		}
		if (params.containsKey("portGroupName")) {
			sql += " and b.name like :portGroupName ";
			sqlParams.put("portGroupName", "%" + params.get("portGroupName") + "%");
		}
		return this.countQuery(sql, sqlParams).intValue();
	}

	public List<StorageView> listViewsByPortGroupId(int page, int rows, long portGroupId, Map<String, Object> params) {
		String sql = "select a.*, b.name as volume_group_name, c.name as host_group_name from storage_view a "
				+ "left join storage_group b on a.volume_group_id = b.id "
				+ "left join storage_group c on a.host_group_id = c.id "
				+ "where a.port_group_id =:portGroupId";
		Map<String, Object> sqlParams = MapTools.simpleMap("portGroupId", portGroupId);
		if (params.containsKey("volumeGroupName")) {
			sql += " and b.name like :volumeGroupName ";
			sqlParams.put("volumeGroupName", "%" + params.get("volumeGroupName") + "%");
		}
		if (params.containsKey("hostGroupName")) {
			sql += " and c.name like :hostGroupName ";
			sqlParams.put("hostGroupName", "%" + params.get("hostGroupName") + "%");
		}
		sql += PageHelper.buildPageSql(page, rows);
		List<Object> objects = this.queryForList(sql, sqlParams, StorageView.class);
		List<StorageView> views = new ArrayList<>();
		for (Object object : objects) {
			views.add((StorageView) object);
		}
		return views;
	}

	public int countViewsByPortGroupId(long groupId, Map<String, Object> params) {
		String sql = "select count(1) from storage_view a "
				+ "left join storage_group b on a.volume_group_id = b.id "
				+ "left join storage_group c on a.host_group_id = c.id "
				+ "where a.port_group_id =:groupId";
		Map<String, Object> sqlParams = MapTools.simpleMap("groupId", groupId);
		if (params.containsKey("volumeGroupName")) {
			sql += " and b.name like :volumeGroupName ";
			sqlParams.put("volumeGroupName", "%" + params.get("volumeGroupName") + "%");
		}
		if (params.containsKey("hostGroupName")) {
			sql += " and c.name like :hostGroupName ";
			sqlParams.put("hostGroupName", "%" + params.get("hostGroupName") + "%");
		}
		return this.countQuery(sql, sqlParams).intValue();
	}

	public List<StorageGroup> listHostGroupForVolumeGroupView(int page, int rows, long volumeGroupId, Map<String, Object> params) {
		String sql = "select * from storage_group " +
				"where id not in (select host_group_id from storage_view where volume_group_id = :volumeGroupId) " +
				"and storage_id = (select storage_id from storage_group where id = :volumeGroupId) " +
				"and type = 'HG' and is_deleted = 0 ";
		Map<String, Object> sqlParams = MapTools.simpleMap("volumeGroupId", volumeGroupId);
		if (params.containsKey("name")) {
			sql += " and name like :name ";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		sql += PageHelper.buildPageSql(page, rows);
		List<Object> objects = this.queryForList(sql, sqlParams, StorageGroup.class);
		return objects.stream().map(o -> (StorageGroup) o).collect(Collectors.toList());
	}

	public int countHostGroupForVolumeGroupView(long volumeGroupId, Map<String, Object> params) {
		String sql = "select count(1) from storage_group " +
				"where id not in (select host_group_id from storage_view where volume_group_id = :volumeGroupId) " +
				"and storage_id = (select storage_id from storage_group where id = :volumeGroupId) " +
				"and type = 'HG' and is_deleted = 0 ";
		Map<String, Object> sqlParams = MapTools.simpleMap("volumeGroupId", volumeGroupId);
		if (params.containsKey("name")) {
			sql += " and name like :name ";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		return this.countQuery(sql, sqlParams).intValue();
	}

	public List<StorageGroup> listVolumeGroupForHostGroupView(int page, int rows, long hostGroupId, Map<String, Object> params) {
		String sql = "select * from storage_group " +
				"where id not in (select volume_group_id from storage_view where host_group_id = :hostGroupId) " +
				"and storage_id = (select storage_id from storage_group where id = :hostGroupId) " +
				"and type = 'VG' and is_deleted = 0 ";
		Map<String, Object> sqlParams = MapTools.simpleMap("hostGroupId", hostGroupId);
		if (params.containsKey("name")) {
			sql += " and name like :name ";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		sql += PageHelper.buildPageSql(page, rows);
		List<Object> objects = this.queryForList(sql, sqlParams, StorageGroup.class);
		return objects.stream().map(o -> (StorageGroup) o).collect(Collectors.toList());
	}

	public int countVolumeGroupForHostGroupView(long hostGroupId, Map<String, Object> params) {
		String sql = "select count(1) from storage_group " +
				"where id not in (select volume_group_id from storage_view where host_group_id = :hostGroupId) " +
				"and storage_id = (select storage_id from storage_group where id = :hostGroupId) " +
				"and type = 'VG' and is_deleted = 0 ";
		Map<String, Object> sqlParams = MapTools.simpleMap("hostGroupId", hostGroupId);
		if (params.containsKey("name")) {
			sql += " and name like :name ";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		return this.countQuery(sql, sqlParams).intValue();
	}

	public BocloudResult checkRepeatMappingWhenAddVolumeToGroup(long volumeId, List<Long> groupIds) {
		String volumeName = this
				.queryForList("select name from volume where id = :id", MapTools.simpleMap("id", volumeId)).get(0)
				.get("name").toString();
		List<StorageViewDetail> allVolumeGroupViews = new ArrayList<>();
		for (Long groupId : groupIds) {
			String groupName = this
					.queryForList("select name from storage_group where id = :id", MapTools.simpleMap("id", groupId))
					.get(0).get("name").toString();

			// 先查询该卷组已经映射的主机组和主机
			List<StorageViewDetail> volumeGroupViews = this.listViewDetail(null, null, groupId, null);
			volumeGroupViews.forEach(view -> {
				view.setVolumeId(null);
				view.setVolumeName(null);
			});
			volumeGroupViews = volumeGroupViews.stream().distinct().collect(Collectors.toList());
			// 再查询该卷已经映射的主机组和主机
			List<StorageViewDetail> volumeViews = this.listViewDetail(volumeId, null, null, null);
			// 首先看看当前卷组是否已经重复映射了某个主机
			Set<Long> hostIds = volumeGroupViews.stream().map(StorageViewDetail::getHostId).filter(Objects::nonNull)
					.collect(Collectors.toSet());
			for (Long hostId : hostIds) {
				List<StorageViewDetail> views = volumeGroupViews.stream()
						.filter(volumeGroupView -> hostId.equals(volumeGroupView.getHostId()))
						.collect(Collectors.toList());
				if (views.size() > 1) {
					return new BocloudResult(false,
							String.format("卷组[%s]已通过主机组[%s]和[%s]映射给了主机[%s]，所以将卷[%s]添加到卷组[%s]中会导致重复映射，操作失败！", groupName,
									views.get(0).getHostGroupName(), views.get(1).getHostGroupName(),
									views.get(0).getHostName(), volumeName, groupName));
				}
			}
			// 然后看看有没有重合的主机
			for (StorageViewDetail volumeView : volumeViews) {
				Optional<StorageViewDetail> findResult = volumeGroupViews.stream()
						.filter(volumeGroupView -> volumeView.getHostId() != null && volumeGroupView.getHostId() != null
								&& volumeView.getHostId().equals(volumeGroupView.getHostId()))
						.findFirst();
				if (findResult.isPresent()) {
					StorageViewDetail volumeGroupView = findResult.get();
					return new BocloudResult(false, String.format(
							"卷[%s]已通过卷组[%s]主机组[%s]映射给了主机[%s]，且卷组[%s]也通过主机组[%s]映射给了主机[%s]，所以将卷[%s]添加到卷组[%s]中会导致重复映射，操作失败！",
							volumeView.getVolumeName(), volumeView.getVolumeGroupName(), volumeView.getHostGroupName(),
							volumeView.getHostName(), volumeGroupView.getVolumeGroupName(),
							volumeGroupView.getHostGroupName(), volumeGroupView.getHostName(), volumeName, groupName));
				}
			}
			// 最后看看有没有重合的空的主机组
			for (StorageViewDetail volumeView : volumeViews) {
				Optional<StorageViewDetail> findResult = volumeGroupViews.stream()
						.filter(volumeGroupView -> volumeView.getHostId() == null && volumeGroupView.getHostId() == null
								&& volumeView.getHostGroupId() != null && volumeGroupView.getHostGroupId() != null
								&& volumeView.getHostGroupId().equals(volumeGroupView.getHostGroupId()))
						.findFirst();
				if (findResult.isPresent()) {
					StorageViewDetail volumeGroupView = findResult.get();
					return new BocloudResult(false,
							String.format(
									"卷[%s]已通过卷组[%s]映射给了空的主机组[%s]，且卷组[%s]也映射给了空的主机组[%s]，所以将卷[%s]添加到卷组[%s]中会导致重复映射，操作失败！",
									volumeView.getVolumeName(), volumeView.getVolumeGroupName(),
									volumeView.getHostGroupName(), volumeGroupView.getVolumeGroupName(),
									volumeGroupView.getHostGroupName(), volumeName, groupName));
				}
			}

			allVolumeGroupViews.addAll(volumeGroupViews);
		}

		// 最最最后再检查下，该卷即将要加入的卷组中映射的主机是否有重合
		Set<Long> hostIds = allVolumeGroupViews.stream().map(StorageViewDetail::getHostId).filter(Objects::nonNull)
				.collect(Collectors.toSet());
		for (Long hostId : hostIds) {
			List<StorageViewDetail> views = allVolumeGroupViews.stream().filter(view -> hostId.equals(view.getHostId()))
					.collect(Collectors.toList());
			if (views.size() > 1) {
				return new BocloudResult(false, String.format(
						"卷[%s]即将映射给卷组[%s]和[%s]，且两个卷组分别通过主机组[%s]和[%s]映射给了主机[%s]，所以将卷[%s]同时添加到卷组[%s]和[%s]中会导致重复映射，操作失败！",
						volumeName, views.get(0).getVolumeGroupName(), views.get(1).getVolumeGroupName(),
						views.get(0).getHostGroupName(), views.get(1).getHostGroupName(), views.get(0).getHostName(),
						volumeName, views.get(0).getVolumeGroupName(), views.get(1).getVolumeGroupName()));
			}
		}

		// 最最最后再检查下，该卷即将要加入的卷组中映射的主机组是否有重合
		Set<Long> hostGroupIds = allVolumeGroupViews.stream().map(StorageViewDetail::getHostGroupId)
				.filter(Objects::nonNull).collect(Collectors.toSet());
		allVolumeGroupViews.forEach(storageViewDetail -> {
			storageViewDetail.setHostId(null);
			storageViewDetail.setHostName(null);
		});
		allVolumeGroupViews = allVolumeGroupViews.stream().distinct().collect(Collectors.toList());
		for (Long hostGroupId : hostGroupIds) {
			List<StorageViewDetail> views = allVolumeGroupViews.stream()
					.filter(view -> hostGroupId.equals(view.getHostGroupId())).collect(Collectors.toList());
			if (views.size() > 1) {
				return new BocloudResult(false, String.format(
						"卷[%s]即将映射给卷组[%s]和[%s]，且两个卷组分别映射给了空的主机组[%s]和[%s]，所以将卷[%s]同时添加到卷组[%s]和[%s]中会导致重复映射，操作失败！",
						volumeName, views.get(0).getVolumeGroupName(), views.get(1).getVolumeGroupName(),
						views.get(0).getHostGroupName(), views.get(1).getHostGroupName(), volumeName,
						views.get(0).getVolumeGroupName(), views.get(1).getVolumeGroupName()));
			}
		}

		return new BocloudResult(true, "没啥问题");
	}

	public BocloudResult checkRepeatMappingWhenAddHostToGroup(long hostId, List<Long> groupIds) {
		String hostName = this
				.queryForList("select name from storage_host where id = :id", MapTools.simpleMap("id", hostId)).get(0)
				.get("name").toString();
		List<StorageViewDetail> allHostGroupViews = new ArrayList<>();
		for (Long groupId : groupIds) {
			int viewInHostGroupCnt = 0;
			int viewHostCnt = 0;
			String groupName = this
					.queryForList("select name from storage_group where id = :id", MapTools.simpleMap("id", groupId))
					.get(0).get("name").toString();
			// 先查询该主机组已经映射的卷组和卷
			List<StorageViewDetail> hostGroupViews = this.listViewDetail(null, null, null, groupId);
			// 获得主机组内的主机与卷映射的数量
			for (StorageViewDetail hostGroupViewDetail : hostGroupViews) {
				if (hostGroupViewDetail.getVolumeId() != null && hostGroupViewDetail.getHostId() != null) {
					viewInHostGroupCnt++;
				}
			}
			hostGroupViews.forEach(view -> {
				view.setHostId(null);
				view.setHostName(null);
			});
			hostGroupViews = hostGroupViews.stream().distinct().collect(Collectors.toList());
			// 再查询该主机已经映射的卷组和卷
			List<StorageViewDetail> hostViews = this.listViewDetail(null, hostId, null, null);
			// 获得主机与卷映射的数量
			for (StorageViewDetail hostViewDetail : hostViews) {
				if (hostViewDetail.getVolumeId() != null) {
					viewHostCnt++;
				}
			}
			// 如果主机和主机组中的主机都与卷存在映射关系，则不允许改主机加入该主机组
			if (viewInHostGroupCnt > 0 && viewHostCnt > 0) {
				return new BocloudResult(false, "主机[" + hostViews.get(0).getHostName() + "]和即将加入的主机组["
						+ hostGroupViews.get(0).getHostGroupName() + "]都与卷存在映射关系，操作失败！");
			}
			// 首先看看当前主机组是否已经重复映射了某个卷
			Set<Long> volumeIds = hostGroupViews.stream().map(StorageViewDetail::getVolumeId).filter(Objects::nonNull)
					.collect(Collectors.toSet());
			for (Long volumeId : volumeIds) {
				List<StorageViewDetail> views = hostGroupViews.stream()
						.filter(hostGroupView -> volumeId.equals(hostGroupView.getVolumeId()))
						.collect(Collectors.toList());
				if (views.size() > 1) {
					return new BocloudResult(false,
							String.format("主机组[%s]已通过卷组[%s]和[%s]映射给了卷[%s]，所以将主机[%s]添加到主机组[%s]中会导致重复映射，操作失败！", groupName,
									views.get(0).getVolumeGroupName(), views.get(1).getVolumeGroupName(),
									views.get(0).getVolumeName(), hostName, groupName));
				}
			}
			// 然后看看有没有重合的卷
			for (StorageViewDetail hostView : hostViews) {
				Optional<StorageViewDetail> findResult = hostGroupViews.stream()
						.filter(hostGroupView -> hostView.getVolumeId() != null && hostGroupView.getVolumeId() != null
								&& hostView.getVolumeId().equals(hostGroupView.getVolumeId()))
						.findFirst();
				if (findResult.isPresent()) {
					StorageViewDetail hostGroupView = findResult.get();
					return new BocloudResult(false, String.format(
							"主机[%s]已通过主机组[%s]卷组[%s]映射给了卷[%s]，且主机组[%s]也通过卷组组[%s]映射给了卷[%s]，所以将主机[%s]添加到主机组[%s]中会导致重复映射，操作失败！",
							hostView.getHostName(), hostView.getHostGroupName(), hostView.getVolumeGroupName(),
							hostView.getVolumeName(), hostGroupView.getHostGroupName(),
							hostGroupView.getVolumeGroupName(), hostGroupView.getVolumeName(), hostName, groupName));
				}
			}
			// 最后看看有没有重合的空的主机组
			for (StorageViewDetail hostView : hostViews) {
				Optional<StorageViewDetail> findResult = hostGroupViews.stream()
						.filter(hostGroupView -> hostView.getHostId() == null && hostGroupView.getHostId() == null
								&& hostView.getHostGroupId() != null && hostGroupView.getHostGroupId() != null
								&& hostView.getHostGroupId().equals(hostGroupView.getHostGroupId()))
						.findFirst();
				if (findResult.isPresent()) {
					StorageViewDetail hostGroupView = findResult.get();
					return new BocloudResult(false, String.format(
							"主机[%s]已通过主机组[%s]映射给了空的卷组[%s]，且主机组[%s]也映射给了空的卷组[%s]，所以将主机[%s]添加到主机组[%s]中会导致重复映射，操作失败！",
							hostView.getHostName(), hostView.getHostGroupName(), hostView.getVolumeGroupName(),
							hostGroupView.getHostGroupName(), hostGroupView.getVolumeGroupName(), hostName, groupName));
				}
			}
			allHostGroupViews.addAll(hostGroupViews);
		}

		// 最最最后再检查下，该主机即将要加入的主机组中映射的卷是否有重合
		Set<Long> volumeIds = allHostGroupViews.stream().map(StorageViewDetail::getVolumeId).filter(Objects::nonNull)
				.collect(Collectors.toSet());
		for (Long volumeId : volumeIds) {
			List<StorageViewDetail> views = allHostGroupViews.stream()
					.filter(view -> volumeId.equals(view.getVolumeId())).collect(Collectors.toList());
			if (views.size() > 1) {
				return new BocloudResult(false, String.format(
						"主机[%s]即将映射给主机组[%s]和[%s]，且两个主机组分别通过卷组[%s]和[%s]映射给了卷[%s]，所以将主机[%s]同时添加到主机组[%s]和[%s]中会导致重复映射，操作失败！",
						hostName, views.get(0).getHostGroupName(), views.get(1).getHostGroupName(),
						views.get(0).getVolumeGroupName(), views.get(1).getVolumeGroupName(),
						views.get(0).getVolumeName(), hostName, views.get(0).getHostGroupName(),
						views.get(1).getHostGroupName()));
			}
		}

		// 最最最后再检查下，该主机即将要加入的主机组中映射的卷组是否有重合
		Set<Long> volumeGroupIds = allHostGroupViews.stream().map(StorageViewDetail::getVolumeGroupId)
				.filter(Objects::nonNull).collect(Collectors.toSet());
		allHostGroupViews.forEach(storageViewDetail -> {
			storageViewDetail.setVolumeId(null);
			storageViewDetail.setVolumeName(null);
		});
		allHostGroupViews = allHostGroupViews.stream().distinct().collect(Collectors.toList());
		for (Long volumeGroupId : volumeGroupIds) {
			List<StorageViewDetail> views = allHostGroupViews.stream()
					.filter(view -> volumeGroupId.equals(view.getVolumeGroupId())).collect(Collectors.toList());
			if (views.size() > 1) {
				return new BocloudResult(false, String.format(
						"主机[%s]即将映射给主机组[%s]和[%s]，且两个主机组分别映射给了空的卷组[%s]和[%s]，所以将主机[%s]同时添加到主机组[%s]和[%s]中会导致重复映射，操作失败！",
						hostName, views.get(0).getHostGroupName(), views.get(1).getHostGroupName(),
						views.get(0).getVolumeGroupName(), views.get(1).getVolumeGroupName(), hostName,
						views.get(0).getHostGroupName(), views.get(1).getHostGroupName()));
			}
		}

		return new BocloudResult(true, "没啥问题");
	}
}
