var charFlip = function (object)
{
    var game = true;

    // Imagesources to load
    var sources = {
        bg: 'img/bg.png',
        bgTwo: 'img/bg2.png'
    };

    // Load imagesources before game starts
    loadImages(sources, function (images)
    {
        // Create new charFlipGame until a board without any correct rows are found.
        while (game)
        {
            approve = new charFlipGame(object.id, object.possible, object.anagrams, images);
            game = approve.check;
        }

    });


}

// Loads images to KineticJS imageobject.
function loadImages(sources, callback)
{
    var images = {};
    var loadedImages = 0;
    var numImages = 0;
    // get num of sources
    for (var src in sources)
    {
        numImages++;
    }
    for (var src in sources)
    {
        images[src] = new Image();
        images[src].onload = function ()
        {
            if (++loadedImages >= numImages)
            {
                callback(images);
            }
        };
        images[src].src = sources[src];
    }
}

function charFlipGame(id, possible, anagram, images)
{

    _this = this;

    this.images = images;

    // All letters that correct letters can be changed with.
    this.possible = possible;

    // Correct answer of letters in multidimensional array.
    this.charArray = anagram;

    // Clone of charArray. This changes when user play.
    this.playBoard = this.clones(this.charArray);

    // Number of char boxes in vertical rows.
    this.height = this.charArray.length;

    // Number of char boxes in horizontal rows.
    this.width = this.charArray[1].length;

    // Width of boxes in px
    this.boxWidth = 60;

    // Box font-size
    var fontSize = 50;

    // Height of canvas in px. Add 200 for finish text.
    var canvasHeight = (this.boxWidth * this.height) + 200;

    // Width of canvas in px. Add 400 for finish text.
    var canvasWidth = (this.boxWidth * this.width) + 400;

    // Count of clicks. This shows up on game finish.
    this.countClick = 0;

    // Time stamp of game start.
    this.gameStart = new Date();

    // Create array with KineticJS rect objects
    this.rectArray = new Array(this.width);
    for (var i = 0; i < this.height; i++)
    {
        this.rectArray[i] = new Array(this.width);
    }

    // New KineticJS stage.
    this.stage = new Kinetic.Stage(
    {
        container: id,
        width: canvasWidth,
        height: canvasHeight
    });

    // Stores current x position and y position of group, and keeps x position centered.
    this.centeredX = (canvasWidth - (this.boxWidth * this.width)) / 2;

    var xPos = this.centeredX;
    var yPos = 0;

    // These are used for storing the two char values for each box.
    var mainChar = '';
    var secondChar = '';

    // Loop through all chars in multidimensional array and draw all in group with boxes.
    for (var i = 0; i < this.height; i++)
    {
        for (var b = 0; b < this.width; b++)
        {
            var layer = new Kinetic.Layer();

            var settings = {
                scaleX: 1,
                scaleY: 1,
                x: xPos,
                y: yPos,
                id: i + ',' + b
            };

            var group = new Kinetic.Group(settings);

            // Store settings for later reset
            group.settings = settings;

            // This choose if box should be right or wrong on start. 35% probability for right, and 65 for wrong.
            var chosenValue = Math.random() < 0.35 ? true : false;


            if (chosenValue)
            {
                var mainChar = this.charArray[i][b];
                var secondChar = this.getRandomChar(this.charArray[i][b]);
            }
            else
            {
                var mainChar = this.getRandomChar(this.charArray[i][b]);
                var secondChar = this.charArray[i][b];

                // This updates playBoard to correct startup values.
                this.playBoard[i][b] = mainChar;
            }

            // Create unique ides for rect object.
            var idr = i + '' + b + 'r';

            // KineticJS Objects
            var complexText = new Kinetic.Text(
            {
                text: mainChar,
                fontSize: fontSize,
                fontFamily: 'helvetica',
                fill: 'black',
                width: this.boxWidth,
                y: 5,
                align: 'center'
            });

            var yellowHex = new Kinetic.Rect(
            {
                fillPatternImage: this.images.bg,
                id: idr,
                width: this.boxWidth,
                height: this.boxWidth,
                stroke: 'black',
                strokeWidth: 2
            });

            // Populating rectArray with objects.
            this.rectArray[i][b] = yellowHex;

            // Group rect and text together.
            group.add(yellowHex);
            group.add(complexText);

            // Add group to a layer and store complexText pointer in that object.
            layer.add(group);
            layer.txt = complexText;

            // Add layer to stage.
            this.stage.add(layer);

            // This changes on all groups that are a part of horizontal or vertical found answer.
            group.found = false;

            // This changes when current group are flipping.
            group.active = false;

            // If the group are flipped from start up position or not.
            group.flipped = false;

            // Store center x in group object. This is later used for correct KineticJS flip animation.
            group.centerX = group.getAbsolutePosition().x + 25;

            // Store both chars in group object.
            group.chars = [mainChar, secondChar];

            // Create tween for hovering
            group.tween = new Kinetic.Tween(
            {
                node: group,
                scaleX: 0.9,
                x: xPos + 1.8,
                duration: 0.05
            });
            // Changes pointer when hovering.
            group.on('mouseover', function ()
            {
                if (!this.active && !this.found)
                {
                    this.tween.play();
                }
                document.body.style.cursor = 'pointer';
            });

            group.on('mouseleave', function ()
            {
                if (!this.active && !this.found)
                {
                    this.tween.reverse();
                }
                document.body.style.cursor = 'default';
            });

            // Flip group when clicked or touched.
            group.on('mousedown touchstart', function ()
            {
                // Dont flip if group is allready fliping or if its a port of a finished row.
                if (!this.active && !this.found)
                {
                    _this.countClick++;
                    _this.flip(this);
                }

            });

            // Controls the right x and y position of next group to be made.
            xPos += this.boxWidth;
            if (b === (this.width - 1))
            {
                yPos += this.boxWidth;
                xPos = this.centeredX;
            }

        }
    }

    this.check = this.checkAnswer();
}

// Function used for cloning array.
charFlipGame.prototype.clones = function (obj)
{
    if (obj == null || typeof (obj) != 'object') return obj;

    var temp = obj.constructor(); // changed
    for (var key in obj)
        temp[key] = this.clones(obj[key]);
    return temp;
}

// Get random number between interval
charFlipGame.prototype.getRandomArbitary = function (min, max)
{
    return Math.random() * (max - min) + min;
}

// This function choose an random char that is different from correct answer char.
charFlipGame.prototype.getRandomChar = function (char)
{
    var possible = this.possible;
    var text = char;
    while (text == char)
    {
        text = possible.charAt(Math.floor(Math.random() * possible.length));
    }

    return text;
}

// Function for flipping char with a KineticJS Animation
charFlipGame.prototype.flip = function (group)
{
    var _this = this;

    // Get current x,y value from id.
    var cord = group.id().split(',');

    // Get parent layer to group.
    var layer = group.getParent();

    // Variabels that controls flip animation.
    var period = 1800;
    var amplitude = 25;
    var centerX = group.centerX;

    // Stores value about if the char is changed or not.		
    var flipped = false;

    // This group is now active.
    group.active = true;

    // New KineticJS Animation object.
    var anim = new Kinetic.Animation(function (frame)
    {
        // Calculating some data about amount to scale x. 
        var scale = Math.sin(frame.time * 2 * Math.PI / period);

        group.scale(
        {
            x: Math.round(scale * 100) / 100,
            y: 1
        });

        // Scaling x makes x position change. Move back x position.
        group.setX(amplitude * Math.sin(frame.time * -2 * Math.PI / period) + centerX);

        // This variable get value 1 when flipping is finished.
        var rounded = Math.round(scale * 10) / 10;
        var grFlipped = group.flipped;

        if (rounded === 1)
        {
            // Set group back to old settings
            group.setAttrs(group.settings);

            if (grFlipped)
            {
                group.flipped = false;
            }
            else
            {
                group.flipped = true;
            }

            // Change back active status.
            group.active = false;

            // Stop animation.
            this.stop();
            // Check if any row has correct answer.
            _this.checkAnswer();
        }

        if (!flipped)
        {
            if (!grFlipped)
            {
                // Set new char.
                layer.txt.setText(group.chars[1]);

                // Update playBoard.
                _this.playBoard[cord[0]][cord[1]] = group.chars[1];
                flipped = true;
            }
            else if (grFlipped)
            {
                // Set new char.
                layer.txt.setText(group.chars[0]);

                // Update playBoard.
                _this.playBoard[cord[0]][cord[1]] = group.chars[0];
                flipped = true;
            }



        }


    }, layer);

    // Start animation
    anim.start();

}

charFlipGame.prototype.writeMessage = function ()
{

    _this = this;
    // Timestamp of game end.
    var end = new Date();

    var secondsElapsed = (end - this.gameStart) / 1000;

    // Write with min or only seconds.
    if (secondsElapsed > 60)
    {
        var minutes = Math.floor(secondsElapsed / 60);
        var seconds = secondsElapsed - minutes * 60;
        var message = "Congratulations! \n You made it in " + Math.round(minutes) + " min and " + Math.round(seconds) + " sec with " + this.countClick + " clicks.";
    }
    else
    {
        var message = "Congratulations! \n  You made it in " + Math.round(secondsElapsed) + " sec with " + this.countClick + " clicks.";
    }

    // New KineticJS text object
    var char = new Kinetic.Text(
    {
        x: _this.centeredX,
        padding: 4,
        text: message,
        fontSize: 30,
        fontFamily: 'helvetica',
        fill: '#FFFFFF',
        width: _this.boxWidth * _this.width,
        align: 'center',
        lineHeight: 1.5
    });

    // Create new KineticJS layer.
    var layerd = new Kinetic.Layer();
    // Add KineticJS text object to that layer.
    layerd.add(char);
    // Add this layer to stage.
    this.stage.add(layerd);

}

// Function that do a group fade out animation when game finished.
charFlipGame.prototype.animateFinish = function ()
{
    var _this = this;

    // Loop through all groups and create a KineticJS fade out animation.
    for (var i = 0; i < this.height; i++)
    {
        for (var o = 0; o < this.width; o++)
        {
            var rec = this.rectArray[i][o];
            var group = rec.getParent();

            var tweens = new Kinetic.Tween(
            {
                duration: _this.getRandomArbitary(0, 1),
                node: group,
                opacity: 0,
                easing: Kinetic.Easings.EaseIn
            });

            tweens.play();

        }
    }

    _this.writeMessage();

}


charFlipGame.prototype.colorRightAnswer = function (rec)
{
    _this = this;

    var group = rec.getParent();
    group.found = true;

    // Change background to blue
    rec.setAttr('fillPatternImage', this.images.bgTwo);
    // Draw group
    group.draw();
}

// This function is called when a letter is flipped. It checks for right answers.
charFlipGame.prototype.checkAnswer = function ()
{
    // This one is used for determine if game is finished.
    var answerCount = 0;

    answerFound = false;

    // Loop through all vertical groups and check for correct answers.
    for (var i = 0; i < this.height; i++)
    {
        var stringH = '';
        var answer = '';

        for (var b = 0; b < this.width; b++)
        {

            stringH += this.playBoard[i][b];
            answer += this.charArray[i][b];

        }

        if (stringH === answer)
        {
            for (var o = 0; o < this.width; o++)
            {
                var rec = this.rectArray[i][o];
                this.colorRightAnswer(rec);
            }
            answerCount++;
            answerFound = true;
        }

    }

    // Loop through all horizontal groups and check for correct answers.
    for (var i = 0; i < this.width; i++)
    {
        var stringV = '';
        var answer = '';

        for (var b = 0; b < this.height; b++)
        {

            stringV += this.playBoard[b][i];
            answer += this.charArray[b][i];

        }

        if (stringV === answer)
        {
            for (var o = 0; o < this.height; o++)
            {
                var rec = this.rectArray[o][i];

                this.colorRightAnswer(rec);
            }
            answerCount++;
            answerFound = true;
        }

    }

    // Game is finished if amount of correct rows are the same as width + height. 
    if (answerCount === (this.width + this.height))
    {
        // Start finished game animation.
        this.animateFinish();

    }

    return answerFound;

}