import {Segment} from "./Segment";
import {Helper} from "../../../../../../js/lib/pwa-lib";

export class ParentSegment extends Segment {
    static initListener() {
        window.addEventListener("mousedown", (e) => {
            ParentSegment.mouseDownTarget = e.target;
            ParentSegment.clickPosition = {x: e.pageX, y: e.pageY};
        });
        window.addEventListener("mouseup", (e) => {
            ParentSegment.mouseDownTarget = null;
            ParentSegment.clickPosition = {};
        });

        window.addEventListener("touchstart", (e) => {
            if (e.targetTouches.length === 1) {
                ParentSegment.mouseDownTarget = e.targetTouches[0].target;
                ParentSegment.clickPosition = {x: e.targetTouches[0].pageX, y: e.targetTouches[0].pageY};
            }
            // else if (Array.isArray(e.path) && e.path.length >= 1) {
            //     ParentSegment.mouseDownTarget = e.path[0];
            //     ParentSegment.clickPosition = null;
            // }
        });
        window.addEventListener("touchend", (e) => {
            ParentSegment.mouseDownTarget = null;
            ParentSegment.clickPosition = {};
        });
    }

    setIsRotatable(rotatable) {
        this.rotatable = rotatable;
        this._updateElement();
    }

    constructor(element) {
        super(element);
        this.children = [];
        this.class = "rotate-0";
        this.rotatable = true;

        this.userRotationDelta = 100;
        this.lastUserRotation = 0;

        let self = this;
        this.touchendListener = function (e) {
            let now = new Date().getTime();

            // console.log("touchendListener", e,now, self.lastUserRotation);
            let target = null;
            let position = null;

            if (e.changedTouches.length >= 1) {
                target = document.elementFromPoint(e.changedTouches[0].pageX, e.changedTouches[0].pageY);
                position = {x: e.changedTouches[0].pageX, y: e.changedTouches[0].pageY};
            }
            if (target != null && e.targetTouches.length === 0 && self.element.contains(ParentSegment.mouseDownTarget) && self.element.contains(target)) {
                e.stopPropagation();
                e.preventDefault();
                if (self.lastUserRotation+self.userRotationDelta > now){
                    return;
                }
                self.getLevel().segmentClickedListener(self);
                self.rotate(ParentSegment.mouseDownTarget, target, ParentSegment.clickPosition, position);
                // console.log("touchendListener stopped event", e);

                self.lastUserRotation = new Date().getTime();
            }
        };
        this.mouseupListener = function (e) {
            let now = new Date().getTime();
            // console.log("mouseupListener", e,now, self.lastUserRotation);

            if (ParentSegment.mouseDownTarget !== null && self.element.contains(ParentSegment.mouseDownTarget) && self.element.contains(e.target)) {
                let position = {x: e.pageX, y: e.pageY};
                e.stopPropagation();
                e.preventDefault();
                if (self.lastUserRotation+self.userRotationDelta > now){
                    return;
                }
                self.getLevel().segmentClickedListener(self);
                self.rotate(ParentSegment.mouseDownTarget, e.target, ParentSegment.clickPosition, position);
                // console.log("mouseupListener stopped event", e);
                self.lastUserRotation = new Date().getTime();
            }
        };
    }

    canRotate() {
        return (this.rotatable && !this.getLevel().getHasWon());
    }

    async rotate(firstElem, secondElem, firstPosition, secondPosition) {
        const timeout = 250;
        const clickTolerance = 5;

        let rotationDirection = 1;
        if (Helper.isNotNull(secondElem) && Helper.isNotNull(firstElem) &&
            (Helper.isNull(firstPosition) || Helper.isNull(secondPosition) ||
                Math.abs(firstPosition.x - secondPosition.x) > clickTolerance ||
                Math.abs(firstPosition.y - secondPosition.y) > clickTolerance)) {

            let firstIndex = -1;
            let secondIndex = -1;
            let rotationIndexes = [0, 1, 3, 2];
            for (let i = 0; i < this.children.length; i++) {
                if (this.children[rotationIndexes[i]].element === firstElem || this.children[rotationIndexes[i]].element.contains(firstElem)) {
                    firstIndex = (i + this.rotation / 90) % 4;
                }
                if (this.children[rotationIndexes[i]].element === secondElem || this.children[rotationIndexes[i]].element.contains(secondElem)) {
                    secondIndex = (i + this.rotation / 90) % 4;
                }
            }

            if (firstIndex >= 0 && secondIndex >= 0) {
                if (firstIndex === 2 && (secondIndex === 0 || secondIndex === 1)
                    || firstIndex === 1 && (secondIndex === 0 || secondIndex === 3)
                    || (firstIndex === 0 && secondIndex === 3)
                    || (firstIndex === 3 && secondIndex === 2)) {
                    rotationDirection = -1;
                }
            }
        }

        if (this.canRotate()) {
            this.rotation += 360 + 90 * rotationDirection;
            this.rotation %= 360;

            let currentRotation = this.rotation;

            this._updateRotationClass();
            this.element.classList.add("rotating");
            if (rotationDirection === -1) {
                this.element.classList.add("reverse");
            }

            let delayPromise = new Promise(function (resolve) {
                setTimeout(resolve, timeout);
            }).then(() => {
                if (this.rotation === currentRotation) {
                    this.element.classList.remove("rotating");
                    this.element.classList.remove("reverse");
                }
            });
            this.getLevel().checkHasWon(delayPromise);
            return delayPromise;
        }
    }

    sameAs(otherSegment) {
        if (!(otherSegment instanceof ParentSegment) || otherSegment.children.length !== this.children.length) {
            return false;
        }
        for (let i = 0; i < this.children.length; i++) {
            if (!this.children[i].sameAs(otherSegment.children[i])) {
                return false;
            }
        }
        return true;
    }

    applyRotations(rotations) {
        this.rotation = rotations[0];

        if (isNaN(this.rotation)) {
            this.rotation = 0;
        }

        rotations.splice(0, 1);
        for (let i = 0, n = this.children.length; i < n; i++) {
            rotations = this.children[i].applyRotations(rotations);
        }
        return rotations;
    }

    applyLocks(locks) {
        this.rotatable = locks[0];
        locks.splice(0, 1);
        for (let i = 0, n = this.children.length; i < n; i++) {
            locks = this.children[i].applyLocks(locks);
        }
        return locks;
    }

    getCurrentRotations(rotations) {
        rotations.push(this.rotation);
        for (let i = 0, n = this.children.length; i < n; i++) {
            rotations = this.children[i].getCurrentRotations(rotations);
        }
        return rotations;
    }

    getCurrentLocked(locked) {
        locked.push(this.rotatable);
        for (let i = 0, n = this.children.length; i < n; i++) {
            locked = this.children[i].getCurrentLocked(locked);
        }
        return locked;
    }

    isSolved(checkChildren) {
        checkChildren = Helper.nonNull(checkChildren, true);
        if (checkChildren) {
            for (let i = 0, n = this.children.length; i < n; i++) {
                if (!this.children[i].isSolved()) {
                    return false;
                }
            }
        }
        return (this.rotation === 0 || (
            this.children[0].sameAs(this.children[3]) && this.children[1].sameAs(this.children[2]) && (
            this.rotation === 180 || this.children[0].sameAs(this.children[1]))))
    }

    setChildren(children) {
        this.children = [];
        for (let i = 0, n = children.length; i < n; i++) {
            this.addChild(children[i]);
        }
    }

    addChild(child) {
        this.children.push(child);
        child.setParent(this);
        this._updateElement();
    }

    _updateRotationClass() {
        // this.style.transform = "rotate("+this.rotation+"deg)";
        this.element.classList.remove(this.class);
        this.class = "rotate-" + this.rotation;
        if (this.class === "rotate-0") {
            this.class = "rotate-360";
        }
        this.element.classList.add(this.class);
    }

    _updateElement() {
        let layer = this._getLayer();
        if (layer >= 2) {
            this.element.classList.add("layer-" + layer);
        }

        if (!this.rotatable) {
            this.element.classList.add("locked");
        }

        const childContainer = this.element.querySelector(".child-container");
        childContainer.removeAllChildren();

        this._updateRotationClass();

        this.element.removeEventListener("mouseup", this.mouseupListener);
        this.element.removeEventListener("touchend", this.touchendListener);

        this.element.addEventListener("mouseup", this.mouseupListener);
        this.element.addEventListener("touchend", this.touchendListener);

        for (let i = 0, n = this.children.length; i < n; i++) {
            this.children[i]._updateElement();
            childContainer.appendChild(this.children[i].getElement());
            if (i % 2 === 1 && this.children.length - 1 !== i) {
                childContainer.appendChild(document.createElement("br"));
            }
        }
    }

    _getLayer() {
        if (this.children.length >= 1 && this.children[0] && this.children[0] instanceof ParentSegment) {
            return this.children[0]._getLayer() + 1;
        }
        return 1;
    }
}

ParentSegment.initListener();