package com.bocloud.ims.repository.resource;

import com.bocloud.common.exception.BoCloudDBException;
import com.bocloud.common.model.Pager;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.database.utils.PageHelper;
import com.bocloud.database.utils.QueryBuilder;
import com.bocloud.ims.entity.resource.Volume;
import com.bocloud.orm.OrmGenericDaoImpl;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.*;

/**
 * 卷数据访问
 *
 * @author wangyu
 * @version 1.0
 * @since 2020年5月15日
 */
@Repository("volumeRepository")
public class VolumeRepository extends OrmGenericDaoImpl<Volume, Long> {

    public VolumeRepository(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate npJdbcTemplate) {
        super(jdbcTemplate, npJdbcTemplate);
    }

    public List<Volume> list(int page, int rows, List<Param> params, Map<String, String> sorter, String labelContent) {
        String sql = "select v.*,c.name vendor_name,rsg.name resource_group_name,s.name server_name,t.name tenant_name,f.name as pool_name,ifnull(b.cloud_server_count, 0) cloud_server_count, snap.name as snapshot_name, region.name region_name, zone.name zone_name, vt.name template_name, st.name storage_name from volume v  "
                + " left join volume_pool f on v.pool_id = f.id  "
                + " left join region region on v.region_id = region.region_id and v.vendor_id = region.vendor_id "
                + " left join zone zone on v.vendor_id = zone.vendor_id and v.zone = zone.zone_id "
                + " left join tenant t on v.tenant_id = t.id " + " left join cloud_vendor c on v.vendor_id = c.id "
                + " left join resource_group rsg on v.resource_group_id = rsg.id "
                + " left join cloud_server s on v.server_id = s.id "
                + " left join (select volume_id, count(server_id) cloud_server_count from server_volume group by volume_id) b on v.id = b.volume_id "
                + " left join snapshot snap on snap.id = v.snapshot_id "
                + " left join volume_template vt on v.template_id = vt.id "
                + " left join storage st on v.storage_id = st.id " + " where v.is_deleted = 0";
        sql = appendLabelSearch(labelContent, sql);
        sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "v");
        return this.list(Volume.class, sql);
    }

    public List<Volume> list(Long vendorId, List<String> statusList, Long userId, Long tenantId, Long projectId,
                             String tenantUuid, String regionId) {
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("statusList", statusList);
        String sql = "";
        if (null != userId && null != tenantId) {
            sql = "select v.*,c.name vendor_name,s.name server_name,t.name tenant_name from volume v left join tenant t on v.tenant_id = t.id left join cloud_vendor c on v.vendor_id = c.id left join cloud_server s on v.server_id = s.id,object_relation b where v.is_deleted = 0 and v.boot_volume = 0 and v.id = b.res_id and b.category = 'Storage'  and v.vendor_id=:vendorId and v.status in (:statusList) and v.tenant_id = "
                    + tenantId + " and b.target = " + userId;
        } else if (null == userId && null != tenantId) {
            sql = "select v.*,c.name vendor_name,s.name server_name,t.name tenant_name from volume v left join tenant t on v.tenant_id = t.id left join cloud_vendor c on v.vendor_id = c.id left join cloud_server s on v.server_id = s.id "
                    + " where v.is_deleted = 0 and v.boot_volume = 0 "
                    + " and v.vendor_id=:vendorId and v.status in (:statusList) and v.tenant_id = " + tenantId;
        } else {
            sql = "select v.*,c.name vendor_name,s.name server_name,t.name tenant_name from volume v left join tenant t on v.tenant_id = t.id left join cloud_vendor c on v.vendor_id = c.id left join cloud_server s on v.server_id = s.id where v.is_deleted = 0 and v.vendor_id=:vendorId and v.status in (:statusList) and v.tenant_id = 0 ";
        }
        if (null != projectId && 0L != projectId) {
            sql += " and v.project_id = " + projectId;
        }
        if (!StringUtils.isEmpty(tenantUuid)) {
            sql += " and v.tenant_uuid = :tenantUuid";
            params.put("tenantUuid", tenantUuid);
        }
        if (!StringUtils.isEmpty(regionId)) {
            sql += " and v.region_id = :regionId";
            params.put("regionId", regionId);
        }
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> list(Long vendorId, List<String> statusList, Long tenantId, Long projectId) {
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("statusList", statusList);
        String sql = "select v.*,c.name vendor_name,s.name server_name,t.name tenant_name from volume v left join tenant t on v.tenant_id = t.id left join cloud_vendor c on v.vendor_id = c.id left join cloud_server s on v.server_id = s.id "
                + " where v.is_deleted = 0 "
                + " and v.vendor_id=:vendorId and v.status in (:statusList) and v.tenant_id = " + tenantId;
        if (null != projectId && 0L != projectId) {
            sql += " and v.project_id = " + projectId;
        }
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> list(Long vendorId, List<String> statusList, Long tenantId) {
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("statusList", statusList);
        String sql = "select v.*,c.name vendor_name,s.name server_name,t.name tenant_name from volume v left join tenant t on v.tenant_id = t.id left join cloud_vendor c on v.vendor_id = c.id left join cloud_server s on v.server_id = s.id "
                + " where v.is_deleted = 0 "
                + " and v.vendor_id=:vendorId and v.status in (:statusList) and v.tenant_id = " + tenantId;
        return this.list(Volume.class, sql, params);
    }

    public int count(List<Param> params) {
        String sql = "select count(1) from volume v where v.is_deleted = 0";
        sql = QueryBuilder.buildRaw(sql, params, null, "v");
        Map<String, Object> param = QueryBuilder.getParam(params);
        return this.countQuery(sql, param).intValue();
    }


    public int countByExistsLabel(List<Param> params, String labelContent) {
        String sql = "select count(1) from volume a where a.is_deleted = 0";
        sql = appendLabelSearch(labelContent, sql);
        sql = QueryBuilder.buildRaw(sql, params, null, "a");
        Map<String, Object> param = QueryBuilder.getParam(params);
        return this.countQuery(sql, param).intValue();
    }

    public List<Volume> listBySyncedSetId(Long syncedSetId) {
        String sql = "select v.* from volume v where is_deleted = 0 and v.synced_set_id = :syncedSetId";
        Map<String, Object> params = new HashMap<>(8);
        params.put("syncedSetId", syncedSetId);
        return this.list(Volume.class, sql, params);
    }

    public int count(Long vendorId, List<String> statusList) {
        String sql = "select count(1) from volume v where v.is_deleted = 0 and v.vendor_id=:vendorId and v.status in (:statusList)";
        Map<String, Object> param = Maps.newHashMap();
        param.put(Common.VENDORID, vendorId);
        param.put("statusList", statusList);
        return this.countQuery(sql, param).intValue();
    }

    public boolean remove(Long id, Long userId) {
        String sql = "update volume set is_deleted = 1, gmt_modify = :gmtModify, mender_id = :menderId where id = :id";
        Map<String, Object> params = MapTools.simpleMap("id", id);
        params.put("gmtModify", new Date());
        params.put("menderId", userId);
        return this.execute(sql, params) > 0;
    }

    public List<Volume> listByVendorId(Long vendorId) {
        String sql = "select a.*,t.name tenant_name from volume a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.vendor_id =:vendorId";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> listByNames(Long serverId, List<String> names) {
        String sql = "select a.* from volume a where a.is_deleted = 0 and a.server_id =:serverId and a.name in (:names)";
        Map<String, Object> params = MapTools.simpleMap("serverId", serverId);
        params.put("names", names);
        return this.list(Volume.class, sql, params);
    }

    public List<SimpleBean> list(List<Param> params, Map<String, String> sorter, String labelContent) {
        String sql = "select a.id,a.name,a.status,a.volume_uuid from volume a where a.is_deleted = 0";
        sql = appendLabelSearch(labelContent, sql);
        sql = QueryBuilder.build(sql, new Pager(1, Integer.MAX_VALUE, params, sorter), "a");
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        List<Volume> volumes = this.list(Volume.class, sql, paramMap);
        List<SimpleBean> beans = new ArrayList<>();
        for (Volume volume : volumes) {
            SimpleBean simpleBean = new SimpleBean(volume.getId(), volume.getName(), volume.getStatus());
            simpleBean.setUuid(volume.getVolumeUuid());
            beans.add(simpleBean);
        }
        return beans;
    }

    public Volume getByVolumeUuid(String volumeUuid) {
        String sql = "select a.*,t.name tenant_name from volume a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.volume_uuid = :volumeUuid";
        Map<String, Object> param = MapTools.simpleMap("volumeUuid", volumeUuid);
        List<Volume> list = this.list(Volume.class, sql, param);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public Volume getByVolumeUuid(String volumeUuid, Long vendorId) {
        String sql = "select a.*,t.name tenant_name from volume a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.volume_uuid = :volumeUuid and a.vendor_id = :vendorId ";
        Map<String, Object> param = MapTools.simpleMap("volumeUuid", volumeUuid);
        param.put("vendorId", vendorId);
        List<Volume> list = this.list(Volume.class, sql, param);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public Volume query(Long id) {
        String sql = "select v.*,c.name vendor_name,rsg.name resource_group_name,cs.name server_name,c.type vendor_type,t.name tenant_name,"
                + " u.name target_name , zone.name zone_name, vt.name template_name, st.name storage_name, project.name project_name ,"
                + " vp.name as pool_name from volume v " + " left join tenant t on v.tenant_id = t.id "
                + " left join cloud_vendor c on v.vendor_id = c.id  "
                + " left join resource_group rsg on v.resource_group_id = rsg.id "
                + " left join zone zone on v.zone = zone.zone_id and v.vendor_id = zone.vendor_id "
                + " left join object_relation o on o.res_id = v.id and o.category = 'Storage' "
                + " left join users u on u.id = o.target and o.catalog = 'USER' "
                + " left join snapshot snap on snap.id = v.snapshot_id "
                + " left join cloud_server cs on cs.id = v.server_id "
                + " left join project project on v.project_id = project.id "
                + " left join volume_template vt on v.template_id = vt.id "
                + " left join storage st on v.storage_id = st.id " + " left join volume_pool vp on v.pool_id = vp.id "
                + " where v.is_deleted = 0 and v.id = :id";
        Map<String, Object> params = MapTools.simpleMap(Common.ID, id);
        List<Volume> list = this.list(Volume.class, sql, params);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public boolean removeByVid(Long vendorId, Long userId) {
        String sql = "update volume set is_deleted = 1, gmt_modify = :gmtModify, mender_id = :menderId where vendor_id = :vendorId";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("gmtModify", new Date());
        params.put("menderId", userId);
        return this.execute(sql, params) > 0;
    }

    public int count(List<Param> params, Long tenantId, List<Long> projectIds) {
        String sql = "select count(a.id) from volume a left join tenant t on a.tenant_id = t.id left join cloud_vendor v on a.vendor_id = v.id,object_relation b where  a.id = b.res_id and b.category = 'Storage' and a.is_deleted = 0 ";
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        if (null != tenantId && 0L != tenantId) {
            sql += " and a.tenant_id = :tenantId";
            paramMap.put("tenantId", tenantId);
        }
        if (!ListTool.isEmpty(projectIds)) {
            sql += " and a.project_id in (:projectIds) ";
            paramMap.put("projectIds", projectIds);
        }
        sql = QueryBuilder.buildRaw(sql, params, null, "a");
        return this.countQuery(sql, paramMap).intValue();
    }

    public List<Volume> list(int page, int rows, List<Param> params, Map<String, String> sorter, Long tenantId,
                             List<Long> projectIds) {
        String sql = "select a.*,v.name vendor_name,v.type vendor_type,b.expired_time,t.name tenant_name, p.name project_name from volume a "
                + " left join tenant t on a.tenant_id = t.id " + " left join project p on a.project_id = p.id "
                + " left join cloud_vendor v on a.vendor_id = v.id,object_relation b "
                + " where a.is_deleted = 0 and a.id = b.res_id and b.category = 'Storage'";
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        if (null != tenantId && 0L != tenantId) {
            sql += " and a.tenant_id = :tenantId";
            paramMap.put("tenantId", tenantId);
        }
        if (!ListTool.isEmpty(projectIds)) {
            sql += " and a.project_id in (:projectIds) ";
            paramMap.put("projectIds", projectIds);
        }
        sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "a");
        return this.list(Volume.class, sql, paramMap);
    }

    public List<Volume> listByCondition(Long vendorId, Long vdcId, Long clusterId) {
        String sql = "select a.* from volume a left join cloud_server b on b.id = a.server_id left join server c on c.id = b.host_id where a.is_deleted = 0 ";
        Map<String, Object> params = new HashMap<>(8);
        if (null != vendorId && 0L != vendorId) {
            sql += " and a.vendor_id = :vendorId";
            params.put("vendorId", vendorId);
        }
        if (null != vdcId && 0L != vdcId) {
            sql += " and c.vdc_id = :vdcId";
            params.put("vdcId", vdcId);
        }
        if (null != clusterId && 0L != clusterId) {
            sql += " and c.cluster_id = :clusterId";
            params.put("clusterId", clusterId);
        }
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> listByTenantId(Long tenantId) {
        String sql = "select a.*,t.name tenant_name from volume a left join tenant t on a.tenant_id = t.id,object_relation b,user c where a.is_deleted = 0 and a.id = b.res_id and b.target = c.id and b.category = 'Storage'  and c.tenant_id ="
                + tenantId;
        return this.list(Volume.class, sql);
    }

    public boolean updateExpriedTime(Long resId, Date expiredTime) {
        String sql = "update object_relation a set a.expired_time = :expiredTime where a.res_id = :resId and a.category = 'Storage' and a.catalog = 'USER'";
        Map<String, Object> params = MapTools.simpleMap("resId", resId);
        params.put("expiredTime", expiredTime);
        return this.execute(sql, params) > 0;
    }

    public List<Volume> listByServerId(Long serverId) {
        String sql = "select a.*,t.name tenant_name , ds.name  data_store_name  from volume a left join tenant t on a.tenant_id = t.id " +
                " left join data_store  ds on a.data_store_id  = ds.id " +
                " where a.is_deleted = 0 and a.server_id = :serverId";
        Map<String, Object> params = MapTools.simpleMap("serverId", serverId);
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> listDataDisks(Long serverId) {
        String sql = "select a.* from volume a where a.is_deleted = 0 and a.server_id = :serverId and a.name not in ('Hard disk 1','硬盘 1')";
        Map<String, Object> params = MapTools.simpleMap("serverId", serverId);
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> listTenantDataDisks(Long serverId) {
        String sql = "select a.* from volume a where a.is_deleted = 0 and a.server_id = :serverId ";
        Map<String, Object> params = MapTools.simpleMap("serverId", serverId);
        return this.list(Volume.class, sql, params);
    }

    public Volume getSystemDisk(Long serverId) {
        String sql = "select a.* from volume a where a.is_deleted = 0 and a.server_id = :serverId and a.name in ('Hard disk 1','硬盘 1')";
        Map<String, Object> params = MapTools.simpleMap("serverId", serverId);
        List<Volume> volumes = this.list(Volume.class, sql, params);
        return ListTool.isEmpty(volumes) ? null : volumes.get(0);
    }

    public Volume getByLvmMntp(Long serverId, String device) {
        String sql = "select a.* from volume a where a.is_deleted = 0 and a.server_id = :serverId and a.name not in ('Hard disk 1','硬盘 1') and a.lvm_mntp = :device";
        Map<String, Object> params = MapTools.simpleMap("serverId", serverId);
        params.put("device", device);
        List<Volume> volumes = this.list(Volume.class, sql, params);
        return ListTool.isEmpty(volumes) ? null : volumes.get(0);
    }

    public boolean detachVolumes(Long serverId, Long userId) {
        String sql = "update volume set server_id = null, device = null, gmt_modify = :gmtModify, mender_id = :menderId where is_deleted = 0 and server_id = :serverId";
        Map<String, Object> params = MapTools.simpleMap("serverId", serverId);
        params.put("gmtModify", new Date());
        params.put("menderId", userId);
        return this.execute(sql, params) > 0;
    }

    public List<Volume> listByServerId(Long serverId, Long vendorId, Boolean bootable) {
        String sql = "select a.*,t.name tenant_name from volume a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.vendor_id =:vendorId and a.server_id = :serverId ";
        if (bootable) {
            sql += " and a.boot_volume = 1";
        }
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("serverId", serverId);
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> listDataVolumeByServerId(Long serverId, Long vendorId) {
        String sql = "select a.*,t.name tenant_name, c.name vendor_name, c.type vendor_type from volume a left join tenant t on a.tenant_id = t.id "
                + " left join cloud_vendor c on a.vendor_id = c.id "
                + " where a.is_deleted = 0 and a.vendor_id =:vendorId and a.server_id = :serverId and a.boot_volume = 0 ";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("serverId", serverId);
        return this.list(Volume.class, sql, params);
    }

    public Boolean isBootFromVolume(Long serverId, Long vendorId, Boolean bootable) {
        String sql = "select a.*,t.name tenant_name from volume a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.boot_volume = 1 and a.vendor_id =:vendorId and a.server_id = :serverId limit 1";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("serverId", serverId);
        return ListTool.isEmpty(this.list(Volume.class, sql, params)) ? false : true;
    }

    public boolean inUseByTenants(Long vendorId) {
        String sql = "select count(1) from volume a where a.is_deleted = 0 and a.tenant_id is not null and a.tenant_id != 0 and a.vendor_id = :vendorId";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        return this.countQuery(sql, params).intValue() > 0;
    }

    public boolean removeByServerId(Long serverId, Long userId) {
        String sql = "update volume set is_deleted = true,gmt_modify = :gmtModify,mender_id = :menderId where is_deleted = 0 and server_id = :serverId";
        Map<String, Object> params = MapTools.simpleMap("serverId", serverId);
        params.put("menderId", userId);
        params.put("gmtModify", new Date());
        return this.execute(sql, params) > 0;
    }

    public boolean tenantCheck(Long tenantId, Long creatorId) {
        String sql = "select count(1) from volume a where a.is_deleted = 0 ";
        Map<String, Object> paramMap = Maps.newHashMap();
        if (null != tenantId && 0L != tenantId) {
            sql += " and a.tenant_id = :tenantId";
            paramMap.put("tenantId", tenantId);
        }
        if (null != creatorId && 0L != creatorId) {
            sql += " and a.creator_id = :creatorId";
            paramMap.put("creatorId", creatorId);
        }
        return this.countQuery(sql, paramMap).intValue() > 0;
    }

    public boolean hasBuilding(Long vendorId) {
        String sql = "select count(1) from volume a where a.is_deleted = 0 and a.status = 'BUILDING' and a.vendor_id = :vendorId";
        Map<String, Object> paramMap = MapTools.simpleMap(Common.VENDORID, vendorId);
        return this.countQuery(sql, paramMap) > 0;
    }

    public List<Volume> listByTarget(Long tenantId, Long target) {
        String sql = "select a.*,t.name tenant_name from volume a left join tenant t on a.tenant_id = t.id,object_relation b,user c where a.is_deleted = 0 and a.id = b.res_id and b.target = c.id and b.category = 'Storage'  and c.tenant_id ="
                + tenantId + " and b.target = " + target;
        return this.list(Volume.class, sql);
    }

    public Integer sizeSum(Long vendorId, Long tenantId) {
        String sql = "select sum(size) from volume where is_deleted = 0 and size is not null";
        Map<String, Object> paramMap = Maps.newHashMap();
        if (null != vendorId && 0L != vendorId) {
            sql += " and vendor_id = :vendorId ";
            paramMap.put(Common.VENDORID, vendorId);
        }
        if (null != tenantId && 0L != tenantId) {
            sql += " and tenant_id = :tenantId ";
            paramMap.put("tenantId", tenantId);
        }
        Long count = this.countQuery(sql, paramMap);
        if (null != count) {
            return count.intValue();
        }
        return 0;
    }

    public boolean updateStatus(Long id, String status, Long userId) {
        String sql = "update volume set status = :status,mender_id = :menderId,gmt_modify = :gmtModify where id = :id";
        Map<String, Object> paramMap = MapTools.simpleMap("status", status);
        paramMap.put("menderId", userId);
        paramMap.put("gmtModify", new Date());
        paramMap.put("id", id);
        return this.execute(sql, paramMap) > 0;
    }

    public List<Volume> listByVendorId(Long vendorId, String regionId) {
        String sql = "select a.*,t.name tenant_name from volume a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.vendor_id =:vendorId ";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        if (!StringUtils.isEmpty(regionId)) {
            sql += " and a.region_id = :regionId ";
            params.put(Common.REGIONID, regionId);
        }
        return this.list(Volume.class, sql, params);
    }

    public boolean removeByVid(Long vendorId, String regionId, Long userId) {
        String sql = "update volume set is_deleted = 1, gmt_modify = :gmtModify, mender_id = :menderId where vendor_id = :vendorId";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        if (!StringUtils.isEmpty(regionId)) {
            sql += " and region_id = :regionId ";
            params.put(Common.REGIONID, regionId);
        }
        params.put("gmtModify", new Date());
        params.put("menderId", userId);
        return this.execute(sql, params) > 0;
    }

    public boolean deleteRegionNull(Long vendorId) {
        String sql = "delete from volume where region_id is null and vendor_id = :vendorId ";
        Map<String, Object> params = new HashMap<>(8);
        params.put(Common.VENDORID, vendorId);
        return this.execute(sql, params) > 0;
    }

    public List<Volume> listByTemplateId(long volumeTemplateId) {
        String sql = "select a.*,t.name tenant_name from volume a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.template_id =:templateId";
        Map<String, Object> params = MapTools.simpleMap("templateId", volumeTemplateId);
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> listByStorageId(Long storageId) {
        String sql = "select a.*,t.name tenant_name from volume a left join tenant t on a.tenant_id = t.id "
                + "where a.is_deleted = 0 and a.storage_id =:storageId";
        Map<String, Object> params = MapTools.simpleMap("storageId", storageId);
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> listByPoolId(long poolId) {
        String sql = "select a.*,t.name tenant_name from volume a left join tenant t on a.tenant_id = t.id "
                + "where a.is_deleted = 0 and a.pool_id =:poolId";
        Map<String, Object> params = MapTools.simpleMap("poolId", poolId);
        return this.list(Volume.class, sql, params);
    }

    /**
     * 计算数据存储下磁盘已使用
     *
     * @param dataStoreId
     * @return
     * @throws Exception
     */

    public int diskSum(Long dataStoreId) {
        String sql = "select sum(v.size) from volume v where v.is_deleted = 0 and v.size is not null and v.data_store_id = :dataStoreId";
        Map<String, Object> param = MapTools.simpleMap("dataStoreId", dataStoreId);
        Long count = this.countQuery(sql, param);
        if (null == count) {
            return 0;
        }
        return count.intValue();
    }

    public Volume getByName(Long vendorId, String name) {
        String sql = "select a.* from volume a where a.is_deleted = 0 and a.vendor_id = :vendorId and a.name = :name";
        Map<String, Object> paramMap = MapTools.simpleMap(Common.VENDORID, vendorId);
        paramMap.put("name", name);
        List<Volume> list = this.list(Volume.class, sql, paramMap);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public Volume getByPath(Long vendorId, String path) {
        String sql = "select a.* from volume a where a.is_deleted = 0 and a.vendor_id = :vendorId and a.path = :path";
        Map<String, Object> paramMap = MapTools.simpleMap(Common.VENDORID, vendorId);
        paramMap.put("path", path);
        List<Volume> list = this.list(Volume.class, sql, paramMap);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public Volume getDiskByName(Long serverId, String name) {
        String sql = "select a.* from volume a where a.is_deleted = 0 and a.server_id = :serverId and a.name = :name";
        Map<String, Object> paramMap = MapTools.simpleMap("serverId", serverId);
        paramMap.put("name", name);
        List<Volume> list = this.list(Volume.class, sql, paramMap);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public Volume getByUuid(String uuid) {
        String sql = "select a.* from volume a where a.is_deleted = 0 and a.uuid = :uuid";
        Map<String, Object> paramMap = MapTools.simpleMap("uuid", uuid);
        List<Volume> list = this.list(Volume.class, sql, paramMap);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public Volume getByServerId(Long serverId, String name) {
        String sql = "select a.* from volume a where a.is_deleted = 0 and a.server_id = :serverId and a.name = :name";
        Map<String, Object> param = MapTools.simpleMap("serverId", serverId);
        param.put("name", name);
        List<Volume> list = this.list(Volume.class, sql, param);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public List<Volume> listVolumeInView(Integer page, Integer rows, Long accessPathId, String viewUuid,
                                         List<Param> paramList, Map<String, String> sorter) {
        String sql = "select a.* from volume a where a.is_deleted = 0 "
                + "and a.id in (select volume_id from storage_view_group where access_path_id = :accessPathId and uuid = :viewUuid and is_deleted = 0 )";
        sql = QueryBuilder.buildRaw(sql, paramList, sorter, "a");
        Map<String, Object> sqlParams = new HashMap<>(8);
        sqlParams.put("accessPathId", accessPathId);
        sqlParams.put("viewUuid", viewUuid);
        sql += PageHelper.buildPageSql(page, rows);
        return this.list(Volume.class, sql, sqlParams);
    }

    public int countVolumeInView(Long accessPathId, String viewUuid, List<Param> paramList) {
        String sql = "select count(1) from volume a where a.is_deleted = 0 "
                + "and a.id in (select volume_id from storage_view_group where access_path_id = :accessPathId and uuid = :viewUuid and is_deleted = 0 )";
        sql = QueryBuilder.buildRaw(sql, paramList, null, "a");
        Map<String, Object> sqlParams = new HashMap<>(8);
        sqlParams.put("accessPathId", accessPathId);
        sqlParams.put("viewUuid", viewUuid);
        return this.countQuery(sql, sqlParams).intValue();
    }

    public List<Volume> listVolumeNotInView(Integer page, Integer rows, Long accessPathId, String viewUuid,
                                            List<Param> paramMap, Map<String, String> sorter) {
        String sql = "select a.* from volume a where a.is_deleted = 0 "
                + "and a.id not in (select volume_id from storage_view_group where access_path_id = :accessPathId and uuid = :viewUuid and is_deleted = 0)";
        sql = QueryBuilder.buildRaw(sql, paramMap, sorter, "a");
        Map<String, Object> sqlParams = new HashMap<>(8);
        sqlParams.put("accessPathId", accessPathId);
        sqlParams.put("viewUuid", viewUuid);
        sql += PageHelper.buildPageSql(page, rows);
        return this.list(Volume.class, sql, sqlParams);
    }

    public int countVolumeNotInView(Long accessPathId, String viewUuid, List<Param> paramList) {
        String sql = "select count(1) from volume a where a.is_deleted = 0 "
                + "and a.id not in (select volume_id from storage_view_group where access_path_id = :accessPathId and uuid = :viewUuid and is_deleted = 0)";
        sql = QueryBuilder.buildRaw(sql, paramList, null, "a");
        Map<String, Object> sqlParams = new HashMap<>(8);
        sqlParams.put("accessPathId", accessPathId);
        sqlParams.put("viewUuid", viewUuid);
        return this.countQuery(sql, sqlParams).intValue();
    }

    public List<Volume> listVolumeByServerId(long serverId) {
        return listVolumeByServerId(serverId, null);
    }

    public List<Volume> listVolumeByServerId(long serverId, Boolean canDelete) {
        String sql = "select a.*, c.name as template_name, d.name as storage_name from volume a "
                + "join server_volume b on a.id = b.volume_id "
                + "left join volume_template c on a.template_id = c.id "
                + "left join storage d on a.storage_id = d.id "
                + "left join (select volume_id, count(server_id) as server_count from server_volume group by volume_id) e on a.id = e.volume_id "
                + "where a.is_deleted = 0 and b.server_id = :serverId";
        Map<String, Object> params = MapTools.simpleMap("serverId", serverId);
        if (canDelete != null) {
            if (canDelete) {
                sql += " and e.server_count = 1 ";
            } else {
                sql += " and e.server_count > 1 ";
            }
        }
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> listVolumeByServerIdAndMultiattach(long serverId, Boolean multiattach) {
        String sql = "select a.*, c.name as template_name, d.name as storage_name from volume a "
                + "join server_volume b on a.id = b.volume_id "
                + "left join volume_template c on a.template_id = c.id "
                + "left join storage d on a.storage_id = d.id "
                + "left join (select volume_id, count(server_id) as server_count from server_volume group by volume_id) e on a.id = e.volume_id "
                + "where a.is_deleted = 0 and b.server_id = :serverId and a.multiattach = :multiattach";
        Map<String, Object> params = MapTools.simpleMap("serverId", serverId);
        params.put("multiattach", multiattach);
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> listByHost(Integer page, Integer rows, Long hostId, Map<String, Object> paramMap,
                                   Map<String, String> sorter) {
        String sql = "select a.*, b.name as pool_name from volume a " + "left join volume_pool b on b.id = a.pool_id "
                + "where a.is_deleted = 0 "
                + "and a.id in (select volume_id from storage_view_group where storage_host_id = :hostId and is_deleted = 0 )";
        Map<String, Object> sqlParams = new HashMap<>(8);
        sqlParams.put("hostId", hostId);
        sql += PageHelper.buildPageSql(page, rows);
        return this.list(Volume.class, sql, sqlParams);
    }

    public int countByHost(Long hostId, Map<String, Object> paramMap) {
        String sql = "select count(1) from volume a where a.is_deleted = 0 "
                + "and a.id in (select volume_id from storage_view_group where storage_host_id = :hostId and is_deleted = 0 )";
        Map<String, Object> sqlParams = new HashMap<>(8);
        sqlParams.put("hostId", hostId);
        return this.countQuery(sql, sqlParams).intValue();
    }

    public List<Volume> listInSyncedSet(Integer page, Integer rows, Map<String, Object> paramMap,
                                        Map<String, String> sorter) {
        String sql = "select a.*, b.name as pool_name from volume a "
                + "left join volume_pool b on a.pool_id = b.id and b.is_deleted = 0 " + " where a.is_deleted = 0 ";
        Map<String, Object> sqlParams = new HashMap<>(8);
        if (paramMap.containsKey("syncedSetId")) {
            sql += " and a.synced_set_id = :syncedSetId";
            sqlParams.put("syncedSetId", paramMap.get("syncedSetId"));
        }
        if (paramMap.containsKey("name")) {
            sql += " and a.name like :name";
            sqlParams.put("name", "%" + paramMap.get("name") + "%");
        }
        sql += PageHelper.buildPageSql(page, rows);
        return this.list(Volume.class, sql, sqlParams);
    }

    public int countListInSyncedSet(Map<String, Object> paramMap) {
        String sql = "select count(1) from volume a where a.is_deleted = 0 ";
        Map<String, Object> sqlParams = new HashMap<>(8);
        if (paramMap.containsKey("syncedSetId")) {
            sql += " and a.synced_set_id = :syncedSetId";
            sqlParams.put("syncedSetId", paramMap.get("syncedSetId"));
        }
        if (paramMap.containsKey("name")) {
            sql += " and a.name like :name";
            sqlParams.put("name", "%" + paramMap.get("name") + "%");
        }
        return this.countQuery(sql, sqlParams).intValue();
    }

    public List<Volume> listNotInSyncedSet(Integer page, Integer rows, Map<String, Object> paramMap,
                                           Map<String, String> sorter) {
        String sql = "select a.*, b.name as pool_name from volume a " + "left join volume_pool b on a.pool_id = b.id "
                + "where a.is_deleted = 0 and isnull(a.synced_set_id)";
        Map<String, Object> sqlParams = new HashMap<>(8);
        if (paramMap.containsKey("name")) {
            sql += " and a.name like :name";
            sqlParams.put("name", "%" + paramMap.get("name") + "%");
        }
        if (paramMap.containsKey(Common.VENDORID)) {
            sql += " and a.vendor_id = :vendorId";
            sqlParams.put(Common.VENDORID, paramMap.get(Common.VENDORID));
        }
        if (paramMap.containsKey("poolId")) {
            sql += " and a.pool_id = :poolId";
            sqlParams.put("poolId", paramMap.get("poolId"));
        }
        sql = QueryBuilder.build(sql, new Pager(page, rows, null, sorter), "a");
        return this.list(Volume.class, sql, sqlParams);
    }

    public int countListNotInSyncedSet(Map<String, Object> paramMap) {
        String sql = "select count(1) from volume a where a.is_deleted = 0 and isnull(a.synced_set_id)";
        Map<String, Object> sqlParams = new HashMap<>(8);
        if (paramMap.containsKey("name")) {
            sql += " and a.name like :name";
            sqlParams.put("name", "%" + paramMap.get("name") + "%");
        }
        if (paramMap.containsKey(Common.VENDORID)) {
            sql += " and a.vendor_id = :vendorId";
            sqlParams.put(Common.VENDORID, paramMap.get(Common.VENDORID));
        }
        if (paramMap.containsKey("poolId")) {
            sql += " and a.pool_id = :poolId";
            sqlParams.put("poolId", paramMap.get("poolId"));
        }
        return this.countQuery(sql, sqlParams).intValue();
    }

    public Volume getByNameAndStorageId(String name, long storageId) {
        String sql = "select a.* from volume a where is_deleted = 0 and a.name = :name and a.storage_id = :storageId ";
        Map<String, Object> params = MapTools.simpleMap("name", name);
        params.put("storageId", storageId);
        List<Volume> list = this.list(Volume.class, sql, params);
        return list == null || list.size() == 0 ? null : list.get(0);

    }

    public List<Volume> listTargetVolumeOfFlashCopyBySourceVolume(int page, int rows, long sourceVolumeId,
                                                                  Map<String, Object> params, Map<String, String> sorter) {
        String sql = "select a.*, c.name as pool_name, d.name as storage_name, f.image_count " + " from volume a "
                + " left join volume_pool c on a.pool_id = c.id " + " left join storage d on a.storage_id = d.id "
                + " left join (select e.source_volume_id, count(e.target_volume_id) as image_count "
                + "            from flash_copy e group by e.source_volume_id) f on a.id = f.source_volume_id "
                + " where a.is_deleted = 0 "
                + " and a.vendor_id = (select g.vendor_id from volume g where g.id = :sourceVolumeId)"
                + " and a.size = (select b.size from volume b where b.id = :sourceVolumeId) "
                + " and a.id <> :sourceVolumeId ";
        Map<String, Object> sqlParams = MapTools.simpleMap("sourceVolumeId", sourceVolumeId);
        if (params.containsKey("name")) {
            sql += " and a.name like :name";
            sqlParams.put("name", "%" + params.get("name") + "%");
        }
        return this.list(Volume.class, sql, params);
    }

    public int countTargetVolumeOfFlashCopyBySourceVolume(long sourceVolumeId, Map<String, Object> params) {
        String sql = "select count(1) from volume a " + " where a.is_deleted = 0 "
                + " and a.vendor_id = (select g.vendor_id from volume g where g.id = :sourceVolumeId)"
                + " and a.size = (select b.size from volume b where b.id = :sourceVolumeId)"
                + " and a.id <> :sourceVolumeId ";
        Map<String, Object> sqlParams = MapTools.simpleMap("sourceVolumeId", sourceVolumeId);
        if (params.containsKey("name")) {
            sql += " and a.name like :name";
            sqlParams.put("name", "%" + params.get("name") + "%");
        }
        return this.countQuery(sql, sqlParams).intValue();
    }

    public List<Volume> listForPowervcVMCreate(int page, int rows, String keyword, long vendorId) {
        String sql = "select a.*, b.name template_name, c.name storage_name, d.cloud_server_count, e.image_count from volume a "
                + "left join volume_template b on a.template_id = b.id " + "left join storage c on a.storage_id = c.id "
                + "left join (select volume_id, count(server_id) cloud_server_count from server_volume group by volume_id) d on a.id = d.volume_id "
                + "left join (select volume_id, count(image_id) image_count from image_volume group by volume_id) e on a.id = e.volume_id "
                + "where a.is_deleted = 0 and a.status != 'error' and a.vendor_id =:vendorId and ifnull(e.image_count, 0) = 0 "
                + "and (ifnull(d.cloud_server_count, 0) = 0 or a.multiattach = 1)  ";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        if (!StringUtils.isEmpty(keyword)) {
            sql += " and a.name like :keyword ";
            params.put("keyword", "%" + keyword + "%");
        }
        sql += PageHelper.buildPageSql(page, rows);
        return this.list(Volume.class, sql, params);
    }

    public int countForPowervcVMCreate(String keyword, long vendorId) {
        String sql = "select count(1) from volume a "
                + "left join (select volume_id, count(server_id) cloud_server_count from server_volume group by volume_id) d on a.id = d.volume_id "
                + "left join (select volume_id, count(image_id) image_count from image_volume group by volume_id) e on a.id = e.volume_id "
                + "where a.is_deleted = 0 and a.status != 'error' and a.vendor_id =:vendorId and ifnull(e.image_count, 0) = 0 "
                + "and (ifnull(d.cloud_server_count, 0) = 0 or a.multiattach = 1)  ";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        if (!StringUtils.isEmpty(keyword)) {
            sql += " and a.name like :keyword ";
            params.put("keyword", "%" + keyword + "%");
        }
        return this.countQuery(sql, params).intValue();
    }

    public List<Volume> listForPowervcVMAttach(int page, int rows, String keyword, long vendorId, long vmId) {
        String sql = "select a.*, b.name template_name, c.name storage_name, d.cloud_server_count, e.image_count from volume a "
                + "left join volume_template b on a.template_id = b.id " + "left join storage c on a.storage_id = c.id "
                + "left join (select volume_id, count(server_id) cloud_server_count from server_volume group by volume_id) d on a.id = d.volume_id "
                + "left join (select volume_id, count(image_id) image_count from image_volume group by volume_id) e on a.id = e.volume_id "
                + "where a.is_deleted = 0 and a.status != 'error' and a.vendor_id =:vendorId "
                + "and ifnull(e.image_count, 0) = 0 "
                + "and (ifnull(d.cloud_server_count, 0) = 0 or a.multiattach = 1) "
                + "and a.id not in (select volume_id from server_volume where server_id = :vmId) ";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("vmId", vmId);
        if (!StringUtils.isEmpty(keyword)) {
            sql += " and a.name like :keyword ";
            params.put("keyword", "%" + keyword + "%");
        }
        sql += PageHelper.buildPageSql(page, rows);
        return this.list(Volume.class, sql, params);
    }

    public int countForPowervcVMAttach(String keyword, long vendorId, long vmId) {
        String sql = "select count(1) from volume a "
                + "left join (select volume_id, count(server_id) cloud_server_count from server_volume group by volume_id) d on a.id = d.volume_id "
                + "left join (select volume_id, count(image_id) image_count from image_volume group by volume_id) e on a.id = e.volume_id "
                + "where a.is_deleted = 0 and a.status != 'error' and a.vendor_id =:vendorId "
                + "and ifnull(e.image_count, 0) = 0 "
                + "and (ifnull(d.cloud_server_count, 0) = 0 or a.multiattach = 1) "
                + "and a.id not in (select volume_id from server_volume where server_id = :vmId) ";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("vmId", vmId);
        if (!StringUtils.isEmpty(keyword)) {
            sql += " and a.name like :keyword ";
            params.put("keyword", "%" + keyword + "%");
        }
        return this.countQuery(sql, params).intValue();
    }

    public List<Volume> listForPowervcImageCreate(int page, int rows, String keyword, long vendorId) {
        String sql = "select a.*, b.name template_name, c.name storage_name, d.cloud_server_count, e.image_count from volume a "
                + "left join volume_template b on a.template_id = b.id " + "left join storage c on a.storage_id = c.id "
                + "left join (select volume_id, count(server_id) cloud_server_count from server_volume group by volume_id) d on a.id = d.volume_id "
                + "left join (select volume_id, count(image_id) image_count from image_volume group by volume_id) e on a.id = e.volume_id "
                + "where a.is_deleted = 0 and a.status != 'error' and a.vendor_id =:vendorId and ifnull(d.cloud_server_count, 0) = 0";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        if (!StringUtils.isEmpty(keyword)) {
            sql += " and a.name like :keyword ";
            params.put("keyword", "%" + keyword + "%");
        }
        sql += PageHelper.buildPageSql(page, rows);
        return this.list(Volume.class, sql, params);
    }

    public int countForPowervcImageCreate(String keyword, long vendorId) {
        String sql = "select count(1) from volume a "
                + "left join (select volume_id, count(server_id) cloud_server_count from server_volume group by volume_id) d on a.id = d.volume_id "
                + "left join (select volume_id, count(image_id) image_count from image_volume group by volume_id) e on a.id = e.volume_id "
                + "where a.is_deleted = 0 and a.status != 'error' and a.vendor_id =:vendorId and ifnull(d.cloud_server_count, 0) = 0";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        if (!StringUtils.isEmpty(keyword)) {
            sql += " and a.name like :keyword ";
            params.put("keyword", "%" + keyword + "%");
        }
        return this.countQuery(sql, params).intValue();
    }

    public boolean tenantCheck(Long tenantId, Long projectId, Long creatorId) throws Exception {
        String sql = "select count(1) from volume a where a.is_deleted = 0 ";
        Map<String, Object> paramMap = Maps.newHashMap();
        if (null != tenantId && 0L != tenantId) {
            sql += " and a.tenant_id = :tenantId";
            paramMap.put("tenantId", tenantId);
        }
        if (null != projectId && 0L != projectId) {
            sql += " and a.project_id = :projectId";
            paramMap.put("projectId", projectId);
        }
        if (null != creatorId && 0L != creatorId) {
            sql += " and a.creator_id = :creatorId";
            paramMap.put("creatorId", creatorId);
        }
        return this.countQuery(sql, paramMap).intValue() > 0;
    }

    public boolean removeByGroupId(Long vendorId, Long userId, Long resourceGroupId) throws BoCloudDBException {
        String sql = "update volume set is_deleted = 1, gmt_modify = :gmtModify, mender_id = :menderId where vendor_id = :vendorId and resource_group_id = :resourceGroupId";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("resourceGroupId", resourceGroupId);
        params.put("gmtModify", new Date());
        params.put(Common.MENDER_ID, userId);
        return this.execute(sql, params) > 0;
    }

    public List<Volume> listBackupResources(Long vendorId, String regionId) {
        String sql = " select a.* from volume a where a.vendor_id = :vendorId and a.is_deleted = 0 and a.region_id = :regionId and a.vaults_uuid is null ; ";
        Map<String, Object> params = MapTools.simpleMap("vendorId", vendorId);
        params.put(Common.REGIONID, regionId);
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> getByVaultsUuid(String vaultsUuid, Long vendorId) {
        String sql = "select a.* from volume a  where a.is_deleted = 0 and a.vaults_uuid =:vaultsUuid and a.vendor_id = :vendorId ";
        Map<String, Object> params = MapTools.simpleMap("vaultsUuid", vaultsUuid);
        params.put("vendorId", vendorId);
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> listByVaultsUuid(String vaultsUuid, Long vendorId, String regionId) {
        String sql = " select a.* from volume a where a.vendor_id = :vendorId and a.is_deleted = 0 and a.region_id = :regionId and a.vaults_uuid = :vaultsUuid  ";
        Map<String, Object> params = MapTools.simpleMap("vendorId", vendorId);
        params.put("vaultsUuid", vaultsUuid);
        params.put(Common.REGIONID, regionId);
        return this.list(Volume.class, sql, params);
    }

    public List<Volume> listByInstanceId(String instanceId, Long vendorId, String regionId) {
        String sql = " select a.* from volume a where a.vendor_id = :vendorId and a.is_deleted = 0 and a.region_id = :regionId and a.instance_id = :instanceId  ";
        Map<String, Object> params = MapTools.simpleMap("vendorId", vendorId);
        params.put("instanceId", instanceId);
        params.put(Common.REGIONID, regionId);
        return this.list(Volume.class, sql, params);
    }

    public int count(Long userId, Long tenantId, List<Long> projectIds, List<Param> params, String vendorType, String labelContent) {
        String subquerySql = "select a.* from volume a left join cloud_vendor c on a.vendor_id = c.id   "
                + " where a.is_deleted = 0 ";
        if (!StringUtils.isEmpty(vendorType)) {
            subquerySql += " and c.type = '" + vendorType + "'  ";
        }
        subquerySql = appendLabelSearch(labelContent, subquerySql);
        Map<String, Object> param = QueryBuilder.getParam(params);
        subquerySql = QueryBuilder.build(subquerySql, params, new HashMap<>(8), "a");
        String sql = "select count(1) from (" + subquerySql + ") c  where ( 1=-1 ";
        if (null != userId && 0L != userId) {
            sql += " or c.owner_id =:userId or c.mender_id = :userId ";
            param.put("userId", userId);
        }
        if (null != tenantId && 0L != tenantId) {
            sql += " or c.tenant_id = :tenantId";
            param.put("tenantId", tenantId);
        }
        if (null != projectIds && !projectIds.isEmpty()) {
            sql += " or c.project_id in (:projectIds) ";
            param.put("projectIds", projectIds);
        }
        sql += ")";
        return this.countQuery(sql, param).intValue();
    }

    public List<Volume> list(int page, int rows, Long userId, Long tenantId, List<Long> projectIds, List<Param> params,
                             Map<String, String> sorter, String vendorType, String labelContent) {
        String subquerySql = "select v.*,c.name vendor_name,c.type vendor_type,rsg.name resource_group_name,s.name server_name,t.name tenant_name,f.name as pool_name,ifnull(b.cloud_server_count, 0) cloud_server_count, snap.name as snapshot_name, region.name region_name, zone.name zone_name, vt.name template_name, st.name storage_name from volume v  "
                + " left join volume_pool f on v.pool_id = f.id  "
                + " left join region region on v.region_id = region.region_id and v.vendor_id = region.vendor_id "
                + " left join zone zone on v.vendor_id = zone.vendor_id and v.zone = zone.zone_id "
                + " left join tenant t on v.tenant_id = t.id left join cloud_vendor c on v.vendor_id = c.id "
                + " left join resource_group rsg on v.resource_group_id = rsg.id "
                + " left join cloud_server s on v.server_id = s.id "
                + " left join (select volume_id, count(server_id) cloud_server_count from server_volume group by volume_id) b on v.id = b.volume_id "
                + " left join snapshot snap on snap.id = v.snapshot_id "
                + " left join volume_template vt on v.template_id = vt.id "
                + " left join storage st on v.storage_id = st.id " + " where v.is_deleted = 0 ";
        if (!StringUtils.isEmpty(vendorType)) {
            subquerySql += " and c.type = '" + vendorType + "'  ";
        }
        subquerySql = appendLabelSearch(labelContent, subquerySql);
        subquerySql = QueryBuilder.build(subquerySql, params, new HashMap<>(8), "v");
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        String sql = "select  d.*  from (" + subquerySql + ") d  where ( 1=-1 ";
        if (null != userId && 0L != userId) {
            sql += " or d.owner_id =:userId or d.mender_id = :userId ";
            paramMap.put("userId", userId);
        }
        if (null != tenantId && 0L != tenantId) {
            sql += " or d.tenant_id = :tenantId";
            paramMap.put("tenantId", tenantId);
        }
        if (null != projectIds && !projectIds.isEmpty()) {
            sql += " or d.project_id in (:projectIds) ";
            paramMap.put("projectIds", projectIds);
        }
        sql += " )";
        sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, null, sorter), "d");
        return this.list(Volume.class, sql, paramMap);
    }

    /**
     * @param sql
     * @return java.lang.String
     * @Author: lxy
     * @Description: 拼接标签查询
     * @Date 2021/9/7 14:36
     * @Param labelContent
     * @throws:
     **/
    private String appendLabelSearch(String labelContent, String sql) {
        if (!StringUtils.isEmpty(labelContent)) {
            String[] split = labelContent.split(":");
            sql += " and a.resource_label like '%\"key\":\""
                    + split[0] + "\"%' and a.resource_label like '%\"value\":\"" + split[1] + "\"%'  ";
        }
        return sql;
    }

    public List<Volume> listVolumeForCloudServerAttach(Long serverId, Pager pager) {
        String sql = "select a.*, b.name as template_name from volume a " +
                "left join volume_template b on a.template_id = b.id " +
                "where a.is_deleted = 0 " +
                "and (a.multiattach = 1 or a.id not in (select volume_id from server_volume)) ";
        Map<String, Object> sqlParams = QueryBuilder.getParam(pager.getParams());
        if (serverId != null) {
            sql += " and a.id not in (select volume_id from server_volume where server_id = :serverId) ";
            sqlParams.put("serverId", serverId);
        }
        sql = QueryBuilder.build(sql, pager, "a");
        return this.list(Volume.class, sql, sqlParams);
    }

    public int countVolumeForCloudServerAttach(Long serverId, List<Param> params) {
        String sql = "select count(1) from volume where is_deleted = 0 " +
                "and (multiattach = 1 or id not in (select volume_id from server_volume)) ";
        Map<String, Object> sqlParams = QueryBuilder.getParam(params);
        if (serverId != null) {
            sql += " and id not in (select volume_id from server_volume where server_id = :serverId) ";
            sqlParams.put("serverId", serverId);
        }
        sql = QueryBuilder.build(sql, params, null, "");
        return this.countQuery(sql, sqlParams).intValue();
    }

    public List<Volume> listVolumeOfCloudServerAttached(Long serverId, Pager pager) {
        String sql = "select a.*, b.name as template_name from volume a " +
                "left join volume_template b on a.template_id = b.id " +
                "where a.is_deleted = 0 ";
        Map<String, Object> sqlParams = QueryBuilder.getParam(pager.getParams());
        if (serverId != null) {
            sql += " and a.id in (select volume_id from server_volume where server_id = :serverId) ";
            sqlParams.put("serverId", serverId);
        }
        sql = QueryBuilder.build(sql, pager, "a");
        return this.list(Volume.class, sql, sqlParams);
    }

    public int countVolumeOfCloudServerAttached(Long serverId, List<Param> params) {
        String sql = "select count(1) from volume where is_deleted = 0 ";
        Map<String, Object> sqlParams = QueryBuilder.getParam(params);
        if (serverId != null) {
            sql += " and id in (select volume_id from server_volume where server_id = :serverId) ";
            sqlParams.put("serverId", serverId);
        }
        sql = QueryBuilder.build(sql, params, null, "");
        return this.countQuery(sql, sqlParams).intValue();
    }

    public Integer getSeqNum(Long serverId, Long vendorId) {
        String sql = "select a.* from volume a where a.is_deleted = 0 and a.server_id = :serverId " +
                "and a.vendor_id = :vendorId and a.sequence_num is not NULL " +
                " order by a.sequence_num DESC LIMIT 1";
        Map<String, Object> params = MapTools.simpleMap("serverId", serverId);
        params.put("vendorId", vendorId);
        List<Volume> list = this.list(Volume.class, sql, params);
        return list == null || list.size() == 0 ? null : list.get(0).getSequenceNum();
    }
}
