package cn.sagacloud.server.algorithm.backstage.sync

import cn.sagacloud.server.algorithm.backstage.model.datacenter.DCFloor
import cn.sagacloud.server.algorithm.backstage.model.datacenter.DCISpace
import cn.sagacloud.server.algorithm.services.datacenter.DataCenterService
import cn.sagacloud.server.algorithm.models.entities.Space
import cn.sagacloud.server.algorithm.models.jsonAnalyzer.Point
import cn.sagacloud.server.algorithm.models.modelFile.FloorModel
import cn.sagacloud.server.algorithm.services.BaseDataService
import cn.sagacloud.server.algorithm.services.CommonService
import com.sybotan.database.SFilter
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Scope
import org.springframework.stereotype.Component

/**
 * 同步元空间
 *
 * @author jxing
 */
@Suppress("UNCHECKED_CAST")
@Component
@Scope("prototype")
class SyncISpace : SyncObject {

    var modelId: String? = null
    var floor: FloorModel? = null
    var dcFloors : ArrayList<DCFloor>? = null
    var bimIdPrefix : String? = null
    val bimMap = HashMap<String, Space>() // <BIMID, Space>
    val dataService = BaseDataService
    val ctmWDRoomFuncId = "ctm-WDRoomFuncID"     //万达空间类型编码
    val ctmWDRoomFuncName = "ctm-WDRoomFuncName"     //万达空间类型名称

    @Autowired
    lateinit var dataCenterService: DataCenterService

    override fun init(modelId: String, obj: FloorModel, dcFloors: ArrayList<DCFloor>, bimIdPrefix: String): SyncObject {
        this.modelId = modelId
        this.floor = obj
        this.dcFloors = dcFloors
        this.bimIdPrefix = bimIdPrefix
        return this
    }

    // 模型内设备
    var modelArr = ArrayList<Space>()
    // 数据中心设备
    var dataCenter = HashMap<String, DCISpace>()

    var createList = ArrayList<DCISpace>()

    var deleteList = ArrayList<DCISpace>()

    var updateList = ArrayList<DCISpace>()

    override fun prepareModelData() : SyncObject{
        modelArr = dataService.spaceService.select(SFilter.eq("modelId", modelId!!)).exec()
        return this
    }

    override fun prepareDataCenterData(): SyncObject {
        if(floor == null || floor!!.projectId == null)
            return this
        val result = dataCenterService.getISpaceByBIMIDPrefix(bimIdPrefix!!, floor!!.projectId!!)
        if(result == null)
            throw Exception("从数据中心获取元空间失败!")
        if(result.isNotEmpty()) {
            dataCenter = result
        }
        return this
    }

    override fun buildBIMIDMap(): SyncObject {
        val sb = StringBuilder()
        modelArr.forEach {
            if(it.sourceId != null) {
                sb.clear()
                sb.append(bimIdPrefix).append(it.sourceId)
                bimMap[sb.toString()] = it
            }
        }
        return this
    }

    override fun matchClassify(): SyncObject {
        val sb = StringBuilder()
        dataCenter.forEach { (_, dcSpace) ->
            if(dcSpace.bimId != null && bimMap.contains(dcSpace.bimId!!)){
                val space = bimMap[dcSpace.bimId!!]
                // 交集, 更新
                bimMap.remove(dcSpace.bimId!!)
                // 绑定数据
                val point = space?.location?.points?.get(0)
                addBimLocationAndFloorId(point, space!!, dcSpace, sb)
                dcSpace.height = space.height
                dcSpace.localName = space.localName
                dcSpace.outline = space.outline
                dcSpace.outerOutline = space.outerOutline
                dcSpace.modelId = space.modelId
                if(dcSpace.customParam == null)
                    dcSpace.customParam = HashMap()
                dcSpace.customParam!![ctmWDRoomFuncId] = space.wDRoomFuncID
                dcSpace.customParam!![ctmWDRoomFuncName] = space.wDRoomFuncName
                updateList.add(dcSpace)
            }else{
                // 需要被删除的
                deleteList.add(dcSpace)
            }
        }
        // 在map里的就是需要创建的
        bimMap.forEach {
            val dcISpace = DCISpace()
            dcISpace.localName = it.value.localName
            dcISpace.outline = it.value.outline
            dcISpace.outerOutline = it.value.outerOutline
            dcISpace.bimId = it.key
            dcISpace.height = it.value.height
//            dcISpace.floorId = dcFloor!!.id
            dcISpace.modelId = it.value.modelId
            if(dcISpace.customParam == null)
                dcISpace.customParam = HashMap()
            dcISpace.customParam!![ctmWDRoomFuncId] = it.value.wDRoomFuncID
            dcISpace.customParam!![ctmWDRoomFuncName] = it.value.wDRoomFuncName
            val point = it.value.location?.points?.get(0)
            addBimLocationAndFloorId(point, it.value, dcISpace, sb)
            createList.add(dcISpace)
        }
        return this
    }

    private fun addBimLocationAndFloorId(point: Point?, space : Space, dcISpace: DCISpace, sb: StringBuilder) {
        if (point != null) {
            if (dcFloors!!.isNotEmpty()) {
                var defaultDCFloor: DCFloor? = null
                // 找到一个没有划分过的楼层作为默认所属楼层(没有outline)
                for (dcFloor in dcFloors!!){
                    if(dcFloor.outline == null) {
                        defaultDCFloor = dcFloor
                        break
                    }
                }
                for (dcFloor in dcFloors!!) {
                    if (dcFloor.outline != null && !space.outline!!.isNullOrEmpty()) {
                        // 如果数据中心的楼层设置了outline, 则只有跟outline重叠过的元空间才能添加楼层关系
                        if (CommonService.isPolygonOverlap(space.outline!![0], dcFloor.outline!!)) {
                            dcISpace.floorId = dcFloor.id
                            dcISpace.buildingId = dcFloor.buildId
                            break
                        }
                    }
                }
                // 如果没找到所属楼层, 则使用默认楼层作为所属楼层
                if(dcISpace.floorId == null && defaultDCFloor != null){
                    dcISpace.floorId = defaultDCFloor.id
                    dcISpace.buildingId = defaultDCFloor.buildId
                }
            }
            sb.clear()
            sb.append(point.x).append(",").append(point.y).append(",").append(point.z)
            dcISpace.bimLocation = sb.toString()
        }
    }

    override fun syncCreate(): SyncObject {
        if(createList.isNotEmpty()) {
            dealWithHeight(createList)
            dataCenterService.sync(createList as ArrayList<Any>, null, floor!!.projectId!!, DataCenterService.DataCenterOperator.iSpaceCreate)
        }
        return this
    }

    fun dealWithHeight(createList: ArrayList<DCISpace>){
        createList.forEach {
            if(it.height != null)
                it.height = it.height!! / 1000
        }
    }

    override fun syncDelete(): SyncObject {
        if(deleteList.isNotEmpty())
            dataCenterService.sync(deleteList as ArrayList<Any>, null, floor!!.projectId!!, DataCenterService.DataCenterOperator.iSpaceDelete)
        return this
    }

    override fun syncUpdate(): SyncObject {
        if(updateList.isNotEmpty()) {
//            updateList.forEach {
//                it.cadId = null
//                it.localName = null
//            }
            dealWithHeight(updateList)
            dataCenterService.sync(updateList as ArrayList<Any>, null, floor!!.projectId!!, DataCenterService.DataCenterOperator.iSpaceUpdate)
        }
        return this
    }
}