package com.persagy.server.services.relation_calc

import com.persagy.server.datacenter.models.entities.graphtype.block.ConnectedBlock
import com.persagy.server.datacenter.models.entities.graphtype.block.ConnectedBlockSource
import com.persagy.server.datacenter.models.entities.graphtype.block.EquipIdUUIDMap
import com.persagy.server.datacenter.models.entities.graphtype.block.MepSourceTypeEntity
import com.persagy.server.datacenter.models.entities.objects.Equipment
import com.persagy.server.datacenter.models.entities.rel.REq2Eq
import com.persagy.server.datacenter.models.entities.task.SpaceType
import com.persagy.server.mappers.MepSystemMapper

import com.persagy.database.SFilter
import com.persagy.database.SOrder
import com.persagy.mybatis.SMybatisDao
import com.persagy.service.SObjectService
import com.persagy.service.models.enums.SResponseType
import com.persagy.service.models.requests.SCreateRequest
import com.persagy.service.models.responses.SQueryResponse
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service

@Service
class MepSystemCalcService {

    val mepSourceTypeService = SObjectService(SMybatisDao(MepSourceTypeEntity::class.java))
    val connectedBlockSourceService = SObjectService(SMybatisDao(ConnectedBlockSource::class.java))
    val connectedBlockService = SObjectService(SMybatisDao(ConnectedBlock::class.java))
    val equipmentService = SObjectService(SMybatisDao(Equipment::class.java))
    val rEq2EqService = SObjectService(SMybatisDao(REq2Eq::class.java))
    @Autowired
    lateinit var mepSystemMapper : MepSystemMapper


    /**
     * 本函数为计算管网流向前指定源设备的操作, 前提是要在revit_calc.mep_source_type表中指定过设备类型(revit.equipment表的family列)
     * 将revit_calc.mep_source_type表里的源设备类型  匹配revit_calc.connected_block表的对应设备, 填入revit_calc.connected_block_source表作为源设备对象使用
     *
     * @param  projectId            项目id
     * @param  calcName             关系卡片名
     * @param  buildingId           建筑id
     * @param  mepSystemTypeList    机电管网系统类型
     *
     */
    fun setSourceType(projectId : String, calcName : String, buildingId : String?, mepSystemTypeList : ArrayList<String>) : Boolean{
        val sources = mepSourceTypeService.select(SFilter.and(SFilter.eq("projectId", projectId), SFilter.eq("calcName", calcName))).exec()
        if (sources.isNullOrEmpty()){
            // 没有指定源设备类型, 直接删除项目下所有源设备类型
            deletePrevSource(projectId, buildingId, mepSystemTypeList)
        }else{
            val typeSet = HashSet<String>()
            sources.forEach {
                if(it.sourceType != null && it.sourceType!!.length == 4)
                    typeSet.add(it.sourceType!!)
            }
            val equipments = equipmentService.select(SFilter.and(SFilter.not(SFilter.isNull("bimId")), SFilter.eq("projectId", projectId), SFilter.inList("category", typeSet.toList()))).exec()
            val bimIdSet = HashSet<String>()
            equipments.forEach {
                if(it.bimId != null && it.bimId!!.length > 10)
                    bimIdSet.add(it.bimId!!)
            }
            val sourceEquipments = mepSystemMapper.getEquipByBimId(projectId, buildingId, mepSystemTypeList, ArrayList(bimIdSet))
            deletePrevSource(projectId, buildingId, mepSystemTypeList)
            if(!sourceEquipments.isNullOrEmpty()){
                sourceEquipments.forEach {
                    it.isSource = true
                }
                val sCreateRequest = SCreateRequest<ConnectedBlockSource>()
                sCreateRequest.content = sourceEquipments
                val response = connectedBlockSourceService.createList(sCreateRequest)
                return response.result == SResponseType.success
            }
        }
        return true
    }


    /**
     * 本函数将revit_calc.connected_block_source表中计算出的有方向性的关系(计算完流向之后的关系)  转换为relationship.r_eq2eq表中的数据, 每次转换会删除以前自动计算的数据
     *
     * @param  projectId            项目id
     * @param  relType              关系类型
     * @param  buildingId           建筑id
     * @param  mepSystemTypeList    机电管网系统类型
     *
     */
    fun generateRelation(projectId : String, relType : String, buildingId : String?, mepSystemTypeList : ArrayList<String>) : ArrayList<REq2Eq>{
        // 1. 获取所有已经计算出流向的数据
        var originData : ArrayList<ConnectedBlock>? = null
        if(buildingId == null) {
            originData = connectedBlockService.select(SFilter.eq("projectId", projectId), SFilter.inList("mepSystemType", mepSystemTypeList),
                    SFilter.gte("direction", -3), SFilter.isNull("buildingId")).order(SOrder("mepSystemType"), SOrder("blockId")).exec()
        } else
            originData = connectedBlockService.select(SFilter.eq("projectId", projectId), SFilter.eq("buildingId", projectId),
                    SFilter.inList("mepSystemType", mepSystemTypeList), SFilter.gte("direction", -3))
                    .order(SOrder("mepSystemType"), SOrder("blockId")).exec()
        // 2. 加入到MepSystemTransformer对象里组织, 并trim掉设备部件以外的对象
        if(originData.isNullOrEmpty()){
            return ArrayList<REq2Eq>()
        }
        val mepSystemTransformer = MepSystemTransformer()
        originData.forEach {
            if(it.direction == 1){
                mepSystemTransformer.insertRelData(it.id1!!, it.type1!!, it.id2!!, it.type2!!)
            }else if(it.direction == -1){
                mepSystemTransformer.insertRelData(it.id2!!, it.type2!!, it.id1!!, it.type1!!)
            }else if(it.direction == 0){
                mepSystemTransformer.insertRelData(it.id1!!, it.type1!!, it.id2!!, it.type2!!)
                mepSystemTransformer.insertRelData(it.id2!!, it.type2!!, it.id1!!, it.type1!!)
            }
        }
        mepSystemTransformer.trim()
        val eq2EqRelation = mepSystemTransformer.getEq2EqRelation()
        val involvedEquip = mepSystemTransformer.getInvolvedEquip(eq2EqRelation, true)
        val involvedEquipPart = mepSystemTransformer.getInvolvedEquip(eq2EqRelation, false)
        // 3. 获取设备id与设备uuid之间的映射关系
        var dcEquipModelEquipMap : ArrayList<EquipIdUUIDMap>? = null
        if(!involvedEquip.isNullOrEmpty()) {
            dcEquipModelEquipMap = mepSystemMapper.getDCEquipModelEquipMap(projectId, involvedEquip)
        }
        if(!involvedEquipPart.isNullOrEmpty()) {
            if(dcEquipModelEquipMap == null)
                dcEquipModelEquipMap = ArrayList()
            dcEquipModelEquipMap.addAll(mepSystemMapper.getDCEquipModelEquipMap(projectId, involvedEquipPart))
        }
        if(dcEquipModelEquipMap.isNullOrEmpty())
            return ArrayList()
        val eq2eqRel = mepSystemTransformer.transformEquipRel(projectId, relType, eq2EqRelation, dcEquipModelEquipMap, true)
        return eq2eqRel
    }


    /**
     * 本函数将revit_calc.connected_block_source表中计算出的没有方向性的关系(计算完流向之后的关系)  转换为relationship.r_eq2eq表中的数据, 每次转换会删除以前自动计算的数据
     *
     * @param  projectId            项目id
     * @param  relType              关系类型
     * @param  buildingId           建筑id
     * @param  mepSystemTypeList    机电管网系统类型
     *
     */
    fun generateNonDirectionalRelation(projectId : String, relType : String, buildingId : String?, mepSystemTypeList : ArrayList<String>) : ArrayList<REq2Eq>{
        // 1. 获取所有已经计算出流向的数据
        var originData : ArrayList<ConnectedBlock>? = null
        if(buildingId == null) {
            originData = connectedBlockService.select(SFilter.eq("projectId", projectId), SFilter.inList("mepSystemType", mepSystemTypeList),
                    SFilter.isNull("direction"), SFilter.isNull("buildingId")).order(SOrder("mepSystemType"), SOrder("blockId")).exec()
        } else
            originData = connectedBlockService.select(SFilter.eq("projectId", projectId), SFilter.eq("buildingId", projectId),
                    SFilter.inList("mepSystemType", mepSystemTypeList), SFilter.isNull("direction"))
                    .order(SOrder("mepSystemType"), SOrder("blockId")).exec()
        // 2. 加入到MepSystemTransformer对象里组织, 并trim掉设备部件以外的对象
        if(originData.isNullOrEmpty()){
            return ArrayList<REq2Eq>()
        }
        val mepSystemTransformer = MepSystemTransformer()
        originData.forEach {
            if(it.direction == 1){
                mepSystemTransformer.insertRelData(it.id1!!, it.type1!!, it.id2!!, it.type2!!)
            }else if(it.direction == -1){
                mepSystemTransformer.insertRelData(it.id2!!, it.type2!!, it.id1!!, it.type1!!)
            }else if(it.direction == 0){
                mepSystemTransformer.insertRelData(it.id1!!, it.type1!!, it.id2!!, it.type2!!)
                mepSystemTransformer.insertRelData(it.id2!!, it.type2!!, it.id1!!, it.type1!!)
            }
        }
        mepSystemTransformer.trim()
        val eq2EqRelation = mepSystemTransformer.getEq2EqNonDirectionalRelation()
        val involvedEquip = mepSystemTransformer.getInvolvedEquip(eq2EqRelation, true)
        val involvedEquipPart = mepSystemTransformer.getInvolvedEquip(eq2EqRelation, false)
        // 3. 获取设备id与设备uuid之间的映射关系
        var dcEquipModelEquipMap : ArrayList<EquipIdUUIDMap>? = null
        if(!involvedEquip.isNullOrEmpty()) {
            dcEquipModelEquipMap = mepSystemMapper.getDCEquipModelEquipMap(projectId, involvedEquip)
        }
        if(!involvedEquipPart.isNullOrEmpty()) {
            if(dcEquipModelEquipMap == null)
                dcEquipModelEquipMap = ArrayList()
            dcEquipModelEquipMap.addAll(mepSystemMapper.getDCEquipModelEquipMap(projectId, involvedEquipPart))
        }
        if(dcEquipModelEquipMap.isNullOrEmpty())
            return ArrayList()
        val eq2eqRel = mepSystemTransformer.transformEquipRel(projectId, relType, eq2EqRelation, dcEquipModelEquipMap, false)
        return eq2eqRel
    } // Fun


    /**
     * 删除以前的源设备数据
     */
    private fun deletePrevSource(projectId : String, buildingId : String?, mepSystemTypeList : ArrayList<String>){
        if(buildingId == null)
            connectedBlockSourceService.delete(SFilter.and(SFilter.eq("projectId", projectId), SFilter.inList("mepSystemType", mepSystemTypeList)))
        else
            connectedBlockSourceService.delete(SFilter.and(SFilter.eq("projectId", projectId), SFilter.inList("mepSystemType", mepSystemTypeList), SFilter.eq("buildingId", buildingId)))
    } // Fun

    /**
     * 处理空间类型
     */
    fun spaceTypes(projectId: String): SQueryResponse<SpaceType>{
        val sQueryResponse = SQueryResponse<SpaceType>()
        try {
            val objectType = mepSystemMapper.getObjectType(projectId)
            sQueryResponse.result = SResponseType.success
            sQueryResponse.content = objectType
            return sQueryResponse
        } catch (e: Exception) {
            e.printStackTrace()
            sQueryResponse.result = SResponseType.failure
            return sQueryResponse
        }
    } // Fun


} // Class