module DragDrop {  
    enum Types {
        OneToMany,
        ManyToOne,
        OneToOne,
        BigContainer
    }
    export class DragDrop extends Base.BasicGroup {
        private isExam = false;
        private allPaired = true;
        private groupsEnabled = true;
        private GameData: any;
        private Elements: any;
        private dragElements: any[];
        private containers: any[];
        private containersGroups: any[];
        constructor(game, name, x, y, json) {
            super(game, name, x, y, json);
        }
        init(json) {
            super.init(json);
            this.GameData = json.GameData;
            this.Elements = json.GameData;
        }
        preload() {
            super.preload();
            this.game.load.onLoadComplete.addOnce(this.create, this);
            this.loadGraphics();
            this.game.load.start();
        }
        create() {
            if (this.json.isStandalone) {
                super.create();
            }
            this.createStaticElements();
            this.createContainerElements();
            this.createDragableElements();
            this.loadGroups();
            this.initOptions();
            EU.createFillElements(this);
            EU.createSelectableElements(this);

        }
        initOptions() {
            if (this.GameData.AllPaired === undefined || this.GameData.AllPaired === null)
                this.allPaired = true;
            else
                this.allPaired = this.GameData.AllPaired;
        }
        loadGraphics() {
            for (var i = 0; i < this.GameData.Graphics.length; i++)
                this.game.load.image(this.GameData.Prefix + this.GameData.Graphics[i].key, this.GameData.Graphics[i].src);
        }




        //create static elements frames and elements non interactive
        createStaticElements() {
            var opt = this.GameData.StaticElements.Options;
            var orientation;
            if (opt.Orientation === undefined || opt.Orientation === null) {
                orientation = true;
            } else {
                orientation = opt.Orientation;
            }
            var positions = EU.generateGridPositions(opt.Columns, opt.Rows, opt.MaxWidth, opt.MaxHeight, opt.Spacing, opt.Spacing, opt.StartingPos.x, opt.StartingPos.y, orientation);
            var el;
            var posX;
            var posY;
            for (var i = 0; i < this.GameData.StaticElements.el.length; i++) {
                if (this.GameData.StaticElements.Options.isGrid) {
                    posX = positions[i].x;
                    posY = positions[i].y;
                }
                else {
                    posX = this.GameData.StaticElements.el[i].pos.x;
                    posY = this.GameData.StaticElements.el[i].pos.y;
                }
                if (this.GameData.StaticElements.el.type) {
                    switch (this.GameData.StaticElements.el[i].type) {
                        case "image":
                            el = this.game.add.image(posX, posY, this.GameData.Prefix + this.GameData.StaticElements.el[i].key);
                            break;
                        case "text":
                            el = this.game.add.text(posX, posY, this.GameData.StaticElements.el[i].text, this.GameData.StaticElements.Options.Style);
                            break;
                        case "sound":
                            el = game.game.add.sprite(posX, posY, "speaker");
                            el.inputEnabled = true;
                            el.name = game.Elements.StaticElements.el[i].sound;
                            el.events.onInputUp.add(EU.soundButtonDown, game);
                            break;
                    }
                }
                else 
                    el = this.game.add.image(posX, posY, this.GameData.Prefix + this.GameData.StaticElements.el[i].key);                

                this.addChild(el);
            }
        }
        //create container elements, add to table of containers
        createContainerElements() {
            this.containers = [];
            var el;
            var opt = this.GameData.ContainerElements.Options;
            var positions = EU.generateGridPositions(opt.Columns, opt.Rows, opt.MaxWidth, opt.MaxHeight, opt.Spacing, opt.Spacing, opt.StartingPos.x, opt.StartingPos.y, true);
            for (var i = 0; i < this.GameData.ContainerElements.el.length; i++) {
                if (this.GameData.ContainerElements.Options.isGrid)
                    el = this.game.add.image(positions[i].x, positions[i].y, this.GameData.Prefix + this.GameData.ContainerElements.el[i].key);
                else
                    el = this.game.add.image(this.GameData.ContainerElements.el[i].pos.x, this.GameData.ContainerElements.el[i].pos.y, this.GameData.Prefix + this.GameData.ContainerElements.el[i].key);
                el.name = this.GameData.ContainerElements.el[i].name;
                this.containers.push({
                    "el": el,
                    "startPos": {
                        "x": el.position.x,
                        "y": el.position.y
                    },
                    "name": el.name,
                    "dragElementName": ""
                });
                this.addChild(el);
            }
        }     

        //create dragable elements and set OnInput method 
        createDragableElements() {
            this.dragElements = [];
            var opt = this.GameData.DragableElements.Options;
            var positions = EU.shuffleArray(EU.generateGridPositions(opt.Columns, opt.Rows, opt.MaxWidth, opt.MaxHeight, opt.Spacing, opt.Spacing, opt.StartingPos.x, opt.StartingPos.y, true));
            for (var i = 0; i < this.GameData.DragableElements.el.length; i++) {
                if (this.GameData.DragableElements.Options.isGrid)
                    var el = this.game.add.image(positions[i].x, positions[i].y, this.GameData.Prefix + this.GameData.DragableElements.el[i].key);
                else
                    var el = this.game.add.image(this.GameData.DragableElements.el[i].pos.x, this.GameData.DragableElements.el[i].pos.y, this.GameData.Prefix + this.GameData.DragableElements.el[i].key);
                el.inputEnabled = true;
                el.name = this.GameData.DragableElements.el[i].name;
                el.input.enableDrag();
                el.events.onInputUp.add(this.onInputUp, this);
                el.events.onInputDown.add(this.onInputDown, this);
                this.dragElements.push({
                    "el": el,
                    "startPos": {
                        "x": el.position.x,
                        "y": el.position.y
                    },
                    "paired": false,
                    "correctContainer": this.GameData.DragableElements.el[i].correctContainer,
                    "correctGroup": this.GameData.DragableElements.el[i].correctGroup,
                    "pairedWith": ""
                });
                this.addChild(el);
            }
        }       
        //load groups of containers into containersGroup array
        loadGroups() {
            this.groupsEnabled = this.GameData.GroupsEnabled;
            if (this.groupsEnabled) {
                this.containersGroups = [];
                if (this.GameData.ContainerGroups != undefined);
                for (var i = 0; i < this.GameData.ContainerGroups.length; i++) {
                    var tmp = [];
                    for (var x = 0; x < this.GameData.ContainerGroups[i].el.length; x++) {
                        tmp.push(this.getContainerByName(this.GameData.ContainerGroups[i].el[x].name));
                    }
                    var z = { "name": this.GameData.ContainerGroups[i].name, el: tmp };
                    this.containersGroups.push(z);
                }
            }
        }


        private onInputUp(el: Phaser.Sprite, pointer) {
            var index = this.getCorrespondingContainerIndex(el);
            for (var i = 0; i < this.containers.length; i++) {
                if (this.overlap(el, this.containers[i].el)) {
                    if (this.GameData.DragType != "BigContainer") {
                        if (this.containers[i].dragElementName === "") {
                            this.containers[i].dragElementName = el.name;
                        } else {
                            var oldDrag = this.getDragElementByName(this.containers[i].dragElementName);
                            oldDrag.pairedWith = "";
                            oldDrag.el.bringToTop();
                            var returnTween = this.game.add.tween(oldDrag.el);
                            returnTween.to({ x: oldDrag.startPos.x, y: oldDrag.startPos.y }, 500, Phaser.Easing.Circular.InOut);
                            returnTween.start();
                            this.containers[i].dragElementName = el.name;
                        }
                        el.x = this.containers[i].startPos.x;
                        el.y = this.containers[i].startPos.y;
                    }
                    this.dragElements[index].paired = true;
                    this.dragElements[index].pairedWith = this.containers[i].name;
                    this.checkIfEverythingIsCorrect();
                    
                    return;
                }
            }
            this.dragElements[index].paired = false;
            this.dragElements[index].pairedWith = "";
            EU.Log("game completion set to 0");
            EU.setGameCompletion(this.parent, 0);
            var tw = this.game.add.tween(el);
            tw.to({ x: this.dragElements[index].startPos.x, y: this.dragElements[index].startPos.y }, 500, Phaser.Easing.Circular.InOut);
            tw.start();
        }           
    
        //zwraca tablice z indexem prawidlowego orderu i prawidlowym indexem w szeregu
        private findCorrectOrders(el) {
            var arr = [];
            for (var i = 0; i < this.GameData.DragCorrectOrder.length; i++) {
                for (var j = 0; j < this.GameData.DragCorrectOrder[i].el.length; j++) {
                    if (el === this.GameData.DragCorrectOrder[i].el[j].name) {
                        arr.push(j);
                    }
                }
            }
            return arr;
        }
        private findContainerCorrectOrder(el) {
            var arr = [];
            for (var i = 0; i < this.GameData.ContainerGroups.length; i++) {
                for (var j = 0; j < this.GameData.ContainerGroups[i].el.length; j++) {
                    if (el === this.GameData.ContainerGroups[i].el[j].name) {
                        arr.push(j);
                    }
                }
            }
            return arr;
        }
        
        //input      
        private onInputDown(el: Phaser.Sprite, pointer) {
            if (this.GameData.DragType != "BigContainer")
                this.getDragElementByName(el.name).pairedWith = "";
            for (var i = 0; i < this.containers.length; i++) {
                if (this.overlap(el, this.containers[i].el)) {
                    this.containers[i].dragElementName = "";
                }
            }
            el.bringToTop();
        }
     
        private checkIfEverythingIsCorrect() {
            switch (this.GameData.DragType) {
                case "GroupsWithOrder":
                    this.checkCompletedGroupsWithOrder(this.allPaired);
                    break;
                case "NotAllPaired":
                    this.checkCompletedFilledContainers();
                    break;
                default:
                    this.checkCompleted(this.allPaired);
                    break;
            }
        }
        //AllPaired if true every drag element must have container
        //
        private checkCompleted(allPaired) {
            EU.Log("game completion set to 0");
            EU.setGameCompletion(this.parent, 0);
            var i = 0;
            //if all objects must be paired
            if (allPaired)
                for (i = 0; i < this.dragElements.length; i++) {
                    if (!this.dragElements[i].paired)
                        return false;
                }
            
            //if groups are enabled check every element in group
            if (this.groupsEnabled) {
                for (i = 0; i < this.dragElements.length; i++) {
                    if (!this.isElementInCorrectGroup(this.dragElements[i]))
                        return false;
                }
            }
            else {
                for (i = 0; i < this.dragElements.length; i++) {
                    if (this.dragElements[i].correctContainer !== this.dragElements[i].pairedWith)
                        return false;
                }

            }
            if (EU.checkIfFillsAreCorrect(this)) {
                EU.setGameCompletion(this.parent, 1);
                EU.Log("completed");
            }
        }
        private checkCompletedGroupsWithOrder(allPaired) {
            EU.Log("game completion set to 0");
            EU.setGameCompletion(this.parent, 0);
            var i = 0;
            //if all objects must be paired         
            if (allPaired)
                for (i = 0; i < this.dragElements.length; i++) {
                    if (!this.dragElements[i].paired)
                        return false;
                }
            for (var i = 0; i < this.dragElements.length; i++) {
                var x = this.findCorrectOrders(this.dragElements[i].el.name);
                var y = this.findContainerCorrectOrder(this.dragElements[i].pairedWith);
                for (var j = 0; j < x.length; j++)
                    if (x[j] !== y[j])
                        return false;
            }
            if (EU.checkIfFillsAreCorrect(this)) {
                EU.setGameCompletion(this.parent, 1);
                EU.Log("completed");
            }
        }
        checkCompletedFilledContainers() {
            EU.Log(this.containers);
            for (var i = 0; i < this.containers.length; i++) {
                if (this.containers[i].dragElementName === "")
                    return false;
            }
            for (var i = 0; i < this.containers.length; i++) {
                var temp = this.getDragElementByName(this.containers[i].dragElementName).correctContainer;
                EU.Log(temp);
                if (temp !== this.containers[i].name)
                    return false;

            }
            if (EU.checkIfFillsAreCorrect(this)) {
                EU.setGameCompletion(this.parent, 1);
                EU.Log("completed");
            }
            return true;
        }

        private overlap(a, b) {
            var bA = a.getBounds();
            var bB = b.getBounds();
            return Phaser.Rectangle.intersects(bA, bB);
        }
        private isElementInCorrectGroup(el) {
            for (var i = 0; i < this.containersGroups.length; i++) {
                if (el.correctGroup === "")
                    return true;
                if (this.containersGroups[i].name === el.correctGroup) {
                    for (var j = 0; j < this.containersGroups[i].el.length; j++) {
                        if (this.containersGroups[i].el[j].name === el.pairedWith)
                            return true;
                    }
                }
            }
            return false;
        }
        //return container by name
        private getContainerByName(name) {
            for (var i = 0; i < this.containers.length; i++)
                if (this.containers[i].el.name === name)
                    return this.containers[i].el;
        }
        private getDragElementByName(name) {
            for (var i = 0; i < this.dragElements.length; i++)
                if (this.dragElements[i].el.name === name)
                    return this.dragElements[i];
        }
        //return index of drag Element
        private getCorrespondingContainerIndex(el) {
            for (var i = 0; i < this.dragElements.length; i++) {
                if (el === this.dragElements[i].el)
                    return i;
            }
        }
    }
}


//JSON
//
//     "DragType": "OneToOne",
//"Graphics":
//[
//    { "src": "Graphics/WorkCards/OS_I_2/1/OS_kp_I_2_drag_01.png", "key": "01" },
//    { "src": "Graphics/WorkCards/OS_I_2/1/OS_kp_I_2_drag_02.png", "key": "02" },
//    { "src": "Graphics/WorkCards/OS_I_2/1/OS_kp_I_2_drag_03.png", "key": "03" },
//    { "src": "Graphics/WorkCards/OS_I_2/1/OS_kp_I_2_drag_04.png", "key": "04" },
//    { "src": "Graphics/WorkCards/OS_I_2/1/OS_kp_I_2_drag_05.png", "key": "05" },
//    { "src": "Graphics/WorkCards/OS_I_2/1/OS_kp_I_2_drag_06.png", "key": "06" },
//    { "src": "Graphics/WorkCards/OS_I_2/1/OS_kp_I_2_drag_07.png", "key": "07" },
//    { "src": "Graphics/WorkCards/OS_I_2/1/OS_kp_I_2_drag_08.png", "key": "08" },
//    { "src": "Graphics/WorkCards/OS_I_2/1/OS_kp_I_2_image1.png", "key": "image1" },
//    { "src": "Graphics/WorkCards/OS_I_2/1/OS_kp_I_2_image2.png", "key": "image2" },
//    { "src": "Graphics/WorkCards/OS_I_2/1/OS_kp_I_2_drag_empty.png", "key": "c" },
//],
//"StaticElements": {
//    "el": [
//        { "key": "image1", "pos": { "x": 30, "y": 50 } },
//        { "key": "image2", "pos": { "x": 30, "y": 400 } }
//    ],
//    "Options": {
//        "isGrid": false,
//        "StartingPos": { "x": 20, "y": 30 },
//        "Columns": 4,
//        "Rows": 2,
//        "Spacing": 10
//    }
//},

//"DragableElements": {
//    "el": [
//        { "key": "01", "pos": { "x": 3, "y": 3 }, "name": "O_1", "correctContainer": "C_1", "correctGroup": "group1" },
//        { "key": "02", "pos": { "x": 3, "y": 3 }, "name": "O_2", "correctContainer": "C_1", "correctGroup": "group2" },
//        { "key": "03", "pos": { "x": 3, "y": 3 }, "name": "O_3", "correctContainer": "C_1", "correctGroup": "group2" },
//        { "key": "04", "pos": { "x": 3, "y": 3 }, "name": "O_4", "correctContainer": "C_1", "correctGroup": "group1" },
//        { "key": "05", "pos": { "x": 3, "y": 3 }, "name": "O_5", "correctContainer": "C_1", "correctGroup": "group2" },
//        { "key": "06", "pos": { "x": 3, "y": 3 }, "name": "O_6", "correctContainer": "C_1", "correctGroup": "group1" },
//        { "key": "07", "pos": { "x": 3, "y": 3 }, "name": "O_7", "correctContainer": "C_1", "correctGroup": "group2" },
//        { "key": "08", "pos": { "x": 3, "y": 3 }, "name": "O_8", "correctContainer": "C_1", "correctGroup": "group1" },
//    ],
//    "Options": {
//        "isGrid": true,
//        "StartingPos": { "x": 1050, "y": 0 },
//        "Columns": 2,
//        "Rows": 4,
//        "Spacing": 10,
//        "MaxWidth": 250,
//        "MaxHeight" : 200

//    }
//},
//"ContainerElements": {
//    "el": [
//        { "key": "c", "pos": { "x": 0, "y": 150 }, "name": "C_1" },
//        { "key": "c", "pos": { "x": 250, "y": 150 }, "name": "C_2" },
//        { "key": "c", "pos": { "x": 500, "y": 150 }, "name": "C_3" },
//        { "key": "c", "pos": { "x": 750, "y": 150 }, "name": "C_4" },
//        { "key": "c", "pos": { "x": 0, "y": 500 }, "name": "C_5" },
//        { "key": "c", "pos": { "x": 250, "y": 500 }, "name": "C_6" },
//        { "key": "c", "pos": { "x": 500, "y": 500 }, "name": "C_7" },
//        { "key": "c", "pos": { "x": 750, "y": 500 }, "name": "C_8" },
//    ],
//    "Options": {
//        "isGrid": false,
//        "StartingPos": { "x": 20, "y": 300 },
//        "Columns": 4,
//        "Rows": 2,
//        "Spacing": 10

//    }
//},
//"ContainerGroups":
//[
//    { "name": "group1", "el": [{ "name": "C_1" }, { "name": "C_2" }, { "name": "C_3" }, { "name": "C_4" }] },
//    { "name": "group2", "el": [{ "name": "C_5" }, { "name": "C_6" }, { "name": "C_7" }, { "name": "C_8" }] }
//]

//            };




/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////            FORMAT JSONA           ////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//    JSON = {
//              completeText: "caly tekst do wyswietlenia",
//              searched: [["znak lub wyraz", (true/false || true szuka znaku lub wyrazu oddzielonego spacjami, kropka, myslnikiem lub cudzyslowiem; false szuka podciągu)], [], []]    
//           } 



