module CharacterCreation {
    interface rangeOptions {
        label? : string;
        showValue? : boolean;
        onChange : (value : number, labelValue : Text, input : HTMLInputElement) => void;
        minValue : number;
        maxValue : number;
        leftLabel? : string;
        rightLabel? : string;
        topLabel? : string;
        value : number;
        step : number;
    }

    function createRange (options : rangeOptions) {
        let valueNode = document.createTextNode(String(options.value));

        let div = document.createElement("div");
        div.classList.add("ccOption");
        if (options.topLabel != undefined) {
            let topLabel = document.createElement("div");
            topLabel.classList.add("ccOptionTopLabel");
            topLabel.appendChild(document.createTextNode(options.topLabel + ":"));
            div.appendChild(topLabel);
        }

        let label = document.createElement("div");
        if (options.showValue != false) {
            label.classList.add("rangeValue");
            if (options.label != undefined) {
                let b = document.createElement("b");
                b.appendChild(document.createTextNode(options.label + ": "));
                label.appendChild(b);
            }
            label.appendChild(valueNode);
        }

        let input = <HTMLInputElement> document.createElement("input");
        input.classList.add("ccRange");
        input.type = "range";
        input.min = options.minValue.toString();
        input.max = options.maxValue.toString();
        input.step = options.step.toString();
        input.value = options.value.toString();

        let onChange = () => {
            valueNode.nodeValue = input.value;
            options.onChange(Number(input.value), valueNode, input);
        }

        input.addEventListener("change", onChange);

        let leftButton = document.createElement("a");
        leftButton.classList.add("ccButton");
        leftButton.addEventListener("click", () => {
            input.value = String(Number(input.value) - options.step);
            onChange();
        });
        Controls.KeyHandler.applyCode(leftButton, Controls.KeyHandler.getFirstKeyCode());
        if (options.leftLabel != undefined) {
            leftButton.appendChild(document.createTextNode(options.leftLabel));
        }

        let rightButton = document.createElement("a");
        rightButton.classList.add("ccButton");
        rightButton.addEventListener("click", () => {
            input.value = String(Number(input.value) + options.step);
            onChange();
        });
        Controls.KeyHandler.applyCode(rightButton, Controls.KeyHandler.getFirstKeyCode());;
        if (options.rightLabel != undefined) {
            rightButton.appendChild(document.createTextNode(options.rightLabel));
        }

        div.appendChild(leftButton);
        div.appendChild(input);
        div.appendChild(rightButton);
        div.appendChild(label);

        onChange();

        return div;
    }

    export let CCSexStats = CharacterCreation.rulebook.createAndAddRule({
        name : "Character Creation - Sex and Stats",
        firstPriority : Rule.PRIORITY_HIGH,
        priority: Rule.PRIORITY_HIGH,
        code : () => {
            Elements.startMenu();

            let ccDiv = document.createElement("div");
            ccDiv.id = "characterCreation";

            let ccLeft = document.createElement("div");
            ccLeft.id = "ccLeft";
            ccDiv.appendChild(ccLeft);

            let ccRight = document.createElement("div");
            ccRight.id = "ccRight";
            ccDiv.appendChild(ccRight);

            let onChange = () => {
                (new Say(WorldState.player.description)).getHTMLContent().then((value => {
                    while (ccRight.firstChild) ccRight.removeChild(ccRight.firstChild);
                    value.forEach(val => {
                        ccRight.appendChild(val);
                    });
                }));
            };

            ccLeft.appendChild(createRange({
                minValue : 0, maxValue : 1, step: 1, value : 0, leftLabel : "Male", rightLabel : "Female", topLabel : "Sex",
                onChange : (value : number, labelValue : Text, input : HTMLInputElement) => {
                    labelValue.nodeValue = (value == 0 ? "Male" : "Female");
                    (<Humanoid> WorldState.player).removeGenderedParts();
                    if (value == 0) {
                        (<Humanoid> WorldState.player).addMaleParts();
                    } else {
                        (<Humanoid> WorldState.player).addFemaleParts();
                    }
                    // Some stats become different whether te player is male or female, so we have to update them all.
                    let otherInputs = ccDiv.getElementsByTagName("input");
                    for (let i = 0; i < otherInputs.length; i++) {
                        let otherInput = otherInputs[i];
                        if (otherInput != input) {
                            otherInput.dispatchEvent(new Event("change"));
                        }
                    }
                    onChange();
                }
            }));



            ccLeft.appendChild(createRange({
                minValue : 0, maxValue : 4, step: 1, value : 2, leftLabel : "Masculine", rightLabel : "Feminine", topLabel : "Gender",
                onChange : (value : number, labelValue : Text) => {
                    let names = ["Masculine", "Somewhat masculine", "Androgynous", "Somewhat feminine", "Feminine"];
                    labelValue.nodeValue = names[value];
                    let player = (<Humanoid> WorldState.player);
                    let intendedValue : number;
                    if (player.isMale()) {
                        let values = [10, 25, 50, 55, 60];
                        intendedValue = values[value];
                    } else {
                        let values = [35, 40, 50, 65, 75];
                        intendedValue = values[value];
                    }
                    (<Humanoid> WorldState.player).setGenderValue(intendedValue);
                    WorldState.player.setStat(Attributes.GenderIdentity, intendedValue);
                    onChange();
                }
            }));

            let statsHeader = document.createElement("div");
            ccLeft.appendChild(statsHeader);
            statsHeader.classList.add("ccHeader");
            statsHeader.appendChild(document.createTextNode("Stats ("));

            let maxStats = 12;
            let statsRemaining = document.createTextNode("4 points remaining");


            statsHeader.appendChild(statsRemaining);
            statsHeader.appendChild(document.createTextNode(")"));

            let setStat = (attr : Attribute, value : number, input : HTMLInputElement) => {
                player.setStat(attr, value);
                let remaining = maxStats
                    - player.getStat(Attributes.Strength)
                    - player.getStat(Attributes.Agility)
                    - player.getStat(Attributes.Intelligence)
                    - player.getStat(Attributes.Charm);

                if (remaining < 0) {
                    value += remaining;
                    remaining = 0;
                    input.value = value.toString();
                    input.dispatchEvent(new Event("change"));
                    return;
                }

                statsRemaining.nodeValue = (remaining == 0 ? "Done" :
                    remaining > 1 ? remaining.toString() + " points remaining" :
                    remaining.toString() + " point remaining");
            };

            ccLeft.appendChild(createRange({
                minValue : 1, maxValue : 5, step: 1, value : 2, leftLabel : "-", rightLabel : "+", topLabel : "Strength",
                onChange : (value : number, labelValue : Text, input : HTMLInputElement) => {
                    setStat(Attributes.Strength, value, input);
                    onChange();
                }
            }));

            ccLeft.appendChild(createRange({
                minValue : 1, maxValue : 5, step: 1, value : 2, leftLabel : "-", rightLabel : "+", topLabel : "Agility",
                onChange : (value : number, labelValue : Text, input : HTMLInputElement) => {
                    setStat(Attributes.Agility, value, input);
                    onChange();
                }
            }));

            ccLeft.appendChild(createRange({
                minValue : 1, maxValue : 5, step: 1, value : 2, leftLabel : "-", rightLabel : "+", topLabel : "Charm",
                onChange : (value : number, labelValue : Text, input : HTMLInputElement) => {
                    setStat(Attributes.Charm, value, input);
                    onChange();
                }
            }));

            ccLeft.appendChild(createRange({
                minValue : 1, maxValue : 5, step: 1, value : 2, leftLabel : "-", rightLabel : "+", topLabel : "Intelligence",
                onChange : (value : number, labelValue : Text, input : HTMLInputElement) => {
                    setStat(Attributes.Intelligence, value, input);
                    onChange();
                }
            }));

            let creationDone = new Promise((resolve) => {
                (new Say("Confirm")).getHTML("p", ["choice"]).then(elementArray => {
                    elementArray[0].addEventListener("click", () => {
                        Elements.endMenu();
                        resolve();
                    });
                    Controls.KeyHandler.applyCode(elementArray[0], Controls.KeyHandler.getSecondKeyCode());
                    Elements.CurrentTurnHandler.print(elementArray[0]);
                });
            });

            Elements.CurrentTurnHandler.print(ccDiv);

            return creationDone;
        }
    });


    // TODO: Pick origin
    // TODO: Pick Perks
}