/// <reference path="../Elements.ts" />
/// <reference path="../../Controls/Modules/KeyHandler.ts" />
module Elements.CurrentTurnHandler {
    export var currentTurnTab = <HTMLElement> document.getElementById("currentTurnTab");
    export var currentTurn = <HTMLElement> document.getElementById("currentTurn");
    export var turnHr = document.createElement("p");
    export var lastReadOffset = currentTurnTab.clientHeight / 2;
    turnHr.classList.add("turnStart");
    turnHr.appendChild(document.createTextNode("Start of Turn"));

    /**
     * Creates the "Start of Turn" elements and scrolls the content panel until the start of the new turn.
     */
    export function startTurn (action? : Action) {

        let oldContent = currentTurnTab.getElementsByClassName("content");
        for (let i = 0; i < oldContent.length; i++) {
            oldContent[i].classList.add("contentOld");
            oldContent[i].classList.remove("content");
        }

        currentTurnTab.appendChild(turnHr);

        Elements.startTurn();

        scrollToNewTurn();
    }

    /**
     * Are we in the middle of a turn?
     */
    export function isTurn () {
        return Elements.isInTurn();
    }

    /**
     * Removes the blur effect around the turn panel
     */
    export function endTurn () {
        Elements.endTurn();
    }

    export function getSayElementsAsContent (say : Say) : Promise<Array<HTMLElement>> {
        return say.getHTML("p", ["content"]);
    }

    /**
     * Prints given Say directly
     * @param say
     */
    export function printAsContent (say : Say) {
        let node = getMarker();
        getSayElementsAsContent(say).then(value => {
            insertBefore(value, node);
            unprint(node);
        });
    }

    /**
     * Creates a say for sayValues and then prints it as content.
     * @param sayValues
     */
    export function simplePrint (...sayValues : Array<any>) {
        printAsContent(new Say(...sayValues));
    }

    export function printAsError (msg : Say | string) {
        if (msg instanceof Say) {
            msg.getHTML("div", ["error"], true).then(value => {
                print(...value);
            });
        } else {
            let div = document.createElement("div");
            div.classList.add("error");
            div.appendChild(document.createTextNode(msg));
            print(div);
        }
    }

    export function clear () {
        while (currentTurnTab.firstChild != undefined) {
            currentTurnTab.removeChild(currentTurnTab.firstChild);
        }
        Controls.KeyHandler.reset();
    }

    /**
     * Includes the given elements as content.
     * This is the only correct way of printing elements.
     * @param elements
     */
    export function print (...elements : Array<Node>) {
        if(elements.length > 0) {
            elements.forEach((element) => {
                currentTurnTab.appendChild(element);
            });

            scrollTo(lastReadOffset);
        }
    }

    export function getMarker () {
        let node = document.createTextNode("");
        currentTurnTab.appendChild(node);
        return node;
    }

    export function insertBefore (newChilds : Array<Node>, oldChild) {
        newChilds.forEach((newChild) => {
            currentTurnTab.insertBefore(newChild, oldChild);
        });
        scrollTo(lastReadOffset);
    }

    /**
     * Removes elements that have been printed in the past.
     * @param elements
     */
    export function unprint (...elements : Array<Node>) {
        elements.forEach((element) => {
            if (element.parentElement == currentTurnTab) {
                currentTurnTab.removeChild(element);
            }
        });
    }

    /**
     * Scrolls to the first current turn element. (Or rather, to just after the Start of Turn element)
     * This is used internally as a new turn begins.
     */
    export function scrollToNewTurn () {
        let target = turnHr.offsetTop + turnHr.offsetHeight;
        lastReadOffset = target;

        //turnHr.scrollIntoView({behavior : "smooth", block : "start"});
        if (target < currentTurn.scrollTop) {
            return; // We don't want to scroll UP.
        }

        scrollTo(target);
    }

    /**
     * Scrolls to the very bottom of the content panel.
     */
    export function scrollToBottom () {
        scrollTo(currentTurn.scrollHeight - currentTurn.clientHeight);
    }

    /**
     * Scroll half a screen forward
     */
    export function scrollSpace () {
        scrollTo(currentTurn.scrollTop + (currentTurn.clientHeight / 2));
    }

    /**
     * Update text that was read as player scrolls
     */
    currentTurn.addEventListener("scroll", () => {
        let currentRead = currentTurn.scrollTop + currentTurn.clientHeight;
        if (currentRead > lastReadOffset) {
            lastReadOffset = currentRead;
        }
    });


    /**
     * Animation... removing jquery
     */
    var startOffset : number;
    var targetOffset : number;
    var startTime : number;
    var finishTime : number;
    var totalTime : number;
    var animationRequest : number;

    export function scrollTo (offset : number) {
        if (offset <= lastReadOffset) {
            startOffset = currentTurn.scrollTop;
            targetOffset = offset;
            startTime = new Date().getTime();
            finishTime = startTime + Elements.animationTime;
            totalTime = finishTime - startTime;
            startScrolling();
        }
    }

    export function startScrolling () {
        if (animationRequest == undefined) {
            animationRequest = requestAnimationFrame(updateFrame);
        }
    }

    export let updateFrame = () => {
        animationRequest = undefined;

        let movingOffset = (targetOffset - startOffset);
        let timePassed = new Date().getTime() - startTime;
        let idealOffset = movingOffset * (timePassed / totalTime);

        let maxScroll = currentTurn.scrollHeight - currentTurn.clientHeight;

        currentTurn.scrollTop = startOffset + idealOffset;

        if (currentTurn.scrollTop < targetOffset && currentTurn.scrollTop < maxScroll) {
            startScrolling();
        }
    }
}