import { combine_hash } from "../../../../core/collection/array/combine_hash.js";
import Vector2 from "../../../../core/geom/Vector2.js";
import ObservedBoolean from "../../../../core/model/ObservedBoolean.js";
import { computeHashFloat } from "../../../../core/primitives/numbers/computeHashFloat.js";

/**
 * @readonly
 * @enum {number}
 */
export const ViewportPositionFlags = {
    StickToScreenEdge: 1,
    ResolveGUICollisions: 2,
};

class ViewportPosition {
    /**
     * Clip-scale position, on-screen values are in range of 0 to 1
     * @type {Vector2}
     */
    position = new Vector2();

    /**
     * Fixed offset in pixels
     * @type {Vector2}
     */
    offset = new Vector2();
    /**
     * ranges from 0..1 in both X and Y, controls anchor point of element positioning
     * @type {Vector2}
     */
    anchor = new Vector2(0, 0);


    /**
     * Makes display element avoid overlap with GUI elements
     * @see GUIElement
     * @type {boolean}
     */
    resolveGuiCollisions = false;

    /**
     * How far should the HUD stay away from the edge if it's sticky
     * @see stickToScreenEdge
     * @type {number}
     */
    screenEdgeWidth = 10;


    /**
     * Controls whenever or not HUD should remain on the screen when it gets to the edge
     * @type {boolean}
     */
    stickToScreenEdge = false;

    /**
     * Can be used to enable and disable positioning
     * @type {ObservedBoolean}
     */
    enabled = new ObservedBoolean(true);

    /**
     *
     * @param {ViewportPosition} other
     * @returns {boolean}
     */
    equals(other) {
        return this.position.equals(other.position)
            && this.offset.equals(other.offset)
            && this.anchor.equals(other.anchor)
            && this.resolveGuiCollisions === other.resolveGuiCollisions
            && this.screenEdgeWidth === other.screenEdgeWidth
            && this.stickToScreenEdge === other.stickToScreenEdge
            && this.enabled.equals(other.enabled)
            ;
    }

    hash() {
        return combine_hash(
            this.position.hash(),
            this.offset.hash(),
            this.anchor.hash(),
            this.resolveGuiCollisions ? 1 : 0,
            computeHashFloat(this.screenEdgeWidth),
            this.stickToScreenEdge ? 1 : 0,
            this.enabled.hash()
        );
    }

    fromJSON(
        {
            position = Vector2.zero,
            offset = Vector2.zero,
            anchor = Vector2.zero,
            screenEdgeWidth = 0,
            stickToScreenEdge = false,
            enabled = true,
        }
    ) {
        this.position.fromJSON(position);
        this.offset.fromJSON(offset);
        this.anchor.fromJSON(anchor);
        this.screenEdgeWidth = screenEdgeWidth;
        this.stickToScreenEdge = stickToScreenEdge;
        this.enabled.fromJSON(enabled);
    }

    toJSON() {
        return {
            position: this.position.toJSON(),
            offset: this.offset.toJSON(),
            anchor: this.anchor.toJSON(),
            screenEdgeWidth: this.screenEdgeWidth,
            stickToScreenEdge: this.stickToScreenEdge,
            enabled: this.enabled.toJSON()
        }
    }

    static fromJSON(opt) {
        const p = new ViewportPosition();

        p.fromJSON(opt);

        return p;
    }
}

ViewportPosition.typeName = "ViewportPosition";
ViewportPosition.serializable = true;

export default ViewportPosition;

