package com.bocloud.ims.repository.resource;

import com.bocloud.cmp.entity.enums.ResourceCategory;
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.IDFactory;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.database.core.intf.impl.BasicGenericDao;
import com.bocloud.database.utils.QueryBuilder;
import com.bocloud.ims.entity.resource.CloudServer;
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("cloudServerRepository") public class CloudServerRepository extends OrmGenericDaoImpl<CloudServer, Long> {

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

    @Override public void save(CloudServer server) throws BoCloudDBException {
        server.setGuid(IDFactory.instance().uuid());
        super.save(server);
    }

    public CloudServer get(Long id) {
        String sql = "select a.* from cloud_server a where a.is_deleted = 0 and a.id = :id";
        Map<String, Object> params = MapTools.simpleMap("id", id);
        List<CloudServer> list = this.list(CloudServer.class, sql, params);
        return list.isEmpty() ? null : list.get(0);
    }

    public CloudServer get(String instanceId) {
        String sql = "select a.* from cloud_server a where a.is_deleted = 0 and a.instance_id = :instanceId";
        Map<String, Object> params = MapTools.simpleMap("instanceId", instanceId);
        List<CloudServer> list = this.list(CloudServer.class, sql, params);
        return list.isEmpty() ? null : list.get(0);
    }

    public List<CloudServer> list(int page, int rows, List<Param> params, Map<String, String> sorter, Long labelId,
        List<Long> projectIds, List<Long> vendorids) {
        String sql = null;
        if (null != labelId && 0L != labelId) {
            sql = "select DISTINCT a.*,b.name vendor_name,t.name from cloud_server a "
                + " left join cloud_vendor b on b.id = a.vendor_id" + " left join tenant t on a.tenant_id = t.id"
                + " where a.is_deleted = 0 and a.id in (select b.target from server_label b where b.type = 'VM' and b.label_id = "
                + labelId + " )";
        } else {
            sql =
                "select a.*,b.name vendor_name, b.type vendor_type , t.name tenant_name,c.cluster_id,u.name target_name, region.`name` region_name, zone.name zone_name, p.name project_name from cloud_server a "
                    + " left join tenant t on a.tenant_id = t.id left join cloud_vendor b on a.vendor_id = b.id left join server c on a.host_id = c.id left join object_relation o on o.res_id = a.id and o.category = 'Computer' left join user u on u.id = o.target "
                    + " left join region region on a.region_id = region.region_id and a.vendor_id = region.vendor_id "
                    + " left join zone zone on a.zone = zone.zone_Id and a.vendor_id = zone.vendor_id "
                    + " left join project p on a.project_id = p.id " + " where a.is_deleted = 0 ";
        }
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        if (!ListTool.isEmpty(projectIds)) {
            sql += " and a.project_id in (:projectIds) ";
            paramMap.put("projectIds", projectIds);
        }
        if (!ListTool.isEmpty(vendorids)) {
            sql += " and a.vendor_id in (:vendorids) ";
            paramMap.put("vendorids", vendorids);
        }
        sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "a");
        return this.list(CloudServer.class, sql, paramMap);
    }

    public List<CloudServer> list(int page, int rows, List<Param> params, Map<String, String> sorter,
        String labelContent) {
        String sql =
            "select a.*,b.name vendor_name, b.type vendor_type , t.name tenant_name,c.cluster_id,u.name target_name, region.`name` region_name, zone.name zone_name, p.name project_name from cloud_server a "
                + " left join tenant t on a.tenant_id = t.id left join cloud_vendor b on a.vendor_id = b.id left join server c on a.host_id = c.id left join object_relation o on o.res_id = a.id and o.category = 'Computer' left join user u on u.id = o.target "
                + " left join region region on a.region_id = region.region_id and a.vendor_id = region.vendor_id "
                + " left join zone zone on a.zone = zone.zone_Id and a.vendor_id = zone.vendor_id "
                + " left join project p on a.project_id = p.id " + " where a.is_deleted = 0 ";
        if (!StringUtils.isEmpty(labelContent)) {
            String[] split = labelContent.split(":");
            sql +=
                " and a.id in  (select sl.target from server_label sl where sl.type = 'VM' and sl.vendor_id = a.vendor_id and sl.content like '%\"key\":\""
                    + split[0] + "\"%' and sl.content like '%\"value\":\"" + split[1] + "\"%' ) ";
        }
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "a");
        return this.list(CloudServer.class, sql, paramMap);
    }

    public List<SimpleBean> list(List<Param> params, Map<String, String> sorter, List<Long> projectIds,
        List<Long> vendorIds) {
        String sql = "select a.id,a.name,a.instance_id from cloud_server a where a.is_deleted = 0";
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        if (!ListTool.isEmpty(projectIds)) {
            sql += " and a.project_id in (:projectIds) ";
            paramMap.put("projectIds", projectIds);
        }
        if (!ListTool.isEmpty(vendorIds)) {
            sql += " and a.vendor_id in (:vendorIds) ";
            paramMap.put("vendorIds", vendorIds);
        }
        sql = QueryBuilder.build(sql, new Pager(1, Integer.MAX_VALUE, params, sorter), "a");
        List<CloudServer> vms = this.list(CloudServer.class, sql, paramMap);
        List<SimpleBean> beans = new ArrayList<>();
        for (CloudServer vm : vms) {
            SimpleBean simpleBean = new SimpleBean(vm.getId(), vm.getName());
            simpleBean.setUuid(vm.getInstanceId());
            beans.add(simpleBean);
        }
        return beans;
    }

    public List<SimpleBean> list(List<Param> params, Map<String, String> sorter) {
        String sql = "select a.id,a.name,a.instance_id from cloud_server a where a.is_deleted = 0";
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        sql = QueryBuilder.build(sql, new Pager(1, Integer.MAX_VALUE, params, sorter), "a");
        List<CloudServer> vms = this.list(CloudServer.class, sql, paramMap);
        List<SimpleBean> beans = new ArrayList<>();
        for (CloudServer vm : vms) {
            SimpleBean simpleBean = new SimpleBean(vm.getId(), vm.getName());
            simpleBean.setUuid(vm.getInstanceId());
            beans.add(simpleBean);
        }
        return beans;
    }

    public int count(List<Param> params, Long subnetId) {
        String sql = "select count(a.id) from cloud_server a where a.is_deleted = 0 ";
        sql = QueryBuilder.buildRaw(sql, params, null, "a");
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        return this.countQuery(sql, paramMap).intValue();
    }

    public int vmCount(List<Param> params, String labelContent) {
        String sql = "select count(a.id) from cloud_server a where a.is_deleted = 0 ";
        if (!StringUtils.isEmpty(labelContent)) {
            String[] split = labelContent.split(":");
            sql +=
                " and a.id in (select sl.target from server_label sl where sl.type = 'VM' and sl.vendor_id = a.vendor_id and sl.content like '%\"key\":\""
                    + split[0] + "\"%' and sl.content like '%\"value\":\"" + split[1] + "\"%' ) ";
        }
        sql = QueryBuilder.buildRaw(sql, params, null, "a");
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        return this.countQuery(sql, paramMap).intValue();
    }

    /**
     * 查询指定云平台下的虚拟机总数
     *
     * @param types
     * @return
     * @throws Exception
     */

    public Integer vendorCount(List<String> types) {
        String sql = "select count(id) from cloud_server where is_deleted = 0 and vendor_type in (:vendorTypes)";
        Map<String, Object> paramMap = MapTools.simpleMap("vendorTypes", types);
        return this.countQuery(sql, paramMap).intValue();
    }

    public int count(List<Param> params, Long labelId, List<Long> projectIds, List<Long> vendorIds) {
        String sql = null;
        if (null != labelId && 0L != labelId) {
            sql =
                "select count(a.id) from cloud_server a where a.is_deleted = 0 and a.id in (select b.target from server_label b where b.type = 'VM' and b.label_id = "
                    + labelId + ")";
        } else {
            sql = "select count(a.id) from cloud_server a where a.is_deleted = 0 ";
        }
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        if (!ListTool.isEmpty(projectIds)) {
            sql += " and a.project_id in (:projectIds) ";
            paramMap.put("projectIds", projectIds);
        }
        if (!ListTool.isEmpty(vendorIds)) {
            sql += " and a.vendor_id in (:vendorIds) ";
            paramMap.put("vendorIds", vendorIds);
        }
        sql = QueryBuilder.buildRaw(sql, params, null, "a");
        return this.countQuery(sql, paramMap).intValue();
    }

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

    /**
     * 虚拟机的管理IP是否存在
     *
     * @since V1.1 2016-09-13 modify by sxp 只检测是否存在，不需要查询出全部字段
     */

    public boolean exists(String name, Long vendorId) {
        String sql =
            "select id from cloud_server a where a.is_deleted = 0 and a.name = :name and a.vendor_id = :vendorId";
        Map<String, Object> params = MapTools.simpleMap("name", name);
        params.put(Common.VENDORID, vendorId);
        List<CloudServer> list = this.list(CloudServer.class, sql, params);
        return !list.isEmpty();
    }

    public CloudServer query(Long id) {
        String sql =
            "select a.*,b.name vendor_name,t.name tenant_name,pj.name project_name, r.`name` region_name, user.name user_name,os.name op_tenant_name from cloud_server a "
                + " left join tenant t on a.tenant_id = t.id "
                + " left join user user on a.owner_id = user.id and user.is_deleted = 0 "
                + " left join region r on a.region_id = r.region_id and r.vendor_id = a.vendor_id "
                + " left join cloud_vendor b on a.vendor_id = b.id "
                + " left join os_tenant os on a.tenant_uuid = os.tenant_uuid and a.vendor_id = os.vendor_id "
                + " left join object_relation o on o.res_id = a.id and o.category = 'Computer' "
                + " left join project pj on pj.id = a.project_id " + " where a.is_deleted = 0 and a.id = :id";
        Map<String, Object> params = MapTools.simpleMap(Common.ID, id);
        List<CloudServer> list = this.list(CloudServer.class, sql, params);
        return list.isEmpty() ? null : list.get(0);
    }

    public CloudServer queryAccount(Long id) {
        String sql =
            "select a.id,a.account,a.password,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.id = :id";
        Map<String, Object> params = MapTools.simpleMap(Common.ID, id);
        List<CloudServer> list = this.list(CloudServer.class, sql, params);
        return list.isEmpty() ? null : list.get(0);
    }

    public List<CloudServer> queryAll() {
        String sql =
            "select a.*,t.name tenant_name, r.`name` region_name from cloud_server a left join tenant t on a.tenant_id = t.id left join region r on r.vendor_id = a.vendor_id and r.region_id = a.region_id where a.is_deleted = 0 and a.is_template = 0";
        return this.list(CloudServer.class, sql);
    }

    public List<CloudServer> listByCondition(Long vendorId, Long vdcId, Long clusterId) {
        String sql =
            "select a.* from cloud_server a left join server s on a.host_id = s.id where a.is_deleted = 0 and a.is_template = 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 s.vdc_id = :vdcId";
            params.put("vdcId", vdcId);
        }
        if (null != clusterId && 0L != clusterId) {
            sql += " and s.cluster_id = :clusterId";
            params.put("clusterId", clusterId);
        }
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listByVms(List<Long> serverIds) {
        String sql =
            "select a.*,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.host_id in (:serverIds)";
        Map<String, Object> params = MapTools.simpleMap("serverIds", serverIds);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listByVendorId(Long vendorId) {
        String sql =
            "select a.*,t.name tenant_name, r.`name` region_name, v.`name` vpc_name from  cloud_server a  left join tenant t on a.tenant_id = t.id "
                + " left join region r on r.vendor_id = a.vendor_id and r.region_id = a.region_id "
                + " left join vpc v on a.vendor_id = v.vendor_id and a.vpc_uuid = v.vpc_id "
                + " where a.is_deleted = 0 and a.vendor_id = :vendorId and a.is_template = 0";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listByHid(Long hostId) {
        String sql =
            "select a.*,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.host_id = :hostId";
        Map<String, Object> params = MapTools.simpleMap("hostId", hostId);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listByHid(List<Long> hostIds) {
        String sql =
            "select a.*,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.host_id in (:hostId)";
        Map<String, Object> params = MapTools.simpleMap("hostId", hostIds);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listByImageUuid(String imageUuid) {
        String sql = "select a.*,t.name tenant_name, b.name as host_server_name "
            + "from cloud_server a left join tenant t on a.tenant_id = t.id "
            + "left join server b on a.host_id = b.id " + "where a.is_deleted = 0 and a.image_uuid = :imageUuid";
        Map<String, Object> params = MapTools.simpleMap("imageUuid", imageUuid);
        return this.list(CloudServer.class, sql, params);
    }

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

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

    public List<CloudServer> list(Long vendorId, String networkUuid) {
        String sql =
            "select a.* from cloud_server a where a.is_deleted = 0 and a.vendor_id = :vendorId and a.network_uuid = :networkUuid";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("networkUuid", networkUuid);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listByFid(Long vendorId, String flavorUuid) {
        String sql =
            "select a.* from cloud_server a where a.is_deleted = 0 and a.vendor_id = :vendorId and a.flavor_uuid = :flavorUuid";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("flavorUuid", flavorUuid);
        return this.list(CloudServer.class, sql, params);
    }

    public List<Map<String, String>> getAll4Snmp() {
        String sql = "select uuid,manager_ip from cloud_server where is_deleted = 0";
        List<CloudServer> vms = this.list(CloudServer.class, sql);
        List<Map<String, String>> result = new ArrayList<>();
        Map<String, String> map;
        String ip;
        for (CloudServer vm : vms) {
            ip = vm.getManagerIp();
            if (StringUtils.isEmpty(ip)) {
                continue;
            }
            map = new HashMap<>(8);
            map.put("uuid", vm.getUuid());
            map.put("ip", ip);
            result.add(map);
        }
        return result;
    }

    public boolean removeByHost(Long hostId, Long userId) {
        String sql =
            "update cloud_server set is_deleted = true,gmt_modify = :gmtModify where is_deleted = 0 and host_id = :hostId";
        Map<String, Object> params = MapTools.simpleMap("hostId", hostId);
        params.put("gmtModify", new Date());
        return this.execute(sql, params) > 0;
    }

    public List<CloudServer> listvmByvhost(long venderId, String hostName) {
        String sql =
            "select a.*,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.vendor_id = :venderId and a.host_name = :hostName";
        Map<String, Object> params = MapTools.simpleMap("venderId", venderId);
        params.put("hostName", hostName);
        return this.list(CloudServer.class, sql, params);
    }

    public int count(List<Param> params, String type) {
        String sql =
            "select count(a.id) from cloud_server a,cloud_vendor b where a.is_deleted = 0 and a.vendor_id = b.id";
        if (!StringUtils.isEmpty(type)) {
            sql += " and b.type = '" + type + "'";
        }
        sql = QueryBuilder.buildRaw(sql, params, null, "a");
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        return this.countQuery(sql, paramMap).intValue();
    }

    public boolean updateStatusByHost(Long hostId, String status, Long userId, String original) {
        String sql =
            "update cloud_server set status = :status,gmt_modify = :gmtModify where is_deleted = 0 and host_id = :hostId and status = :original";
        Map<String, Object> params = MapTools.simpleMap("hostId", hostId);
        params.put("gmtModify", new Date());
        params.put("status", status);
        params.put("original", original);
        return this.execute(sql, params) > 0;
    }

    public List<CloudServer> listByStore(Long storeId) {
        String sql =
            "select a.*,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id,store_host b where a.is_deleted = 0 and a.is_template = false and a.id = b.vhost_id and b.category = 'VM' and b.store_id = :storeId";
        Map<String, Object> params = MapTools.simpleMap("storeId", storeId);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listServers(int page, int rows, List<Param> params, Map<String, String> sorter,
        Long targetId, String category) {
        String sql = null;
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        if (category.equals(ResourceCategory.Storage.name())) {
            sql =
                "select a.*,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id,store_host b where a.is_deleted = 0 and a.is_template = false and a.id = b.vhost_id and b.category = 'VM' and b.store_id = :targetId";
            paramMap.put("targetId", targetId);
        } else if (category.equals(ResourceCategory.Network.name())) {
            sql =
                "select a.*,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id,network_host b where a.is_deleted = 0 and a.is_template = false and a.id = b.vhost_id and b.category = 'VM' and b.network_id = :targetId";
            paramMap.put("targetId", targetId);
        } else {
            sql =
                "select a.*,b.name vendor_name,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id left join cloud_vendor b on a.vendor_id = b.id where a.is_deleted = 0";
        }
        sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "a");
        return this.list(CloudServer.class, sql, paramMap);
    }

    public int count(String category, Long targetId, List<Param> params) {
        String sql = null;
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        if (category.equals(ResourceCategory.Storage.name())) {
            sql =
                "select count(a.id) from cloud_server a,store_host b where a.is_deleted = 0 and a.is_template = false and a.id = b.vhost_id and b.category = 'VM' and b.store_id = :targetId";
            paramMap.put("targetId", targetId);
        } else if (category.equals(ResourceCategory.Network.name())) {
            sql =
                "select count(a.id) from cloud_server a,network_host b where a.is_deleted = 0 and a.is_template = false and a.id = b.vhost_id and b.category = 'VM' and b.network_id = :targetId";
            paramMap.put("targetId", targetId);
        } else {
            sql = "select count(a.id) from cloud_server a where a.is_deleted = 0";
        }
        sql = QueryBuilder.buildRaw(sql, params, null, "a");
        return this.countQuery(sql, paramMap).intValue();
    }

    public List<CloudServer> list(int page, int rows, List<Param> params, Map<String, String> sorter, Long subnetId,
        Long tenantId, List<Long> projectIds, List<String> vendorTypes) {
        String sql = null;
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        if (null != subnetId && 0L != subnetId) {
            if (null != tenantId && 0L != tenantId) {
                sql =
                    "select a.*,v.name vendor_name,b.expired_time,t.name tenant_name, r.`name` region_name,z.`name` zone_name"
                        + " from cloud_server a  "
                        + " left join region r on r.region_id = a.region_id and r.vendor_id = a.vendor_id "
                        + " left join zone z on z.zone_id = a.zone and z.vendor_id = a.vendor_id "
                        + " left join port p on a.instance_id = p.device_uuid "
                        + " left join port_fixedip pf on p.id = pf.port_id  "
                        + " 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.is_deleted = 0 and a.id = b.res_id and b.category = 'Computer' and a.tenant_id = "
                        + tenantId + " and pf.subnet_id = " + subnetId;
            } else {
                sql =
                    "select a.*,b.expired_time,project.visibility project_visibility,v.name vendor_name,t.name tenant_name , r.`name` region_name,z.`name` zone_name "
                        + " from cloud_server a "
                        + " left join region r on r.region_id = a.region_id and r.vendor_id = a.vendor_id "
                        + " left join zone z on z.zone_id = a.zone and z.vendor_id = a.vendor_id "
                        + " left join project project on a.project_id = project.id "
                        + " left join port p on a.instance_id = p.device_uuid left join port_fixedip pf on p.id = pf.port_id  left join tenant t on a.tenant_id = t.id left join cloud_vendor v on a.vendor_id = v.id left join object_relation b on a.id = b.res_id and b.category = 'Computer' where a.is_deleted = 0 and pf.subnet_id = "
                        + subnetId;
            }
        } else {
            if (null != tenantId && 0L != tenantId) {
                sql =
                    "select a.*,v.name vendor_name,b.expired_time,t.name tenant_name , r.`name` region_name,z.`name` zone_name"
                        + " from cloud_server a "
                        + " left join region r on r.region_id = a.region_id and r.vendor_id = a.vendor_id "
                        + " left join zone z on z.zone_id = a.zone and z.vendor_id = a.vendor_id "
                        + " 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 = 'Computer' and a.is_deleted = 0 and a.tenant_id = "
                        + tenantId;
            } else {
                sql =
                    "select a.*,v.name vendor_name,b.expired_time,t.name tenant_name , r.`name` region_name,z.`name` zone_name "
                        + " from cloud_server a "
                        + " left join region r on r.region_id = a.region_id and r.vendor_id = a.vendor_id "
                        + " left join zone z on z.zone_id = a.zone and z.vendor_id = a.vendor_id "
                        + " left join project project on a.project_id = project.id "
                        + " 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.is_deleted = 0 and a.id = b.res_id and b.category = 'Computer'";
            }
        }
        if (!ListTool.isEmpty(projectIds)) {
            sql += " and a.project_id in (:projectIds) ";
            paramMap.put("projectIds", projectIds);
        }
        if (!ListTool.isEmpty(vendorTypes)) {
            sql += " and a.vendor_type in (:vendorTypes) ";
            paramMap.put("vendorTypes", vendorTypes);
        }
        sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "a");
        return this.list(CloudServer.class, sql, paramMap);
    }

    public int count(List<Param> params, Long subnetId, Long tenantId, List<Long> projectIds, List<String> vendorTypes)
        throws Exception {
        String sql = null;
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        if (null != subnetId && 0L != subnetId) {
            if (null != tenantId && 0L != tenantId) {
                sql = "select count(a.id) " + " from cloud_server a  "
                    + " left join region r on r.region_id = a.region_id and r.vendor_id = a.vendor_id "
                    + " left join zone z on z.zone_id = a.zone and z.vendor_id = a.vendor_id "
                    + " left join port p on a.instance_id = p.device_uuid "
                    + " left join port_fixedip pf on p.id = pf.port_id  " + " 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.is_deleted = 0 and a.id = b.res_id and b.category = 'Computer' and a.tenant_id = "
                    + tenantId + " and pf.subnet_id = " + subnetId;
            } else {
                sql = "select count(a.id) " + " from cloud_server a "
                    + " left join region r on r.region_id = a.region_id and r.vendor_id = a.vendor_id "
                    + " left join zone z on z.zone_id = a.zone and z.vendor_id = a.vendor_id "
                    + " left join project project on a.project_id = project.id "
                    + " left join port p on a.instance_id = p.device_uuid left join port_fixedip pf on p.id = pf.port_id  left join tenant t on a.tenant_id = t.id left join cloud_vendor v on a.vendor_id = v.id left join object_relation b on a.id = b.res_id and b.category = 'Computer' where a.is_deleted = 0 and pf.subnet_id = "
                    + subnetId;
            }
        } else {
            if (null != tenantId && 0L != tenantId) {
                sql = "select count(a.id) " + " from cloud_server a "
                    + " left join region r on r.region_id = a.region_id and r.vendor_id = a.vendor_id "
                    + " left join zone z on z.zone_id = a.zone and z.vendor_id = a.vendor_id "
                    + " 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 = 'Computer' and a.is_deleted = 0 and a.tenant_id = "
                    + tenantId;
            } else {
                sql = "select count(a.id) " + " from cloud_server a "
                    + " left join region r on r.region_id = a.region_id and r.vendor_id = a.vendor_id "
                    + " left join zone z on z.zone_id = a.zone and z.vendor_id = a.vendor_id "
                    + " left join project project on a.project_id = project.id "
                    + " 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.is_deleted = 0 and a.id = b.res_id and b.category = 'Computer'";
            }
        }
        if (!ListTool.isEmpty(projectIds)) {
            sql += " and a.project_id in (:projectIds) ";
            paramMap.put("projectIds", projectIds);
        }
        if (!ListTool.isEmpty(vendorTypes)) {
            sql += " and a.vendor_type in (:vendorTypes) ";
            paramMap.put("vendorTypes", vendorTypes);
        }
        sql = QueryBuilder.buildRaw(sql, params, null, "a");
        return this.countQuery(sql, paramMap).intValue();
    }

    public List<CloudServer> listByVolume(Long volumeId) {
        String sql =
            "select a.*,v.name vendor_name,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id left join cloud_vendor v on a.vendor_id = v.id left join volume b on a.id = b.server_id where a.is_deleted = 0 and b.id = :volumeId";
        Map<String, Object> params = MapTools.simpleMap("volumeId", volumeId);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listByVendorType(Long tenantId, String vendorType) {
        String sql =
            "select a.*,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id,object_relation b where a.is_deleted = 0 and a.is_recycle = 0 and a.id = b.res_id and b.category = 'Computer' and a.tenant_id = "
                + tenantId + " and a.vendor_type = '" + vendorType + "' ";
        return this.list(CloudServer.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 = 'Computer'";
        Map<String, Object> params = MapTools.simpleMap("resId", resId);
        params.put("expiredTime", expiredTime);
        return this.execute(sql, params) > 0;
    }

    public boolean recycle(Long id, Long userId) {
        String sql =
            "update cloud_server set recycle_time = :recycleTime,is_recycle = true,gmt_modify = :gmtModify,gmt_vmremove = :gmtVmremove where is_deleted = 0 and id = :id";
        Map<String, Object> params = MapTools.simpleMap("id", id);
        params.put("gmtModify", new Date());
        params.put("gmtVmremove", new Date());
        params.put("recycleTime", new Date());
        return this.execute(sql, params) > 0;
    }

    public boolean restore(Long id, Long userId) {
        String sql =
            "update cloud_server set is_recycle = false,gmt_modify = :gmtModify,gmt_vmremove = null where is_deleted = 0 and id = :id";
        Map<String, Object> params = MapTools.simpleMap("id", id);
        params.put("gmtModify", new Date());
        return this.execute(sql, params) > 0;
    }

    public List<CloudServer> listRecycle(Long vendorId) {
        String sql =
            "select a.* from cloud_server a where a.is_deleted = 0 and a.is_recycle = 1 and (a.is_template = 0 or a.is_template is null) and a.vendor_id = :vendorId";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        return this.list(CloudServer.class, sql, params);
    }

    public CloudServer get(Long id, Boolean ifHasPass) {
        String sql =
            "select a.*,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.id = :id";
        Map<String, Object> params = MapTools.simpleMap("id", id);
        List<CloudServer> list = this.list(CloudServer.class, sql, params);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public CloudServer get(String instanceId, Long vendorId) {
        String sql =
            "select a.* from cloud_server a where a.is_deleted = 0 and a.instance_id = :instanceId and a.vendor_id = :vendorId";
        Map<String, Object> params = MapTools.simpleMap("instanceId", instanceId);
        params.put("vendorId", vendorId);
        List<CloudServer> list = this.list(CloudServer.class, sql, params);
        return list.isEmpty() ? null : list.get(0);
    }

    public CloudServer getByInstanceId(String instanceId) {
        return getByInstanceId(instanceId, null);
    }

    public CloudServer getByInstanceId(String instanceId, Long vendorId) {
        String sql = "select a.*,t.name tenant_name " + "from cloud_server a left join tenant t on a.tenant_id = t.id "
            + "where a.is_deleted = 0 and a.instance_id = :instanceId";
        Map<String, Object> params = MapTools.simpleMap("instanceId", instanceId);
        if (vendorId != null) {
            sql += " and a.vendor_id = :vendorId ";
            params.put(Common.VENDORID, vendorId);
        }
        List<CloudServer> list = this.list(CloudServer.class, sql, params);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public boolean inUseByTenants(Long vendorId) {
        String sql =
            "select count(1) from cloud_server 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 List<CloudServer> listServersByNetwork(Long networkId, Long hostId) {
        String sql =
            "select a.*,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id,network_host b where a.is_deleted = 0 and a.id = b.vhost_id and b.category = 'VM' and b.network_id = :networkId and a.host_id = :hostId";
        Map<String, Object> paramMap = MapTools.simpleMap("hostId", hostId);
        paramMap.put("networkId", networkId);
        return this.list(CloudServer.class, sql, paramMap);
    }

    public List<CloudServer> listByResPoolId(Long resPoolId) {
        String sql = "select a.* from cloud_server a where a.is_deleted = 0 and a.res_pool_id = :resPoolId";
        Map<String, Object> paramMap = MapTools.simpleMap("resPoolId", resPoolId);
        return this.list(CloudServer.class, sql, paramMap);
    }

    public boolean tenantCheck(Long tenantId, Long creatorId) {
        String sql = "select count(1) from cloud_server 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(a.id) from cloud_server a where a.is_deleted = 0 and a.status = 'BUILDING' and a.vendor_id = :vendorId and a.is_template = 0";
        Map<String, Object> paramMap = MapTools.simpleMap(Common.VENDORID, vendorId);
        return this.countQuery(sql, paramMap) > 0;
    }

    public List<CloudServer> listByVdcId(Long vdcId) {
        String sql = "select a.* from cloud_server a where a.is_deleted = 0 and a.vdc_id = :vdcId";
        Map<String, Object> paramMap = MapTools.simpleMap("vdcId", vdcId);
        return this.list(CloudServer.class, sql, paramMap);
    }

    public List<CloudServer> listByTarget(Long tenantId, Long target, String vendorType) {
        String sql =
            "select a.*,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id,object_relation b,user c where a.is_deleted = 0 and a.is_recycle = 0 and a.id = b.res_id and b.target = c.id and b.category = 'Computer'  and a.tenant_id = "
                + tenantId + " and a.vendor_type = '" + vendorType + "' ";
        if (null != target && 0L != target) {
            sql += " and b.target = " + target;
        }
        return this.list(CloudServer.class, sql);
    }

    public List<CloudServer> list(int page, int rows, Long clusterId, List<Param> params, Map<String, String> sorter) {
        String sql = "select a.*,b.name vendor_name,c.cluster_id from cloud_server a "
            + " left join cloud_vendor b on a.vendor_id = b.id " + " left join server c on a.host_id = c.id "
            + " where a.is_deleted = 0 and c.cluster_id = " + clusterId + " and a.is_template = 0 ";
        sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "a");
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        return this.list(CloudServer.class, sql, paramMap);
    }

    public int count(Long userId, Long tenantId, List<Long> projectIds, List<Param> params, String labelContent) {
        String subquerySql = "SELECT a.* FROM cloud_server a where  a.is_deleted = 0 and a.is_template = 0 ";
        if (!StringUtils.isEmpty(labelContent)) {
            String[] split = labelContent.split(":");
            subquerySql +=
                " and a.id in (select sl.target from server_label sl where sl.type = 'VM' and sl.vendor_id = a.vendor_id and sl.content like '%\"key\":\""
                    + split[0] + "\"%' and sl.content like '%\"value\":\"" + split[1] + "\"%' ) ";
        }
        Map<String, Object> param = QueryBuilder.getParam(params);
        subquerySql = QueryBuilder.buildRaw(subquerySql, params, new HashMap<>(8), "a");
        String sql = "select distinct 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<CloudServer> list(int page, int rows, Long userId, Long tenantId, List<Long> projectIds,
        List<Param> params, Map<String, String> sorter, String labelContent) {
        String subquerySql = "SELECT a.*,b.name vendor_name,c.cluster_id, zone.name zone_name FROM cloud_server a "
            + " left join cloud_vendor b on a.vendor_id = b.id " + " left join server c on a.host_id = c.id "
            + " left join zone zone on a.zone = zone.zone_Id and a.vendor_id = zone.vendor_id "
            + " where a.is_deleted = 0 and a.is_template = 0 ";
        if (!StringUtils.isEmpty(labelContent)) {
            String[] split = labelContent.split(":");
            subquerySql +=
                " and a.id in (select sl.target from server_label sl where sl.type = 'VM' and sl.vendor_id = a.vendor_id and sl.content like '%\"key\":\""
                    + split[0] + "\"%' and sl.content like '%\"value\":\"" + split[1] + "\"%' ) ";
        }
        subquerySql = QueryBuilder.buildRaw(subquerySql, params, new HashMap<>(8), "a");
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        String sql = "select distinct d.*,d.name vendor_name,d.cluster_id 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(CloudServer.class, sql, paramMap);
    }

    public List<CloudServer> listAll(int page, int rows, Long userId, Long tenantId, List<Long> projectIds,
        List<Param> params, Map<String, String> sorter, Boolean containRemove) {
        String subquerySql = "SELECT a.*,b.name vendor_name,c.cluster_id, zone.name zone_name FROM cloud_server a "
            + " left join cloud_vendor b on a.vendor_id = b.id " + " left join server c on a.host_id = c.id "
            + " left join zone zone on a.zone = zone.zone_Id and a.vendor_id = zone.vendor_id "
            + " where a.is_template = 0 ";
        if (!containRemove) {
            subquerySql += " and a.is_deleted = 0";
        }
        subquerySql = QueryBuilder.buildRaw(subquerySql, params, new HashMap<>(8), "a");
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        String sql = "select distinct d.*,d.name vendor_name,d.cluster_id 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(CloudServer.class, sql, paramMap);
    }

    public int count(Long clusterId, List<Param> params) {
        String sql =
            "select count(1) from cloud_server a left join server b on a.host_id = b.id where a.is_deleted = 0 and b.cluster_id = "
                + clusterId + " and a.is_template = 0 ";
        sql = QueryBuilder.build(sql, params, new HashMap<>(8), "a");
        Map<String, Object> param = QueryBuilder.getParam(params);
        return this.countQuery(sql, param).intValue();
    }

    public List<CloudServer> listByVendor(String vendorType) {
        String sql =
            "select a.*,s.name host,c.name cluster_name,v.name vdc_name,cv.name vendor_name from cloud_server a left join server s on a.host_id = s.id and s.is_deleted = 0 left join cluster c on s.cluster_id = c.id and c.is_deleted = 0 left join vdc v on v.id = a.vdc_id and v.is_deleted = 0 left join cloud_vendor cv on cv.id = a.vendor_id and cv.is_deleted = 0 where a.is_deleted = 0 and a.is_template = 0 and a.vendor_type = :vendorType";
        Map<String, Object> params = MapTools.simpleMap("vendorType", vendorType);
        return this.list(CloudServer.class, sql, params);
    }

    public Integer cpuSum(Long vendorId, Long tenantId, Long projectId) {
        String sql = "select sum(cpu) from cloud_server where is_deleted = 0 and cpu 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);
        }
        if (null != projectId && 0L != projectId) {
            sql += " and project_id = :projectId ";
            paramMap.put("projectId", projectId);
        }
        Long count = this.countQuery(sql, paramMap);
        if (null != count) {
            return count.intValue();
        }
        return 0;
    }

    public Integer memorySum(Long vendorId, Long tenantId, Long projectId) {
        String sql = "select sum(memory) from cloud_server where is_deleted = 0 and memory 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);
        }
        if (null != projectId && 0L != projectId) {
            sql += " and project_id = :projectId ";
            paramMap.put("projectId", projectId);
        }
        Long count = this.countQuery(sql, paramMap);
        if (null != count) {
            return count.intValue();
        }
        return 0;
    }

    public Integer diskSum(Long vendorId, Long tenantId) {
        String sql = "select sum(disk) from cloud_server where is_deleted = 0 and disk 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 Integer count(Long vendorId, Long tenantId) {
        String sql = "select count(1) from cloud_server where is_deleted = 0 ";
        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 List<CloudServer> listTemplate(Long vendorId, Long vdcId) {
        String sql =
            "select a.* from cloud_server a where a.is_deleted = 0 and a.vendor_id = :vendorId and a.is_template = 1";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        if (null != vdcId && 0L != vdcId) {
            sql += " and a.vdc_id = :vdcId";
            params.put("vdcId", vdcId);
        }
        return this.list(CloudServer.class, sql, params);
    }

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

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

    public boolean removeByInstanceId(String instanceId, Long serverId, Long userId) {
        String sql = "update cloud_server set is_deleted = true,gmt_modify = :gmtModify where is_deleted = 0"
            + " and instance_id = :instanceId and host_id = :serverId";
        Map<String, Object> params = MapTools.simpleMap("instanceId", instanceId);
        params.put("serverId", serverId);
        params.put("gmtModify", new Date());
        return this.execute(sql, params) > 0;
    }

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

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

    public List<CloudServer> list(int page, int rows, List<Param> params, Map<String, String> sorter) {
        String sql =
            "select a.*,t.`name` tenant_name, b.type vendor_type,b.name vendor_name, p.name project_name from cloud_server a "
                + " left join tenant t on a.tenant_id = t.id " + " left join cloud_vendor b on a.vendor_id = b.id "
                + " left join project p on a.project_id = p.id " + " where a.is_deleted = 0 and a.is_template = 0 ";
        sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "a");
        return this.list(CloudServer.class, sql, null);
    }

    public int count(List<Param> params) {
        String sql = " select count(1) from cloud_server a where a.is_deleted = 0 and a.is_template = 0 ";
        sql = QueryBuilder.buildRaw(sql, params, null, "a");
        return this.countQuery(sql, null).intValue();
    }

    public List<CloudServer> listByKeypair(Long keypairId) throws Exception {
        String sql =
            " select * from cloud_server s , server_keypair k where  s.id = k.server_id and k.keypair_id = :keypairId ";
        Map<String, Object> params = MapTools.simpleMap("keypairId", keypairId);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listByNetworkId(long networkId) {
        String sql = "select a.*, c.name as host_server_name " + "from cloud_server a "
            + "join port b on a.instance_id = b.device_uuid " + "join server c on a.host_id = c.id "
            + "where a.is_deleted = 0 and b.network_id = :networkId ";
        Map<String, Object> params = MapTools.simpleMap("networkId", networkId);
        return this.list(CloudServer.class, sql, params);
    }

    public boolean removeByUuid(String uuid, long userId) {
        String sql = "update cloud_server set is_deleted = true,gmt_modify = :gmtModify "
            + "where is_deleted = 0 and uuid = :uuid ";
        Map<String, Object> params = MapTools.simpleMap("uuid", uuid);
        params.put("gmtModify", new Date());
        return this.execute(sql, params) > 0;
    }

    public CloudServer queryByUuid(String uuid) {
        String sql = "select * from cloud_server a where is_deleted = 0 and uuid = :uuid ";
        Map<String, Object> params = MapTools.simpleMap("uuid", uuid);
        List<CloudServer> list = this.list(CloudServer.class, sql, params);
        if (!ListTool.isEmpty(list)) {
            return list.get(0);
        }
        return null;
    }

    public List<CloudServer> queryByEnv(Long env, Long vendorId) {
        String sql = "select * from cloud_server a where is_deleted = 0 and a.vendor_id = :vendorId and a.env = :env ";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("env", env);
        List<CloudServer> list = this.list(CloudServer.class, sql, params);
        if (!ListTool.isEmpty(list)) {
            return list;
        }
        return null;
    }

    public boolean removeByEnv(Long envId, Long vendorId, Long userId) {
        String sql =
            "update cloud_server set is_deleted = true,gmt_modify = :gmtModify where is_deleted = 0 and vendor_id = :vendorId and env = :envId ";
        Map<String, Object> params = MapTools.simpleMap("envId", envId);
        params.put("vendorId", vendorId);
        params.put("gmtModify", new Date());
        return this.execute(sql, params) > 0;
    }

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

    public List<CloudServer> listByInstanceId(List<String> instanceIds) {
        String sql = "select * from cloud_server a where is_deleted = 0 and a.instance_id in (:instanceIds)";
        Map<String, Object> params = MapTools.simpleMap("instanceIds", instanceIds);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> summary(Date start, Date end, Long hostId) {
        String sql =
            "select * from cloud_server where is_deleted = 0 and gmt_create >= :start and gmt_create <= :end and host_id = :hostId";
        Map<String, Object> params = MapTools.simpleMap("start", start);
        params.put("end", end);
        params.put("hostId", hostId);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listServerByVolumeId(long volumeId) {
        String sql =
            "select a.*, c.name host_server_name from cloud_server a " + "join server_volume b on a.id = b.server_id "
                + "join server c on a.host_id = c.id " + "where b.volume_id = :volumeId";
        Map<String, Object> params = MapTools.simpleMap("volumeId", volumeId);
        return this.list(CloudServer.class, sql, params);
    }

    public Integer countByClusterId(Long clusterId, Boolean template) {
        String sql =
            "select count(a.id) from cloud_server a left join server b on b.id = a.host_id where b.cluster_id = :clusterId and a.is_deleted = 0 and a.is_template = :template";
        Map<String, Object> paramMap = MapTools.simpleMap("clusterId", clusterId);
        paramMap.put("template", template);
        return this.countQuery(sql, paramMap).intValue();
    }

    public List<CloudServer> listByHostIds(List<Long> hostIds) {
        String sql =
            "select * from cloud_server a where is_deleted = 0 and a.is_template = 0 and a.host_id in (:hostIds)";
        Map<String, Object> params = MapTools.simpleMap("hostIds", hostIds);
        return this.list(CloudServer.class, sql, params);
    }

    public boolean tenantCheck(Long tenantId, Long projectId, Long creatorId) throws Exception {
        String sql = "select count(1) from cloud_server 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 removeByGroupName(Long vendorId, Long userId, String resourceGroupName) {
        String sql =
            "update cloud_server set is_deleted = true,gmt_modify = :gmtModify where is_deleted = 0 and vendor_id = :vendorId and azure_resource_group_name = :resourceGroupName ";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("resourceGroupName", resourceGroupName);
        params.put("gmtModify", new Date());
        return this.execute(sql, params) > 0;
    }

    public List<CloudServer> listByVaultsUuid(String vaultsUuid, Long vendorId, String regionId) {
        String sql =
            " select a.* from cloud_server 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(CloudServer.class, sql, params);
    }

    public List<CloudServer> listBackupResources(Long vendorId, String regionId) {
        String sql =
            " select a.* from cloud_server 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(CloudServer.class, sql, params);
    }

    public List<CloudServer> listVmsByTenants(List<Long> tenantIds, Boolean isAll, List<Long> projectIds) {
        String sql =
            "select a.*,t.name tenant_name ,p.`name` project_name,b.name business_name from cloud_server a left join tenant t on a.tenant_id = t.id "
                + " left join project p on a.project_id = p.id left join business b on a.business_id = b.id  where a.is_template = 0 ";
        Map<String, Object> params = new HashMap<String, Object>(8);
        if (!ListTool.isEmpty(tenantIds)) {
            sql += " and a.tenant_id in (:tenantIds) ";
            params.put("tenantIds", tenantIds);
        }
        if (!ListTool.isEmpty(projectIds)) {
            sql += " and a.project_id in (:projectIds) ";
            params.put("projectIds", projectIds);
        }
        if (null != isAll && !isAll) {
            sql += " and a.is_deleted = 0 ";
        }
        return this.list(CloudServer.class, sql, params);
    }

    public CloudServer checkCloudServerName(String ip) {
        String sql =
            "select a.* from cloud_server a left join cloud_vendor b on a.vendor_id=b.id where a.is_deleted = 0 and a.is_template = 0  and b.type='VMWARE' and a.name like '%"
                + ip + "'";
        List<CloudServer> list = this.list(CloudServer.class, sql, null);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public boolean removeTemplateByVid(Long vendorId, Long userId) {
        String sql =
            "update cloud_server set is_deleted = true,gmt_modify = :gmtModify where is_deleted = 0 and vendor_id = :vendorId and is_template = 1 ";
        Map<String, Object> params = MapTools.simpleMap("vendorId", vendorId);
        params.put("gmtModify", new Date());
        return this.execute(sql, params) > 0;
    }

    public CloudServer queryByIp(String privateIp, Long vendorId, String regionId) {
        String sql =
            "select a.* from cloud_server a where a.vendor_id = :vendorId and a.region_id = :regionId and a.is_deleted = 0 and a.private_ips like :privateIp";
        Map<String, Object> params = MapTools.simpleMap("vendorId", vendorId);
        params.put("regionId", regionId);
        params.put("privateIp", "%\"" + privateIp + "\"%");
        List<CloudServer> list = this.list(CloudServer.class, sql, params);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public List<CloudServer> list(String vpcUuid, Long vendorId) {
        String sql = "select a.* from cloud_server a LEFT JOIN elastic_ip b on a.instance_id = b.instance_id "
            + " where a.is_deleted=0  and a.vendor_id = :vendorId  "
            + "  and vpc_uuid = :vpcUuid  and   b.instance_id is null ";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("vpcUuid", vpcUuid);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listAvailableVm(Long vendorId, String regionId) {
        String sql = "select a.* from cloud_server a LEFT JOIN elastic_ip b on a.instance_id=b.instance_id "
            + " where a.is_deleted=0 and a.status in ('RUNNING','STOPPED') and a.vendor_id = :vendorId and a.region_id = :regionId and b.instance_id is null ";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("regionId", regionId);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listAvailableVm(Long vendorId, String regionId, Long userId, Long tenantId,
        List<Long> projectIds) {
        String subquerySql = "select a.* from cloud_server a LEFT JOIN elastic_ip b on a.instance_id=b.instance_id "
            + " where a.is_deleted=0 and a.status in ('RUNNING','STOPPED') and a.vendor_id = :vendorId and a.region_id = :regionId and b.instance_id is null ";
        Map<String, Object> paramMap = MapTools.simpleMap(Common.VENDORID, vendorId);
        paramMap.put("regionId", regionId);
        String sql = "select distinct 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 += " )";
        return this.list(CloudServer.class, sql, paramMap);
    }

    public CloudServer get(Long vendorId, String instanceId) {
        String sql = "select a.* , rg.name resource_group_name from cloud_server a "
            + " LEFT JOIN resource_group rg ON a.resource_group_id = rg.id "
            + " where a.is_deleted = 0 and a.vendor_id = :vendorId and a.instance_id = :instanceId";
        Map<String, Object> params = MapTools.simpleMap("instanceId", instanceId);
        params.put("vendorId", vendorId);
        List<CloudServer> list = this.list(CloudServer.class, sql, params);
        return list.isEmpty() ? null : list.get(0);
    }

    public List<CloudServer> listByTenantId(Long tenantId) {
        String sql =
            "select a.*,t.name tenant_name from cloud_server a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.tenant_id = :tenantId and (a.is_template = 0 or a.is_template is null)";
        Map<String, Object> params = MapTools.simpleMap(Common.TENANTID, tenantId);
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listByTenants() {
        String sql =
            "SELECT a.*, t.NAME tenant_name FROM cloud_server a LEFT JOIN tenant t ON a.tenant_id = t.id WHERE  a.is_deleted = 0    AND a.tenant_id != 0 and a.tenant_id is not null    AND (   a.is_template = 0 OR a.is_template IS NULL)";
        Map<String, Object> params = new HashMap<>();
        return this.list(CloudServer.class, sql, params);
    }

    public List<CloudServer> listByResourceGroupUuid(Long vendorId, String regionId, String resourceGroupUuid) {
        String sql =
            "select a.* from cloud_server a  where a.is_deleted = 0 and a.vendor_id = :vendorId and a.is_template = 0 and a.region_id = :regionId  and a.resource_group_uuid = :resourceGroupUuid ";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("regionId", regionId);
        params.put("resourceGroupUuid", resourceGroupUuid);
        return this.list(CloudServer.class, sql, params);
    }

    public boolean removeByGroupId(Long vendorId, Long userId, Long resourceGroupId) throws BoCloudDBException {
        String sql =
            "update cloud_server set is_deleted = 1, gmt_modify = :gmtModify 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());
        return this.execute(sql, params) > 0;
    }

    public List<CloudServer> listHicUnBindEip(Long vendorId, String regionId, List<Long> ids) {
		String sql = "select a.* from cloud_server a where a.is_deleted=0 and a.vendor_id = :vendorId and a.region_id = :regionId and a.instance_id not in "
				+ " (select p.device_uuid from elastic_ip i ,port p where  p.is_deleted=0  and i.is_deleted=0 and p.vendor_id=i.vendor_id and p.region_id=i.region_id "
				+ " and p.port_uuid = i.instance_id and p.device_owner like 'compute%'"
				+ " and i.vendor_id = :vendorId  and i.region_id = :regionId )";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		params.put("regionId", regionId);
		if (!ListTool.isEmpty(ids)) {
			sql += " and a.id in (:ids) ";
			params.put("ids", ids);
		}
		return this.list(CloudServer.class, sql, params);
	}


    /**
     * 云平台下虚拟机信息（个数、cpu、men、disk）统计
     *
     * @param vendorId
     * @return
     */
    public List<Map<String, Object>> selectAllByVendorId(Long vendorId) {
        String sql =
            "select count(*) as host,SUM(cpu) as cpu ,SUM(memory) as mem ,SUM(disk) as disk from cloud_server where is_deleted = 0 and is_template = 0";
        Map<String, Object> paramMap = Maps.newHashMap();
        if (null != vendorId && 0L != vendorId) {
            sql += " and vendor_id = " + vendorId;
        }
        return this.list(sql);
    }
}
