Source: animation/animation-types/z-park.mjs

'use strict'

import * as td from '../../type-defs.mjs'

/**
 * @class
 * @param {td.AnimationHandler} animationHandler
 * @param {String} animName
 */
function ZPark(animationHandler, animName) {
    this.animationHandler = animationHandler
    this.name = animName

    this.ruleObject = undefined
    this.endVals = undefined
}

/**
 * @method
 * @param {td.Car} car
 */
ZPark.prototype.buildSelf = function (car) {
    this.endVals = this.getEndVals(car)

    let ruleString = this.buildRuleString(car, this.name, this.endVals)

    this.animationHandler.styleSheet.insertRule(
        ruleString,
        this.animationHandler.styleSheet.cssRules.length
    )
    this.ruleObject = this.animationHandler.getAnimationRule(this.name)
}

ZPark.prototype.buildRuleString = function (car, name, endVals) {
    let first, second, third, fourth, last
    first = this.buildFirstKeyframe(car)
    second = this.buildSecondKeyframe(car, endVals, 30)
    third = this.buildThirdKeyframe(car, endVals, 45)
    fourth = this.buildFourthKeyframe(car, endVals, 80)
    last = this.buildLastKeyframe(endVals)

    return '@keyframes ' + name + first + second + third + fourth + last
}

ZPark.prototype.buildFirstKeyframe = function (car) {
    let first =
        '{0% {left: ' +
        car.coords.x +
        'px;top: ' +
        car.coords.y +
        'px;transform: rotate(' +
        car.orientation +
        'deg);}'
    return first
}
ZPark.prototype.buildSecondKeyframe = function (car, endVals, keyframe) {
    let leftVal, topVal, orientationVal, orientationChange
    switch (endVals.direction) {
        case 'west':
            console.err('Unexpected State/Unhandled Case!')
            break
        case 'east':
            leftVal =
                endVals.spaceEntrance -
                car.baseLength -
                (car.baseWidth / 2) * car.negation

            topVal =
                car.coords.y +
                (endVals.crossDistance / 4) * endVals.crossNegation
            break
        case 'north':
            leftVal =
                car.coords.x +
                (endVals.crossDistance / 4) * endVals.crossNegation

            topVal = endVals.spaceEntrance - (car.baseWidth / 2) * car.negation
            break
        case 'south':
            console.err('Unexpected State/Unhandled Case!')
            break
    }

    if (endVals.crossDistance > car.baseWidth) {
        // Stop cars from over-rotating
        orientationChange = 30
    } else {
        orientationChange = endVals.crossDistance / 4
    }
    orientationVal = car.orientation + orientationChange * endVals.crossNegation

    let second =
        keyframe +
        '% {left: ' +
        leftVal +
        'px;top: ' +
        topVal +
        'px;transform: rotate(' +
        orientationVal +
        'deg);}'
    return second
}
ZPark.prototype.buildThirdKeyframe = function (car, endVals, keyframe) {
    let leftVal, topVal, orientationVal, orientationChange
    switch (endVals.direction) {
        case 'west':
            console.err('Unexpected State/Unhandled Case!')
            break
        case 'east':
            leftVal = endVals.spaceEntrance - car.baseLength

            topVal =
                car.coords.y +
                endVals.crossDistance * 0.6 * endVals.crossNegation
            break
        case 'north':
            leftVal =
                car.coords.x +
                endVals.crossDistance * 0.6 * endVals.crossNegation

            topVal = endVals.spaceEntrance
            break
        case 'south':
            console.err('Unexpected State/Unhandled Case!')
            break
    }

    orientationChange = endVals.crossDistance / 2
    if (endVals.crossDistance > car.baseWidth) {
        // Stop cars from over-rotating
        orientationChange = 50
    }
    orientationVal = car.orientation + orientationChange * endVals.crossNegation

    let third =
        keyframe +
        '% {left: ' +
        leftVal +
        'px;top: ' +
        topVal +
        'px;transform: rotate(' +
        orientationVal +
        'deg);}'
    return third
}
ZPark.prototype.buildFourthKeyframe = function (car, endVals, keyframe) {
    let leftVal, topVal, orientationVal, orientationChange
    switch (endVals.direction) {
        case 'west':
            console.err('Unexpected State/Unhandled Case!')
            break
        case 'east':
            leftVal =
                endVals.spaceEntrance -
                car.baseLength +
                (car.baseWidth / 2) * car.negation

            topVal = endVals.y
            break
        case 'north':
            leftVal = endVals.x

            topVal = endVals.spaceEntrance + (car.baseWidth / 2) * car.negation
            break
        case 'south':
            console.err('Unexpected State/Unhandled Case!')
            break
    }

    orientationChange = endVals.crossDistance / 6
    if (endVals.crossDistance > car.baseWidth) {
        // Stop cars from over-rotating
        orientationChange = 15
    }
    orientationVal = car.orientation + orientationChange * endVals.crossNegation

    let fourth =
        keyframe +
        '% {left: ' +
        leftVal +
        'px;top: ' +
        topVal +
        'px;transform: rotate(' +
        orientationVal +
        'deg);}'
    return fourth
}
ZPark.prototype.buildLastKeyframe = function (endVals) {
    let last =
        '100% {left: ' +
        endVals.x +
        'px;top: ' +
        endVals.y +
        'px;transform: rotate(' +
        endVals.orientation +
        'deg);}}'
    return last
}

ZPark.prototype.getEndVals = function (car) {
    let endVals = {}

    let relationalValues = this.getRelationalValues(car)
    endVals.orientation = relationalValues.orientation
    endVals.direction = relationalValues.direction
    endVals.crossNegation = relationalValues.crossNegation
    endVals.crossDistance = relationalValues.crossDistance
    endVals.forwardDistance = relationalValues.forwardDistance
    endVals.spaceEntrance = relationalValues.spaceEntrance

    endVals.y = car.assignedSpace.y
    endVals.x = car.assignedSpace.x

    endVals = this.getAdjustedEndCoords(car, endVals)

    return endVals
}
ZPark.prototype.getRelationalValues = function (car) {
    let orientation = car.orientation
    let endDirection = car.assignedSpace.facing

    // Only handling cases present in current parking lot.

    let crossNegation, closestEdge
    // Check against true mid point of the car (license plate)
    if (
        car.route[1].coord >
        car.coords[car.oppSymbol] +
            (car.baseLength - car.baseWidth) / 2 +
            car.baseWidth / 2
    ) {
        crossNegation = 1
        // Opposite side of wrapper
        closestEdge =
            car.coords[car.oppSymbol] +
            car.baseLength -
            (car.baseLength - car.baseWidth) / 2
    } else {
        crossNegation = -1
        // Normal side of wrapper
        closestEdge =
            car.coords[car.oppSymbol] + (car.baseLength - car.baseWidth) / 2
    }
    let crossDistance = Math.abs(car.route[1].coord - closestEdge)

    let spaceEntrance = car.assignedSpace[car.symbol]
    if (car.assignedSpace.facing === 'north') {
        spaceEntrance += car.assignedSpace.height
    } else if (car.assignedSpace.facing === 'west') {
        spaceEntrance += car.assignedSpace.width
    }

    let forwardDistance = Math.abs(car.leadingEdge - spaceEntrance)

    return {
        orientation: orientation,
        direction: endDirection,
        crossNegation: crossNegation,
        crossDistance: crossDistance,
        forwardDistance: forwardDistance,
        spaceEntrance: spaceEntrance,
    }
}
ZPark.prototype.getAdjustedEndCoords = function (car, endVals) {
    switch (endVals.direction) {
        case 'west':
            console.err('Unexpected State/Unhandled Case!')
            break
        case 'east':
            endVals.x = endVals.x + (car.assignedSpace.width - car.baseLength)

            endVals.y -=
                car.baseWidth / 2 -
                (car.assignedSpace.height - car.baseWidth) / 2

            endVals.orientation = car.orientation

            endVals.x -= 10
            break
        case 'north':
            endVals.x -=
                car.baseWidth / 2 -
                (car.assignedSpace.width - car.baseWidth) / 2

            endVals.y = endVals.y

            endVals.orientation = car.orientation

            endVals.y += 10
            break
        case 'south':
            console.err('Unexpected State/Unhandled Case!')
            break
    }

    return endVals
}

export {ZPark}