package cn.sagacloud.server.algorithm.common.utils

import cn.sagacloud.server.algorithm.models.dataCheck.LevelCheckResult
import cn.sagacloud.server.algorithm.models.modelFile.FloorModelView
import org.apache.commons.collections4.CollectionUtils
import org.apache.commons.lang3.StringUtils
import org.springframework.beans.BeanUtils
import java.util.*

/**
 * 楼层号检查
 * 基于python代码改写:relations.src.level.check_level
 * @author Administrator
 * @date 2021-10-21
 */
object FloorLevelCheckUtil {
    /**
     * 检查
     * @param views
     * @return
     */
    fun checkLevel(views: List<FloorModelView?>): List<LevelCheckResult>? {
        if (CollectionUtils.isEmpty(views)) {
            return null
        }
        // 排序
        val viewArr: Array<FloorModelView?> = views.toTypedArray()
        Arrays.sort(viewArr, FloorModelCompare())
        val errorIds: MutableSet<String?> = HashSet()
        var lastView: FloorModelView? = null
        // 检查有楼层号异常的楼层
        for (view in viewArr) {
            val level = view!!.baseLevel
            if (level != null && (lastView == null || level > lastView.baseLevel!!)) {
                lastView = view
                continue
            }
            // 将前后的模型ID放入异常队列
            errorIds.add(lastView!!.currentModelId)
            errorIds.add(view.currentModelId)
            lastView = null
        }
        // 回写结果，按原顺序
        val result: MutableList<LevelCheckResult> = ArrayList()
        for (view in views) {
            val rs = LevelCheckResult()
            BeanUtils.copyProperties(view, rs)
            rs.hasError = errorIds.contains(view!!.currentModelId)
            rs.errorMsg = if (rs.hasError!!) "标高冲突" else null
            result.add(rs)
        }
        return result
    }

    /**
     * 楼层比较器
     */
    class FloorModelCompare : Comparator<FloorModelView?> {
        override fun compare(v1: FloorModelView?, v2: FloorModelView?): Int {
            if (v1 == null || v2 == null) {
                return if (v1 == null) 1 else -1
            }
            val o1 = convertToFloorLevel(v1.floorName)
            val o2 = convertToFloorLevel(v2.floorName)
            // 如果楼层类型不一样
            if (o1.type != o2.type) {
                return o1.type - o2.type
            }
            // 楼层类型一样，则看层数
            if (o1.level != o2.level) {
                // 层号越大的越高，但地下则刚好相反
                val result = o1.level - o2.level
                return if (o1.type == 0) -result else result
            }
            // 都一样则看夹层号，夹层号越大越高
            return if (o1.middle != o2.middle) {
                o1.middle - o2.middle
            } else 0
        }

        /**
         * 根据楼层名称转换楼层信息
         * @param floorName
         * @return
         */
        protected fun convertToFloorLevel(floorName: String?): FloorLevel {
            val floor = FloorLevel()
            if (StringUtils.isBlank(floorName)) {
                return floor
            }
            // 顶层夹层
            if (floorName!!.startsWith("RFM")) {
                floor.type = 2
                if (floorName.length > 3) {
                    floor.middle = Integer.valueOf(floorName.substring(3))
                }
                return floor
            }
            // 顶层
            if (floorName.startsWith("RF")) {
                floor.type = 2
                return floor
            }
            // 正常楼层/地下
            if (floorName.startsWith("F") || floorName.startsWith("B")) {
                floor.type = if (floorName.startsWith("F")) 1 else 0
                // 是否有夹层
                val mIndex = floorName.indexOf("M")
                if (mIndex < 0) {
                    floor.level = Integer.valueOf(floorName.substring(1))
                } else if (floorName.endsWith("M")) {
                    // 没夹层数也算没夹层
                    floor.level = Integer.valueOf(floorName.substring(1, mIndex))
                } else {
                    floor.level = Integer.valueOf(floorName.substring(1, mIndex))
                    floor.middle = Integer.valueOf(floorName.substring(mIndex + 1))
                }
                return floor
            }
            return floor
        }
    }

    /**
     * 楼层信息
     */
    class FloorLevel {
        /** 楼层类型：0-地下，1-正常，2-顶层  */
        var type = 1

        /** 楼层号  */
        var level = 1

        /** 夹层号  */
        var middle = 0
    }
}