import { wallService } from '../Service/WallService'
import { floorplanService } from '../Service/FloorplanService'
import Constant from '../Constant'
import { mathUtil } from '../MathUtil'
import { elementService } from '../Service/ElementService'
import { coordinate } from '../Coordinate'

export default class MoveWall {
    constructor() {
        this.needUpdateRoom = false //是否重新计算房间
        this.startMoving = false
        this.moveFlag = false

        //拖拽墙角的时候，墙角的父亲与其他墙角相交
        this.adsorbPointWalls = {}

        //拖拽墙角的时候，该墙角与其他墙面相交
        this.splitWallId = null
    }

    // 测试要考虑pointId拖拽到包含他的所有墙的另一头
    // 这个函数不会删除/拆分/合并墙或者点
    movePoint(pointId, position, modifyPoint) {
        let point = floorplanService.getPoint(pointId)
        let linkedPointId = null
        let linkedWallId = null

        if (modifyPoint != null) {
            position = {
                x: modifyPoint.x,
                y: modifyPoint.y,
            }
            linkedPointId = modifyPoint.linkedPointId
            linkedWallId = modifyPoint.linkedWallId
        }
        this.needUpdateRoom = false
        this.adsorbPointWalls = {}
        this.splitWallId = null
        let flag = this.canMoveForPoint(pointId, position, linkedPointId, linkedWallId)

        if (!flag) {
            if (this.splitWallId == null && Object.keys(this.adsorbPointWalls).length > 0) {
                //要吸附一下
                const parent = point.parent
                const wall = floorplanService.getWall(Object.keys(parent)[0])
                const otherPointId = wall.getOtherPointId(pointId)
                let otherPoint = floorplanService.getPoint(otherPointId)
                let modifyPoint = floorplanService.getPoint(Object.keys(this.adsorbPointWalls)[0])
                let line = mathUtil.createLine1(otherPoint, modifyPoint)
                position = mathUtil.getJoinLinePoint(position, line)
                point.setPosition(position)
            }
            return false
        }

        let newPosition = null
        if (modifyPoint == null) {
            //90°或者180°纠正
            //不考虑当前角度

            //当前点的parent只有一个，考虑邻居点
            let neighPoints = wallService.getNeighPoints(pointId)
            if (neighPoints.length == 1) {
                newPosition = elementService.checkAngle(position, neighPoints[0].vectorId, pointId)
            }
            //当前点的parent有两个
            else if (neighPoints.length == 2) {
                newPosition = elementService.checkAngle(position, neighPoints[0].vectorId, pointId)
                if (!newPosition) {
                    newPosition = elementService.checkAngle(position, neighPoints[1].vectorId, pointId)
                }
                // let angle = mathUtil.Angle(position, neighPoints[0], neighPoints[1])
                // if (Math.abs((angle / Math.PI) * 180 - 90) < 5) {
                //     let line = mathUtil.createLine1(position, neighPoints[0])
                //     let join = mathUtil.getJoinLinePoint(neighPoints[1], line)
                //     if (join) {
                //         mathUtil.clonePoint(position, join)
                //     }
                // } else if (Math.abs((angle / Math.PI) * 180) < 5 || Math.abs((angle / Math.PI) * 180 - 180) < 5) {
                //     let line = mathUtil.createLine1(neighPoints[0], neighPoints[1])
                //     let join = mathUtil.getJoinLinePoint(position, line)
                //     if (join) {
                //         mathUtil.clonePoint(position, join)
                //     }
                // }
            }

            if (newPosition) {
                flag = this.canMoveForPoint(pointId, newPosition, linkedPointId, linkedWallId)
                if (!flag) {
                    return false
                }
                mathUtil.clonePoint(position, newPosition)
            }

            point.setPosition(position)
        }
        // 与别的墙角重合
        else if (modifyPoint.hasOwnProperty('linkedPointId') && modifyPoint.linkedPointId != null) {
            const wallId = wallService.getWallId(pointId, modifyPoint.linkedPointId)
            // pointId与linkedPointId属于同一堵墙，不允许，所以不移动
            if (wallId != null) {
                return false
            } else {
                point.setPosition(modifyPoint)
                this.needUpdateRoom = true
            }
        }
        // 与别的墙面重合
        // 如果墙面的交点与其余墙角的距离过短，那也不允许拖动
        else if (modifyPoint.hasOwnProperty('linkedWallId')) {
            const wall = floorplanService.getWall(modifyPoint.linkedWallId)
            const startPoint = floorplanService.getPoint(wall.start)
            const endPoint = floorplanService.getPoint(wall.end)

            // 与其余墙角的距离过短，不允许拖动
            if (mathUtil.getDistance(startPoint, position) < Constant.minAdsorb || mathUtil.getDistance(endPoint, position) < Constant.minAdsorb) {
                return false
            }
            point.setPosition(modifyPoint)
            this.needUpdateRoom = true
        } else {
            if (modifyPoint.hasOwnProperty('linkedPointIdX') && modifyPoint.linkedPointIdX) {
                //const linkedPointX = floorplanService.getPoint(modifyPoint.linkedPointIdX)
                //elementService.setCheckLinesX(position, linkedPointX)
                point.setPosition(position)
            }

            if (modifyPoint.hasOwnProperty('linkedPointIdY') && modifyPoint.linkedPointIdY) {
                //const linkedPointY = floorplanService.getPoint(modifyPoint.linkedPointIdY)
                //elementService.setCheckLinesY(position, linkedPointY)
                point.setPosition(position)
            }
        }
        return true
    }

    // 拖拽墙面
    moveWallPlane(wallId, dx, dy) {
        // 1表示可以继续移动，2表示不能移动(启动距离还不够)，3表示wallId被删除了,4表示重新开始移动（需要达到一定距离才能启动）,5表示不能移动（不合适）
        let MoveState = 1
        let wall = floorplanService.getWall(wallId)
        let startPointId = wall.start
        let endPointId = wall.end
        let startPoint = floorplanService.getPoint(wall.start)
        let endPoint = floorplanService.getPoint(wall.end)
        // 不考虑约束的情况，得到移动后的坐标
        const newpts = this.getNewPointsForMoveWall(wallId, dx, dy)
        let newLine = mathUtil.createLine1(newpts.point1, newpts.point2)
        // 获取约束信息，包括：是否新建墙，受约束的侧墙
        const limit = this.getTwoLimitInfos(wallId, newLine)
        this.needUpdateRoom = false
        // 不考虑吸附的情况下，经过约束条件后，得到的新的移动后的坐标
        let virtualStartPoint = mathUtil.getIntersectionPoint(newLine, limit.startLimitLine)
        let virtualEndPoint = mathUtil.getIntersectionPoint(newLine, limit.endLimitLine)
        // 刚刚开始移动的时候，或者吸附后再移动的时候，都需要积累一点移动距离才能真正开始移动
        if (!this.startMoving && (mathUtil.getDistance(startPoint, virtualStartPoint) < Constant.minAdsorb || mathUtil.getDistance(endPoint, virtualEndPoint) < Constant.minAdsorb)) {
            this.moveFlag = false
            MoveState = 2
            return MoveState
        }
        this.startMoving = true
        // 判断是否会吸附到邻居墙的另一头端点，同时确保新的坐标在邻居墙内
        let startInfo = this.updateVirtualPosition(wall.start, virtualStartPoint, limit.startWallId, limit.newStartWallId)
        let endInfo = this.updateVirtualPosition(wall.end, virtualEndPoint, limit.endWallId, limit.newEndWallId)
        if (startInfo == null || endInfo == null) {
            this.moveFlag = false
            MoveState = 2
            this.startMoving = false
            return MoveState
        }

        // 判断wallId的 1端/2端 吸附后，是否和别的墙重合
        let coincideFlag = false
        // wallId的长度，可能会很短，要删除
        let distance = null
        // 如果一头被吸附，另一头的坐标还要再次调整
        if (startInfo.adsorb && !endInfo.adsorb) {
            // 先更新newLine
            newLine = mathUtil.createLine3(newLine, startInfo.virtualPosition)
            // 需要判断夹角，如果接近0，则不能移动
            const flag = this.isOKForTwoSegmentsAngle(startInfo.adsorbPointId, wall.start, wall.end)
            if (!flag) {
                this.moveFlag = false
                MoveState = 5
                return MoveState
            }
            // 更新virtualEndPoint
            virtualEndPoint = mathUtil.getIntersectionPoint(newLine, limit.endLimitLine)
            // 再次判断是否吸附
            endInfo = this.updateVirtualPosition(wall.end, virtualEndPoint, limit.endWallId, limit.newEndWallId)
            if (endInfo == null) {
                endInfo = {
                    adsorb: false,
                    adsorbPointId: null,
                    virtualPosition: virtualEndPoint,
                }
            }
            // 一头吸附后，wallId可能和别的墙重合
            coincideFlag = this.isCoincideForAdsorbOne(wall.start, startInfo.adsorbPointId, wallId)
            distance = mathUtil.getDistance(startInfo.virtualPosition, virtualEndPoint)

            MoveState = 4
            this.needUpdateRoom = true
            this.startMoving = false
        } else if (!startInfo.adsorb && endInfo.adsorb) {
            newLine = mathUtil.createLine3(newLine, endInfo.virtualPosition)
            // 需要判断夹角，如果接近0，则不能移动
            const flag = this.isOKForTwoSegmentsAngle(endInfo.adsorbPointId, wall.end, wall.start)
            if (!flag) {
                this.moveFlag = false
                MoveState = 5
                return MoveState
            }

            virtualStartPoint = mathUtil.getIntersectionPoint(newLine, limit.startLimitLine)
            startInfo = this.updateVirtualPosition(wall.start, virtualStartPoint, limit.startWallId, limit.newStartWallId)
            if (startInfo == null) {
                startInfo = {
                    adsorb: false,
                    adsorbPointId: null,
                    virtualPosition: virtualStartPoint,
                }
            }
            coincideFlag = this.isCoincideForAdsorbOne(wall.end, endInfo.adsorbPointId, wallId)
            distance = mathUtil.getDistance(endInfo.virtualPosition, virtualStartPoint)

            MoveState = 4
            this.needUpdateRoom = true
            this.startMoving = false
        }

        // 两头同时吸附呢，wallId可能和别的墙重合
        if (startInfo && endInfo && startInfo.adsorb && endInfo.adsorb) {
            coincideFlag = this.isCoincideForAdsorbOne2(wallId, startInfo.adsorbPointId, endInfo.adsorbPointId)
            distance = mathUtil.getDistance(startInfo.virtualPosition, endInfo.virtualPosition)
            this.startMoving = false
            if (coincideFlag) {
                this.moveFlag = false
                MoveState = 5
                return MoveState
            }
            MoveState = 4
            this.needUpdateRoom = true
        } else {
            distance = mathUtil.getDistance(virtualStartPoint, virtualEndPoint)
            if (distance < Constant.minAdsorb) {
                // 执行deleteWallForLinked后start和end会变，所以提前保存
                this.deleteWallForLinked(wallId)
                startPoint = floorplanService.getPoint(startPointId)
                endPoint = floorplanService.getPoint(endPointId)
                if (!startPoint || !endPoint) {
                    this.moveFlag = false
                    MoveState = 3
                    this.needUpdateRoom = true
                    return MoveState
                }
                if (
                    (Object.keys(startPoint.parent).length > 1 && Object.keys(endPoint.parent).length == 1) ||
                    (Object.keys(startPoint.parent).length == 1 && Object.keys(endPoint.parent).length == 1)
                ) {
                    wallService.moveTo(endPointId, startPointId)
                } else if (Object.keys(startPoint.parent).length == 1 && Object.keys(endPoint.parent).length > 1) {
                    wallService.moveTo(startPointId, endPointId)
                }
                this.moveFlag = false
                MoveState = 3
                this.needUpdateRoom = true
                return MoveState
            }
        }

        startPointId = wall.start
        endPointId = wall.end

        // 是否交叉
        const crossFlag = this.isOKForCrossForMoveWall(virtualStartPoint, virtualEndPoint, wallId, startPointId, endPointId, startInfo.adsorbPointId, endInfo.adsorbPointId)
        // ok
        if (!crossFlag) {
            MoveState = 2
            this.moveFlag = false
            this.startMoving = false
            return MoveState
        }

        // 要删除墙了
        if (coincideFlag || (distance != null && distance < Constant.minAdsorb)) {
            this.deleteWallForLinked(wallId)
            MoveState = 3
            // 删除完墙，邻居墙可能会合并
            wallService.mergeWallForPoint(startPointId)
            wallService.mergeWallForPoint(endPointId)
            this.moveFlag = false
            this.needUpdateRoom = true
            return MoveState
        } else {
            // 要删除墙了
            const join = mathUtil.getIntersectionPoint3(startPoint, virtualStartPoint, endPoint, virtualEndPoint)
            if (join != null) {
                startPoint.setPosition(join)
                endPoint.setPosition(join)
                wallService.moveTo(startPointId, endPointId)
                MoveState = 3
                this.moveFlag = false
                this.needUpdateRoom = true
                return MoveState
            }
        }

        let overlapFlag = false
        if (!limit.newStartWallId && startInfo.adsorbPointId) {
            overlapFlag = wallService.isOverlapForMergePoint(startPointId, startInfo.adsorbPointId)
        } else if (!limit.newEndWallId && endInfo.adsorbPointId) {
            overlapFlag = wallService.isOverlapForMergePoint(endPointId, endInfo.adsorbPointId)
        }
        if (overlapFlag) {
            this.moveFlag = false
            MoveState = 5
            return MoveState
        }

        // 到了这一步，端点的新坐标已经确定了，这里开始更新端点坐标
        // 这里需要升级优化，因为  updatePointForMoveWall方法里也更新了edge,这个其实不需要的。
        this.updatePointForMoveWall(wallId, startPointId, startInfo, limit.startWallId, limit.newStartWallId)
        this.updatePointForMoveWall(wallId, endPointId, endInfo, limit.endWallId, limit.newEndWallId)
        wall = floorplanService.getWall(wallId)
        if (wall == null) {
            MoveState = 3
            this.moveFlag = false
            this.needUpdateRoom = true
            // console.log(271)
            return MoveState
        }

        if (MoveState == 1) {
            this.moveFlag = true
        } else {
            this.moveFlag = false
        }
        return MoveState
    }

    //拖拽墙角/墙面，被其他墙角吸附
    updateForAbsorbWallPoints() {
        if (Object.keys(this.adsorbPointWalls).length == 0) {
            return
        } else if (Object.keys(this.adsorbPointWalls).length == 2) {
            debugger
        }

        let joins = []
        let wallId = null
        for (let key in this.adsorbPointWalls) {
            let point = floorplanService.getPoint(key)
            joins.push({
                join: point,
                pointId: key,
            })
            wallId = this.adsorbPointWalls[key]
        }

        const wall = floorplanService.getWall(wallId)
        const startPoint = floorplanService.getPoint(wall.start)

        function sortNumber(a, b) {
            return mathUtil.getDistance(startPoint, a.join) - mathUtil.getDistance(startPoint, b.join)
        }

        joins = joins.sort(sortNumber.bind(this))

        for (let i = 0; i < joins.length; ++i) {
            const info = joins[i]
            const join = info.join
            const pointId = info.pointId

            wallService.splitWall(wallId, pointId, 'end')
        }
    }

    getNewPointsForMoveWall(wallId, dx, dy) {
        dx = dx / coordinate.res * Constant.defaultZoom/coordinate.zoom
        dy = -dy / coordinate.res * Constant.defaultZoom/coordinate.zoom

        const wall = floorplanService.getWall(wallId)
        const startPoint = floorplanService.getPoint(wall.start)
        const endPoint = floorplanService.getPoint(wall.end)

        const p1 = { x: startPoint.x + dx, y: startPoint.y + dy }
        const p2 = { x: endPoint.x + dx, y: endPoint.y + dy }

        return {
            point1: p1,
            point2: p2,
        }
    }

    getTwoLimitInfos(wallId, newLine) {
        const wall = floorplanService.getWall(wallId)
        const startPoint = floorplanService.getPoint(wall.start)
        const endPoint = floorplanService.getPoint(wall.end)
        let startLimitLine, endLimitLine, info
        const wallLine = mathUtil.createLine1(startPoint, endPoint)

        const limitInfos = {}
        limitInfos.newStartWallId = false // 不需要新建墙
        limitInfos.newEndWallId = false // 不需要新建墙

        // 先处理start
        if (Object.keys(startPoint.parent).length == 1) {
            startLimitLine = mathUtil.getVerticalLine(wallLine, startPoint)
            limitInfos.startWallId = null
        } else if (Object.keys(startPoint.parent).length == 2) {
            let tempWall
            if (Object.keys(startPoint.parent)[0] == wallId) {
                tempWall = floorplanService.getWall(Object.keys(startPoint.parent)[1])
            } else if (Object.keys(startPoint.parent)[1] == wallId) {
                tempWall = floorplanService.getWall(Object.keys(startPoint.parent)[0])
            }
            if (!tempWall) {
                console.error(352)
            }
            const angle = wallService.AngleForWall(tempWall.vectorId, wallId)
            startLimitLine = wallService.getLine(tempWall)
            limitInfos.startWallId = tempWall.vectorId
            if (angle > (Constant.maxAngle / 180) * Math.PI) {
                startLimitLine = mathUtil.getVerticalLine(wallLine, startPoint)
                limitInfos.startWallId = null
                limitInfos.newStartWallId = true
            }
        } else {
            let tempWall, tempWallId
            info = wallService.wallIdForMinAngle(wall.start, wallId)
            const wall1 = floorplanService.getWall(info.min0.wallId)
            const startPoint1 = floorplanService.getPoint(wall1.start)
            const endPoint1 = floorplanService.getPoint(wall1.end)
            const wall2 = floorplanService.getWall(info.min1.wallId)
            const startPoint2 = floorplanService.getPoint(wall2.start)
            const endPoint2 = floorplanService.getPoint(wall2.end)

            const join1 = mathUtil.getIntersectionPoint4(startPoint1, endPoint1, newLine)
            const join2 = mathUtil.getIntersectionPoint4(startPoint2, endPoint2, newLine)

            // 取角度大的
            if (join1 == null && join2 == null) {
                let angle0 = wallService.AngleForWall(wallId, info.min0.wallId)
                let angle1 = wallService.AngleForWall(wallId, info.min1.wallId)
                if (angle0 > Math.PI) {
                    angle0 = Math.PI - angle0
                }
                if (angle1 > Math.PI) {
                    angle1 = Math.PI - angle1
                }
                if (angle0 < angle1) {
                    tempWallId = info.min0.wallId
                } else {
                    tempWallId = info.min1.wallId
                }
                limitInfos.newStartWallId = true
            }
            // 取角度小的
            else if (join1 != null && join2 != null) {
                if (info.min0.angle < info.min1.angle) {
                    tempWallId = info.min0.wallId
                } else {
                    tempWallId = info.min1.wallId
                }
            } else if (join1 == null && join2 != null) {
                tempWallId = info.min1.wallId
            } else if (join1 != null && join2 == null) {
                tempWallId = info.min0.wallId
            }
            limitInfos.startWallId = tempWallId
            tempWall = floorplanService.getWall(tempWallId)
            const angle = wallService.AngleForWall(tempWallId, wallId)
            startLimitLine = wallService.getLine(tempWall)
            if (angle > (Constant.maxAngle / 180) * Math.PI) {
                startLimitLine = mathUtil.getVerticalLine(wallLine, startPoint)
                limitInfos.startWallId = null
                limitInfos.newStartWallId = true
            }
        }

        // 再处理end
        if (Object.keys(endPoint.parent).length == 1) {
            endLimitLine = mathUtil.getVerticalLine(wallLine, endPoint)
            limitInfos.endWallId = null
        } else if (Object.keys(endPoint.parent).length == 2) {
            let tempWall
            if (Object.keys(endPoint.parent)[0] == wallId) {
                tempWall = floorplanService.getWall(Object.keys(endPoint.parent)[1])
            } else if (Object.keys(endPoint.parent)[1] == wallId) {
                tempWall = floorplanService.getWall(Object.keys(endPoint.parent)[0])
            }
            const angle = wallService.AngleForWall(tempWall.vectorId, wallId)
            endLimitLine = wallService.getLine(tempWall)
            limitInfos.endWallId = tempWall.vectorId
            if (angle > (Constant.maxAngle / 180) * Math.PI) {
                endLimitLine = mathUtil.getVerticalLine(wallLine, endPoint)
                limitInfos.endWallId = null
                limitInfos.newEndWallId = true
            }
        } else {
            let tempWall, tempWallId
            info = wallService.wallIdForMinAngle(wall.end, wallId)
            const wall1 = floorplanService.getWall(info.min0.wallId)
            const startPoint1 = floorplanService.getPoint(wall1.start)
            const endPoint1 = floorplanService.getPoint(wall1.end)
            const wall2 = floorplanService.getWall(info.min1.wallId)
            const startPoint2 = floorplanService.getPoint(wall2.start)
            const endPoint2 = floorplanService.getPoint(wall2.end)

            const join1 = mathUtil.getIntersectionPoint4(startPoint1, endPoint1, newLine)
            const join2 = mathUtil.getIntersectionPoint4(startPoint2, endPoint2, newLine)

            // 取角度大的
            if (join1 == null && join2 == null) {
                let angle0 = wallService.AngleForWall(wallId, info.min0.wallId)
                let angle1 = wallService.AngleForWall(wallId, info.min1.wallId)
                if (angle0 > Math.PI) {
                    angle0 = Math.PI - angle0
                }
                if (angle1 > Math.PI) {
                    angle1 = Math.PI - angle1
                }
                if (angle0 < angle1) {
                    tempWallId = info.min0.wallId
                } else {
                    tempWallId = info.min1.wallId
                }
                limitInfos.newEndWallId = true
            }
            // 取角度小的
            else if (join1 != null && join2 != null) {
                if (info.min0.angle < info.min1.angle) {
                    tempWallId = info.min0.wallId
                } else {
                    tempWallId = info.min1.wallId
                }
            } else if (join1 == null && join2 != null) {
                tempWallId = info.min1.wallId
            } else if (join1 != null && join2 == null) {
                tempWallId = info.min0.wallId
            }
            limitInfos.endWallId = tempWallId
            tempWall = floorplanService.getWall(tempWallId)
            const angle = wallService.AngleForWall(tempWallId, wallId)
            endLimitLine = wallService.getLine(tempWall)
            if (angle > (Constant.maxAngle / 180) * Math.PI) {
                endLimitLine = mathUtil.getVerticalLine(wallLine, endPoint)
                limitInfos.endWallId = null
                limitInfos.newEndWallId = true
            }
        }
        limitInfos.startLimitLine = startLimitLine
        limitInfos.endLimitLine = endLimitLine
        return limitInfos
    }

    // 是否可以移动point
    // 两个判断：拖拽的墙（可能是多个），一方面不能与其他墙相交，另一方面这些墙之间或者与别的墙之间的角度必须大于Constant.minAngle
    canMoveForPoint(pointId, position, linkedPointId, linkedWallId) {
        const point = floorplanService.getPoint(pointId)
        // 先判断第二点(这些墙之间或者与别的墙之间的角度必须大于MinAngle)
        let flag = this.isOKForMinAngleWall(pointId, position)
        // 开始考虑第一点
        if (flag) {
            // 不仅仅角度，还有相交
            flag = this.isOKForCross(pointId, position, point.parent, linkedPointId, linkedWallId)
        }
        return flag
    }

    isOKForMinAngleWall(pointId, position) {
        const point = floorplanService.getPoint(pointId)
        const parent = point.parent

        const angle = this.getMinAngle(pointId, position)
        if (Math.abs(angle) < (Constant.minAngle / 180) * Math.PI) {
            return false
        }

        // 判断邻居点
        for (const key in parent) {
            const wall = floorplanService.getWall(key)
            const otherPointId = wall.getOtherPointId(pointId)
            const info = this.getNeighMinAngle(otherPointId, key, position)
            if (info && Math.abs(info.angle) < (Constant.minAngle / 180) * Math.PI) {
                return false
            } else {
                const otherPoint = floorplanService.getPoint(otherPointId)
                if (mathUtil.getDistance(position, otherPoint) < Constant.minAdsorb) {
                    return false
                }
            }
        }

        return true
    }

    //点pointId移动到position后，求出最小角度
    getMinAngle(pointId, position) {
        const point = floorplanService.getPoint(pointId)
        const parent = point.parent
        let angle = null
        if (Object.keys(parent).length == 1) {
            return 2 * Math.PI
        } else if (Object.keys(parent).length == 2) {
            const wall1 = floorplanService.getWall(Object.keys(parent)[0])
            const wall2 = floorplanService.getWall(Object.keys(parent)[1])

            const otherPointId1 = wall1.getOtherPointId(pointId)
            const otherPoint1 = floorplanService.getPoint(otherPointId1)
            const otherPointId2 = wall2.getOtherPointId(pointId)
            const otherPoint2 = floorplanService.getPoint(otherPointId2)

            angle = mathUtil.Angle(position, otherPoint1, otherPoint2)
            return angle
        } else {
            const _position = {
                x: position.x + 1,
                y: position.y,
            }
            let angles = []
            for (const key in parent) {
                const wall = floorplanService.getWall(key)
                const otherPointId = wall.getOtherPointId(pointId)
                const otherPoint = floorplanService.getPoint(otherPointId)
                if (mathUtil.equalPoint(_position, otherPoint)) {
                    angles.push(0)
                    continue
                } else {
                    let angle = mathUtil.Angle(position, _position, otherPoint)
                    // 统一按照逆时针顺序
                    if (otherPoint.y < position.y) {
                        angle = 2 * Math.PI - angle
                    }
                    angles.push(angle)
                }
            }

            angles = angles.sort(sortNumber)

            let minAngle = 2 * Math.PI
            for (let i = 0; i < angles.length - 1; ++i) {
                for (let j = i + 1; j < angles.length; ++j) {
                    const _angle = angles[j] - angles[i]
                    if (_angle < minAngle) {
                        minAngle = _angle
                    }
                }
            }

            const angle1 = angles[0]
            const angle2 = angles[angles.length - 1]
            if (angle1 < Math.PI && angle2 > Math.PI) {
                const dAngle = 2 * Math.PI + angle1 - angle2
                if (dAngle < minAngle) {
                    minAngle = dAngle
                }
            }
            return minAngle
        }

        function sortNumber(a, b) {
            return a - b
        }
    }

    // 用于邻居点
    // pointId是顶点
    // position是wallId相对于pointId另一头的点的坐标，一般发生改变的时候使用这个函数
    getNeighMinAngle(otherPointId, wallId, position) {
        const point1 = floorplanService.getPoint(otherPointId)
        const point2 = {
            x: position.x,
            y: position.y,
        }
        let pointId3 = null
        let point3 = null
        let minAngle = null
        let result = null

        for (const key in point1.parent) {
            if (key == wallId) {
                continue
            }

            const wall = floorplanService.getWall(key)
            pointId3 = wall.getOtherPointId(otherPointId)
            point3 = floorplanService.getPoint(pointId3)

            const angle = mathUtil.Angle(point1, point2, point3)
            if (minAngle == null || minAngle > angle) {
                minAngle = angle
                result = {
                    angle: minAngle,
                    pointId: pointId3,
                }
            }
        }
        return result
    }

    // linkedPointId,linkedWallId表示吸附
    // wallIds是pointId的parent
    isOKForCross(pointId, position, wallIds, linkedPointId, linkedWallId) {
        const walls = floorplanService.getWalls()
        for (const key in walls) {
            if (wallIds.hasOwnProperty(key)) {
                continue
            } else if (linkedWallId == key) {
                continue
            }

            for (const _key in wallIds) {
                //相连就不用考虑了
                if (wallService.isWallLink(key, _key)) {
                    continue
                }
                const _wall = floorplanService.getWall(_key)
                const otherPointId = _wall.getOtherPointId(pointId)
                const otherPoint = floorplanService.getPoint(otherPointId)

                const flag = this.isOKForCrossTwoWall(position, otherPoint, key, linkedPointId, linkedWallId, _wall.vectorId)
                // 交叉
                if (!flag) {
                    this.adsorbPointWalls = {}
                    return false
                }
            }
        }
        //需要吸附了。
        if (Object.keys(this.adsorbPointWalls).length > 0) {
            return false
        } else if (this.splitWallId != null) {
            return false
        }
        // 不交叉
        return true
    }

    // position1表示拖拽的点的坐标（修复过了的）
    // position2对应墙的另一头坐标
    // wallId表示其余的墙（与position1无关的墙）
    isOKForCrossTwoWall(position1, position2, wallId, linkedPointId, linkedWallId, dragWallId) {
        const wall = floorplanService.getWall(wallId)
        const startPoint = floorplanService.getPoint(wall.start)
        const endPoint = floorplanService.getPoint(wall.end)
        const join = mathUtil.getIntersectionPoint3(position1, position2, startPoint, endPoint)
        if (join && wall.start != linkedPointId && wall.end != linkedPointId) {
            // 交叉了
            this.splitWallId = wallId
            return true
        } else {
            if (mathUtil.equalPoint(position1, position2)) {
                return true
            }
            let line = mathUtil.createLine1(position1, position2)
            let join1 = mathUtil.getJoinLinePoint(startPoint, line)
            let join2 = mathUtil.getJoinLinePoint(endPoint, line)

            if (mathUtil.getDistance(join1, startPoint) < Constant.minAdsorb && mathUtil.PointInSegment(join1, position1, position2)) {
                if (wall.start != linkedPointId) {
                    // 交叉了
                    this.adsorbPointWalls[startPoint.vectorId] = dragWallId
                    //为了找到全部的吸附点，暂时返回true,在外面一层再做判断
                    return true
                }
            } else if (mathUtil.getDistance(join2, endPoint) < Constant.minAdsorb && mathUtil.PointInSegment(join2, position1, position2)) {
                if (wall.end != linkedPointId) {
                    // 交叉了
                    this.adsorbPointWalls[endPoint.vectorId] = dragWallId
                    //为了找到全部的吸附点，暂时返回true,在外面一层再做判断
                    return true
                }
            }

            line = mathUtil.createLine1(startPoint, endPoint)
            join1 = mathUtil.getJoinLinePoint(position1, line)
            join2 = mathUtil.getJoinLinePoint(position2, line)
            if (mathUtil.getDistance(join1, position1) < Constant.minAdsorb && mathUtil.PointInSegment(join1, startPoint, endPoint)) {
                if (wall.start != linkedPointId && wall.end != linkedPointId && wallId != linkedWallId) {
                    // 交叉了
                    //return false
                    return true
                }
            } else if (mathUtil.getDistance(join2, position2) < Constant.minAdsorb && mathUtil.PointInSegment(join2, startPoint, endPoint)) {
                if (wall.start != linkedPointId && wall.end != linkedPointId && wallId != linkedWallId) {
                    // 交叉了
                    //return false
                    return true
                }
            }
        }

        return true
    }

    isOKForCrossTwoWall2(position1, position2, wallId) {
        const wall = floorplanService.getWall(wallId)
        const startPoint = floorplanService.getPoint(wall.start)
        const endPoint = floorplanService.getPoint(wall.end)
        let flag = mathUtil.crossTwoLines(position1, position2, startPoint, endPoint, 0.01)
        if (flag) {
            // 交叉了
            return false
        } else {
            if (mathUtil.equalPoint(position1, position2)) {
                return true
            }
            flag = this.isCoincide(position1, position2, wallId)
            if (!flag) {
                return false
            }
        }

        return true
    }

    isOKForCrossTwoWall3(position1, position2, wallId) {
        const wall = floorplanService.getWall(wallId)
        const startPoint = floorplanService.getPoint(wall.start)
        const endPoint = floorplanService.getPoint(wall.end)
        const flag = mathUtil.crossTwoLines(position1, position2, startPoint, endPoint, 0.01)
        if (flag) {
            // 交叉了
            return false
        } else {
            if (mathUtil.equalPoint(position1, position2)) {
                return true
            }
            let line = mathUtil.createLine1(position1, position2)
            let join1 = mathUtil.getJoinLinePoint(startPoint, line)
            const join2 = mathUtil.getJoinLinePoint(endPoint, line)

            if (mathUtil.getDistance(join1, startPoint) < Constant.minAdsorb && mathUtil.PointInSegment(join1, position1, position2)) {
                // 交叉了
                return false
            } else if (mathUtil.getDistance(join2, endPoint) < Constant.minAdsorb && mathUtil.PointInSegment(join2, position1, position2)) {
                // 交叉了
                return false
            }

            line = mathUtil.createLine1(startPoint, endPoint)
            join1 = mathUtil.getJoinLinePoint(position1, line)
            if (mathUtil.getDistance(join1, position1) < Constant.minAdsorb && wallService.isContain(wall, join1)) {
                // 交叉了
                return false
            }
        }

        return true
    }

    isCoincide(position1, position2, wallId) {
        const wall = floorplanService.getWall(wallId)
        const startPoint = floorplanService.getPoint(wall.start)
        const endPoint = floorplanService.getPoint(wall.end)
        let line = mathUtil.createLine1(position1, position2)
        let join1 = mathUtil.getJoinLinePoint(startPoint, line)
        let join2 = mathUtil.getJoinLinePoint(endPoint, line)
        if (mathUtil.getDistance(join1, startPoint) < Constant.minAdsorb && mathUtil.PointInSegment(join1, position1, position2)) {
            // 交叉了
            return false
        } else if (mathUtil.getDistance(join2, endPoint) < Constant.minAdsorb && mathUtil.PointInSegment(join2, position1, position2)) {
            // 交叉了
            return false
        }

        line = mathUtil.createLine1(startPoint, endPoint)
        join1 = mathUtil.getJoinLinePoint(position1, line)
        join2 = mathUtil.getJoinLinePoint(position2, line)

        if (mathUtil.getDistance(join1, position1) < Constant.minAdsorb && wallService.isContain(wall, join1)) {
            // 交叉了
            return false
        } else if (mathUtil.getDistance(join2, position2) < Constant.minAdsorb && wallService.isContain(wall, join2)) {
            // 交叉了
            return false
        }
        return true
    }

    // 更新virtualPosition（一般是吸附）
    updateVirtualPosition(pointId, virtualPosition, limitWallId, needNew) {
        const limitWall = floorplanService.getWall(limitWallId)
        const point = floorplanService.getPoint(pointId)
        let otherPointId, otherPoint
        let adsorb = false
        // 不需要新建墙
        if (!needNew) {
            if (limitWall != null) {
                otherPointId = limitWall.getOtherPointId(pointId)
                otherPoint = floorplanService.getPoint(otherPointId)
                // 会吸附另一头
                if (
                    mathUtil.getDistance(virtualPosition, otherPoint) < Constant.minAdsorb ||
                    (!wallService.isContain(limitWall, virtualPosition) && mathUtil.getDistance(virtualPosition, otherPoint) < mathUtil.getDistance(virtualPosition, point))
                ) {
                    mathUtil.clonePoint(virtualPosition, otherPoint)
                    adsorb = true
                }
            }
        }
        // 需要新建墙
        else {
            // 新建的墙太短，不允许
            if (mathUtil.getDistance(point, virtualPosition) < Constant.minAdsorb) {
                return null
            }
        }
        return {
            adsorb: adsorb,
            adsorbPointId: adsorb ? otherPointId : null,
            virtualPosition: virtualPosition,
        }
    }

    // 两条线段的夹角，这两条线段分别有一个端点挨的很近
    isOKForTwoSegmentsAngle(pointId, pointId1, pointId2) {
        const point = floorplanService.getPoint(pointId)
        const point1 = floorplanService.getPoint(pointId1)
        const point2 = floorplanService.getPoint(pointId2)
        const dx = point.x - point1.x
        const dy = point.y - point1.y

        const newPoint2 = {
            x: dx + point2.x,
            y: dy + point2.y,
        }

        for (const key in point.parent) {
            const wall = floorplanService.getWall(key)
            const otherPointId = wall.getOtherPointId(pointId)
            const otherPoint = floorplanService.getPoint(otherPointId)
            const angle = mathUtil.Angle(point, otherPoint, newPoint2)
            if (Math.abs(angle) < (Constant.minAngle / 180) * Math.PI) {
                return false
            }
        }
        return true
    }

    // 一头吸附后，是否会重合
    // pointId属于wallId，当pointId吸附到adsorbPointId时
    isCoincideForAdsorbOne(pointId, adsorbPointId, wallId) {
        if (pointId && adsorbPointId) {
            const wall = floorplanService.getWall(wallId)
            const otherPointId = wall.getOtherPointId(pointId)
            const _wallId = wallService.getWallId(otherPointId, adsorbPointId)
            if (_wallId != null) {
                return true
            }
        }
        return false
    }

    isCoincideForAdsorbOne2(wallId, adsorbPointId1, adsorbPointId2) {
        if (adsorbPointId1 && adsorbPointId2) {
            const _wallId = wallService.getWallId(adsorbPointId1, adsorbPointId2)
            if (_wallId != null) {
                return true
            }
            // 可能吸附的是两堵墙，但是这两堵墙呈180°
            else {
                let adsorbPoint = floorplanService.getPoint(adsorbPointId1)
                let parent = adsorbPoint.parent
                for (const key in parent) {
                    const angle = wallService.AngleForWall3(wallId, key)
                    if (Math.abs(angle) < (Constant.minAngle / 180) * Math.PI) {
                        return true
                    }
                }

                adsorbPoint = floorplanService.getPoint(adsorbPointId2)
                parent = adsorbPoint.parent
                for (const key in parent) {
                    const angle = wallService.AngleForWall3(wallId, key)
                    if (Math.abs(angle) < (Constant.minAngle / 180) * Math.PI) {
                        return true
                    }
                }
            }
        }
        return false
    }

    // position1和position2表示wall的两个端点坐标（下一步的）
    // position3和position4表示wall的start一边的线段（startPoint——virtualStartPoint）
    // position5和position6表示wall的end一边的线段（endPoint——virtualEndPoint）
    // adsorbPointId1对应start那一头的吸附点
    // adsorbPointId2对应end那一头的吸附点
    isOKForCrossForMoveWall(position1, position2, wallId, startPointId, endPointId, adsorbPointId1, adsorbPointId2) {
        const startPoint = floorplanService.getPoint(startPointId)
        const endPoint = floorplanService.getPoint(endPointId)
        let flag = true
        const walls = floorplanService.getWalls()
        for (const key in walls) {
            if (key == wallId) {
                continue
            }

            let flag1 = true
            let flag2 = true

            const _wall = floorplanService.getWall(key)
            if (adsorbPointId1 && (adsorbPointId1 == _wall.start || adsorbPointId1 == _wall.end)) {
                flag1 = false
            }
            if (adsorbPointId2 && (adsorbPointId2 == _wall.start || adsorbPointId2 == _wall.end)) {
                flag2 = false
            }

            if (_wall.start == startPointId || _wall.end == startPointId) {
                flag1 = false
            }

            if (_wall.start == endPointId || _wall.end == endPointId) {
                flag2 = false
            }

            // 两头不连
            if (flag1 && flag2) {
                flag = this.isOKForCrossTwoWall2(position1, position2, key)
            }

            if (!flag) {
                return false
            }
            if (flag1 && _wall.start != startPointId && _wall.end != startPointId) {
                flag = this.isOKForCrossTwoWall3(position1, startPoint, key)
            }

            if (!flag) {
                return false
            }

            if (flag2 && _wall.start != endPointId && _wall.end != endPointId) {
                flag = this.isOKForCrossTwoWall3(position2, endPoint, key)
            }

            if (!flag) {
                return false
            }
        }
        return flag
    }

    // 更新pointId的坐标
    updatePointForMoveWall(wallId, pointId, virtualInfo, limitWallId, needNew) {
        const point = floorplanService.getPoint(pointId)
        const wall = floorplanService.getWall(wallId)
        // 如果没有约束墙，只有两种情况：一种是不新建墙，另一种是需要新建墙
        if (limitWallId == null) {
            // 不需要新建墙，这种情况一般是pointId的parent只有一个
            if (!needNew) {
                point.setPosition(virtualInfo.virtualPosition)
            }
            // 新建墙
            else {
                this.createWallForMoveWall(pointId, wallId, virtualInfo.virtualPosition)
                this.needUpdateRoom = true
            }
        } else {
            /*
        不新建墙：
        1. 更新坐标（一种是当pointId的parent是2个，另一种是三个，但是wallId对应的两堵墙接近180°）
        2. 拆分墙
        3. 吸附邻居墙的另一个端点
        新建墙：
        */
            // 不新建墙
            if (!needNew) {
                if (!virtualInfo.adsorb) {
                    // 只更新坐标
                    if (Object.keys(point.parent).length == 2) {
                        point.setPosition(virtualInfo.virtualPosition)
                    } else {
                        const info = wallService.wallIdForMinAngle(pointId, wallId)
                        const angle = wallService.AngleForWall(info.min0.wallId, info.min1.wallId)
                        // 只更新坐标
                        if (Object.keys(point.parent).length == 3 && angle > (Constant.maxAngle / 180) * Math.PI) {
                            point.setPosition(virtualInfo.virtualPosition)
                        }
                        // 拆分墙
                        else {
                            const dir = wallService.getDirction(pointId, wallId)
                            // 先断开链接
                            wallService.subtraWallFromIntersect(pointId, wallId)
                            const newPointId = wall.getPointId(dir)
                            const newPoint = floorplanService.getPoint(newPointId)
                            // 更新新坐标
                            newPoint.setPosition(virtualInfo.virtualPosition)
                            // 拆分
                            wallService.splitWall(limitWallId, newPointId, dir)
                            this.needUpdateRoom = true
                        }
                    }
                }
                // 吸附邻居墙的另一个端点。
                else {
                    wallService.moveTo(pointId, virtualInfo.adsorbPointId)
                    this.needUpdateRoom = true
                }
            }
            // 新建墙
            else {
                this.createWallForMoveWall(pointId, wallId, virtualInfo.virtualPosition)
                this.needUpdateRoom = true
            }
        }
    }

    //
    createWallForMoveWall(pointId, wallId, newPosition) {
        const wall = floorplanService.getWall(wallId)
        const dir = wallService.getDirction(pointId, wallId)

        // 第一步是断开连接
        wallService.subtraWallFromIntersect(pointId, wallId)
        // 第二步更新端点坐标
        const newPointId = wall.getPointId(dir)
        const newPoint = floorplanService.getPoint(newPointId)
        newPoint.setPosition(newPosition)
        // 第三步先新建墙
        wallService.createWall(pointId, newPointId)
        // 还缺少wall和newWall相交，这需要等另一头的point完成后最后处理
    }

    deleteWallForLinked(wallId) {
        const wall = floorplanService.getWall(wallId)
        wallService.subtraWallFromIntersect(wall.start, wallId)
        wallService.subtraWallFromIntersect(wall.end, wallId)
        floorplanService.deleteWall(wallId)
    }
}

const moveWall = new MoveWall()
export { moveWall }
