﻿/* Copyright © Jon Howson 2011
/*
/**********************************************************************************************************/
(function (sunshine, $, undefined)
{

    /* Form manager
    /**********************************************************************************************************/
    (function (manager, $, undefined)
    {
        manager.buttons = [],
        manager.checkBoxes = [],
        manager.dropDownLists = [],
        manager.radioButtons = [],
        manager.radioButtonGroups = [],
        manager.textBoxes = []

        manager.get = function (formIdentifier)
        {
            var _this = this;

            for (var i = 0; i < _this.buttons.length; i++)
            {
                if (_this.buttons[i].formIdentifier == formIdentifier)
                    return _this.buttons[i];
            }

            for (var i = 0; i < _this.checkBoxes.length; i++)
            {
                if (_this.checkBoxes[i].formIdentifier == formIdentifier)
                    return _this.checkBoxes[i];
            }

            for (var i = 0; i < _this.dropDownLists.length; i++)
            {
                if (_this.dropDownLists[i].formIdentifier == formIdentifier)
                    return _this.dropDownLists[i];
            }

            for (var i = 0; i < _this.radioButtons.length; i++)
            {
                if (_this.radioButtons[i].formIdentifier == formIdentifier)
                    return _this.radioButtons[i];
            }

            for (var i = 0; i < _this.radioButtonGroups.length; i++)
            {
                if (_this.radioButtonGroups[i].formIdentifier == formIdentifier)
                    return _this.radioButtonGroups[i];
            }

            for (var i = 0; i < _this.textBoxes.length; i++)
            {
                if (_this.textBoxes[i].formIdentifier == formIdentifier)
                    return _this.textBoxes[i];
            }

            return null;
        }

    } (window.sunshine.manager = window.sunshine.manager || {}, jQuery)),

    /* 
    /**********************************************************************************************************/
    (function (controls, $, undefined)
    {

        /* Button
        /**********************************************************************************************************/
        controls.button = function (element, formIdentifier)
        {
            this.element = element;
            this.formIdentifier = formIdentifier;
            this.onclick = [];
            this.enabled = true;
            sunshine.manager.buttons.push(this);
            this.initialise();
        };
        controls.button.prototype.initialise = function ()
        {
            var _this = this;

            $("input", this.element).hide();
            $("span", this.element).css({ "display": "block" });

            $(this.element).attr("href", "#").click(function (evt)
            {
                evt.preventDefault();
                _this.click();
            });
        };
        controls.button.prototype.click = function (eventObject)
        {
            if (eventObject && typeof eventObject == "function")
                this.onclick.push(eventObject);
            else if (this.enabled)
            {
                for (var i = 0; i < this.onclick.length; i++)
                    this.onclick[i]()
            }
        };
        controls.button.prototype.enable = function ()
        {
            this.enabled = true;
            $(this.element).removeClass("button-disabled");
        };
        controls.button.prototype.disable = function ()
        {
            this.enabled = false;
            $(this.element).addClass("button-disabled");
        };


        /* Slideshow
        /**********************************************************************************************************/
        controls.slideshow = function (element, options)
        {
            this.element = element;
            this.width = (options.width) ? options.width : 570;
            this.height = (options.height) ? options.height : 360;
            this.rows = (options.rows) ? options.rows : 10;
            this.columns = (options.columns) ? options.columns : 10;
            this.animationType = (options.animationType) ? options.animationType : "topleft-bottomright";
            this.delay = (options.delay) ? options.delay : 4000;
            this.slides = [];
            this.current = 0;
            this.initialise();
        }
        controls.slideshow.prototype.initialise = function ()
        {
            var _this = this;
            $(".slide", this.element).each(function (index)
            {
                $(this).prependTo(_this.element);
                _this.slides.push(new sunshine.controls.slide(this, _this));
            });

            // Set the slideshow going.
            _this.advance();
        };
        controls.slideshow.prototype.advance = function ()
        {
            var _this = this;

            if (_this.current >= _this.slides.length)
                _this.current = 0;

            setTimeout(function ()
            {
                _this.animate(_this.current, function ()
                {
                    $(_this.slides[_this.current].element).prependTo(_this.element);
                    _this.slides[_this.current].reset();
                    _this.current++;
                    _this.advance();
                });
            }, _this.delay);
        };
        controls.slideshow.prototype.animate = function (index, callback)
        {
            switch (this.animationType)
            {
                case "left-right":
                    this.leftRight(this.slides[index], 0, callback);
                    break;
                case "topleft-bottomright":
                    this.topLeftBottomRight(this.slides[index], 0, callback);
                    break;
                default:
                    break;
            }
        };
        controls.slideshow.prototype.leftRight = function (slide, index, callback)
        {
            var _this = this;
            index = (index) ? index : 0;
            for (var i in slide.cubes)
            {
                if (slide.cubes[i].x == index)
                    slide.cubes[i].fadeOut(500, function ()
                    {
                        if ((index + 1 >= _this.columns + _this.rows) && callback)
                            callback();
                    });
            }

            if (index + 1 < this.columns)
            {
                index++;
                setTimeout(function () { _this.leftRight(slide, index, callback); }, 100);
            }
        };
        controls.slideshow.prototype.topLeftBottomRight = function (slide, x, callback)
        {
            // The coordinates passed through here are coordinates along the top row.
            var _this = this,
                _matches = [],
                limit = (_this.columns > _this.rows) ? _this.columns : _this.rows;
            x = (x) ? x : 0;
            y = 0;
            createMatches(x, y);
            for (var i in slide.cubes)
            {
                if (slide.cubes[i].x >= x - limit &&
                    slide.cubes[i].x <= x &&
                    slide.cubes[i].y >= -limit &&
                    contains(slide.cubes[i].x, slide.cubes[i].y))
                {
                    slide.cubes[i].fadeOut(500, function ()
                    {
                        if ((x + 1 >= _this.columns + _this.rows) && callback)
                            callback();
                    });

                    if (_matches.length == 0)
                        break;
                }
            }

            if (x + 1 < this.columns + this.rows)
            {
                x++;
                setTimeout(function () { _this.topLeftBottomRight(slide, x, callback); }, 100);
            }

            // Functions
            function contains(_x, _y)
            {
                for (var j in _matches)
                {
                    if (_matches[j].x == _x && _matches[j].y == _y)
                    {
                        _matches.splice(j, 1);
                        return true;
                    }
                }
                return false;
            }
            function createMatches(_x, _y)
            {
                var start = _x;
                _matches = [];
                _matches.push({ x: _x, y: _y });
                while (_x > (start - limit) && _x > 0)
                {
                    _x--;
                    _y++;
                    _matches.push({ x: _x, y: _y });
                }
            }
        };


        /* Slides
        /************************************************************/
        controls.slide = function (element, parent)
        {
            this.element = element;
            this.parent = parent;
            this.cubes = [];
            this.initialise();
        }
        controls.slide.prototype.initialise = function ()
        {
            var _this = this,
                _width = 0,
                _height = 0,
                _top = 0,
                _left = 0,
                _url = "",
                _x = 0,
                _y = 0;

            _width = this.parent.width / this.parent.columns;
            _height = this.parent.height / this.parent.rows;

            $(this.element).css({
                "position": "absolute",
                "top": 0,
                "left": 0,
                "width": this.parent.width,
                "height": this.parent.height
            });
            _url = $("img", this.element).attr("src");

            for (var i = 0; i < _this.parent.rows; i++)
            {
                for (var j = 0; j < _this.parent.columns; j++)
                {
                    var cube = new sunshine.controls.cube($("<div></div>"), _this, j, i)
                    _this.cubes.push(cube);
                    $(cube.element).css({
                        "position": "absolute",
                        "top": _top,
                        "left": _left,
                        "display": "block",
                        "width": _width,
                        "height": _height,
                        "background-repeat": "no-repeat",
                        "background-position": _x + "px " + _y + "px",
                        "background-image": "url(" + _url + ")"
                    });
                    $(_this.element).append(cube.element);

                    _left += _width;
                    _x -= _width;
                }

                _top += _height;
                _left = 0;
                _x = 0;
                _y -= _height;
            }

            $("img", this.element).remove();

            // Reset for the next slide.
            _top = 0;
            _left = 0;
            _x = 0;
            _y = 0;
        };
        controls.slide.prototype.reset = function ()
        {
            for (var i = 0; i < this.cubes.length; i++)
            {
                $(this.cubes[i].element).show();
            }
        }


        /* Codes
        /************************************************************/
        controls.cube = function (element, parent, x, y)
        {
            this.element = element;
            this.parent = parent;
            this.x = x;
            this.y = y;
        }
        controls.cube.prototype.fadeOut = function (duration, callback)
        {
            duration = (duration) ? duration : 250;
            $(this.element).fadeOut(duration, function ()
            {
                if (callback)
                    callback();
            });
        };


        /* Textbox
        /**********************************************************************************************************/
        controls.textBox = function (element, formIdentifier, validation)
        {
            this.type = "textbox";
            this.element = element;
            this.formIdentifier = formIdentifier;
            this.isEnabled = true;
            this.validator = new controls.validator(this, validation);
            sunshine.manager.textBoxes.push(this);
            this.initialise();
        }
        controls.textBox.prototype.initialise = function ()
        {
            var _this = this;
            $(this.element).blur(function () { _this.validate(); });
        }
        controls.textBox.prototype.val = function (value)
        {
            if (value != undefined)
                $(this.element).val(value);
            else
                return $(this.element).val();
        }
        controls.textBox.prototype.enable = function ()
        {
            this.isEnabled = true;
            $(this.element).removeClass("textbox-disabled");
        }
        controls.textBox.prototype.disable = function ()
        {
            this.isEnabled = true;
            $(this.element).addClass("textbox-disabled");
        }
        controls.textBox.prototype.validate = function ()
        {
            return this.validator.validate();
        }


        /* Validator
        /**********************************************************************************************************/
        controls.validator = function (object, validation)
        {
            this.formItemTypes = { "checkbox": "checkbox",
                "dropdown": "dropdown",
                "password": "password",
                "radiobutton": "radiobutton",
                "radiobuttongroup": "radiobuttongroup",
                "textarea": "textarea",
                "textbox": "textbox",
                "undefined": "undefined"
            }

            this.object = object;
            this.element = ($(object.element).hasClass("form-element")) ? object.element : $(object.element).closest(".form-element");

            this.icon = $(".form-element-icon", this.element);
            this.message = $(".form-element-message", this.element);

            this.validationTypes = this.setValidationTypes(validation);
            this.validationFunctions = [];
            this.bespokeFunctions = [];
            this.setStatus(true, "");

            this.emailRegex = /^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.(([0-9]{1,3})|([a-zA-Z]{2,3})|(aero|coop|info|museum|name|mobi|asia|jobs|travel))$/;
            this.telephoneRegex = /^[0-9-\+\(\)\W]+$/;
            this.canBeEmpty = false;

            this.initialise();
        }
        controls.validator.prototype.initialise = function ()
        {
            var _this = this;

            // Add in the validation functions.
            if (this.validationTypes.length > 0)
            {
                for (var i = 0; i < this.validationTypes.length; i++)
                {
                    switch (/[a-z]+/g.exec(this.validationTypes[i])[0])
                    {
                        case "date":
                            this.validationFunctions.push(function () { return _this.date(); });
                            break;
                        case "email":
                            this.validationFunctions.push(function () { return _this.email(); });
                            break;
                        case "empty":
                            this.canBeEmpty = true;
                            break;
                        case "mandatory":
                            this.validationFunctions.push(function () { return _this.mandatory(); });
                            break;
                        case "password":
                            this.validationFunctions.push(function () { return _this.password(); });
                            break;
                        case "telephone":
                            this.validationFunctions.push(function () { return _this.telephone(); });
                            break;
                        case "length":
                            this.validationFunctions.push(function () { return _this.length(); });
                            break;
                    }
                }
            }
        }
        controls.validator.prototype.mandatory = function ()
        {
            switch (this.object.type)
            {
                case "checkbox":
                    if (!this.object.isChecked)
                        this.setStatus(false, "This field is required.");
                    else
                        this.setStatus(true, "");
                    break;
                case "dropdown":
                    if (this.object.selectedValue == undefined || this.object.selectedValue == "")
                        this.setStatus(false, "This field is required.");
                    else
                        this.setStatus(true, "");
                    break;
                    break;
                case "radiobuttongroup":
                    if (this.object.val() == undefined || this.object.val() == "")
                        this.setStatus(false, "This field is required.");
                    else
                        this.setStatus(true, "");
                    break;
                case "textbox":
                case "textarea":
                case "password":
                    if (this.object.val() == undefined || this.object.val() == "")
                        this.setStatus(false, "This field is required.");
                    else
                        this.setStatus(true, "");
                    break;
                default:
                    alert("Items of form type '" + this.object.type + "' cannot be validated as mandatory.");
                    break;
            }
        }
        controls.validator.prototype.email = function ()
        {
            switch (this.object.type)
            {
                case "textbox":
                    if (!this.emailRegex.test(this.object.val()))
                        this.setStatus(false, "Please enter a valid email address.");
                    else
                        this.setStatus(true, "");
                    break;
                case "checkbox":
                case "dropdown":
                case "password":
                case "radiobutton":
                case "textarea":
                default:
                    alert("Items of form type '" + this.formItemType + "' cannot be validated as an email.");
                    break;
            }
        }
        controls.validator.prototype.date = function ()
        {
            switch (this.object.type)
            {
                case "textbox":
                    break;
                default:
                    alert("Items of form type " + this.formItemType + " cannot be validated as a date.");
                    break;
            }
        }
        controls.validator.prototype.empty = function ()
        {
            switch (this.object.type)
            {
                case "textbox":
                case "textarea":
                    if (this.object.val() == "")
                    {
                        this.setStatus(true, "");
                        this.setDefault();
                    }
                    break;
                case "checkbox":
                case "dropdown":
                case "password":
                case "radiobutton":
                default:
                    alert("Items of form type '" + this.formItemType + "' cannot be validated as empty.");
                    break;
            }
        }
        controls.validator.prototype.password = function (formElement)      // Add password limitations.
        {
            switch (this.object.type)
            {
                case "password":
                    break;
                default:
                    alert("Items of form type " + this.formItemType + " cannot be validated as matching another element");
                    break;
            }
        }
        controls.validator.prototype.telephone = function ()
        {
            switch (this.object.type)
            {
                case "textbox":
                    if (!this.telephoneRegex.test(this.object.val()))
                        this.setStatus(false, "Telephone numbers can only contain numbers and '+', '(' or ')'.");
                    else
                        this.setStatus(true, "");
                    break;
                case "checkbox":
                case "dropdown":
                case "password":
                case "radiobutton":
                case "textarea":
                default:
                    alert("Items of form type '" + this.formItemType + "' cannot be validated as a telephone number.");
                    break;
            }
        }
        controls.validator.prototype.length = function ()
        {
            switch (this.object.type)
            {
                case "textbox":
                case "password":
                    for (var i = 0; i < this.validationTypes.length; i++)
                    {
                        if (this.validationTypes[i].indexOf('length') != -1)
                        {
                            var len = /[0-9]+/ig.exec(this.validationTypes[i]);
                            if (this.object.val().length > len)
                                this.setStatus(false, "This field cannot be longer than " + len + " characters. It is currently " + this.object.val().length + " charcters");
                            else
                                this.setStatus(true, "");
                            break;
                        }
                    }
                    break;
                default:
                    alert("Items of form type " + this.formItemType + " cannot be validated with a length");
                    break;
            }
        }
        controls.validator.prototype.validate = function ()
        {
            this.status = { "isValid": true, "message": "" };
            if (this.validationFunctions.length > 0 || this.bespokeFunctions.length > 0)
            {
                if (this.validationFunctions.length > 0)
                {
                    for (var i = 0; i < this.validationFunctions.length; i++)
                    {
                        if (this.status.isValid)
                            this.validationFunctions[i]();
                        else
                            break;
                    }
                }
                if (this.bespokeFunctions.length > 0)
                {
                    for (var j = 0; j < this.bespokeFunctions.length; j++)
                    {
                        if (this.status.isValid)
                            this.bespokeFunctions[j]();
                        else
                            break;
                    }
                }


                if (this.status.isValid)
                    this.setValid();
                else
                    this.setInvalid();

                // If it's possible to have an empty element then overwrite all other validation if the element is empty.
                if (this.canBeEmpty && this.empty())
                    this.setDefault();
            }
            return this.status;
        }
        controls.validator.prototype.setStatus = function (isValid, message)
        {
            this.status = { "isValid": isValid, "message": message };
        }
        controls.validator.prototype.setValid = function ()
        {
            $(this.element).removeClass("form-element-invalid").addClass("form-element-valid");
            $(this.message).html("");
        }
        controls.validator.prototype.setInvalid = function ()
        {
            $(this.element).removeClass("form-element-valid").addClass("form-element-invalid");
            $(this.message).html(this.status.message);
        }
        controls.validator.prototype.setDefault = function ()
        {
            $(this.element).removeClass("form-element-valid").removeClass("form-element-invalid");
            $(this.message).html("");
        }
        controls.validator.prototype.highlightInvalid = function ()
        {
            var _this = this;
            $(_this.message).fadeTo(200, 0.6, function ()
            {
                $(_this.message).fadeTo(200, 1, function ()
                {
                    $(_this.message).fadeTo(200, 0.6, function ()
                    {
                        $(_this.message).fadeTo(200, 1);
                    });
                });
            });
        }
        controls.validator.prototype.setValidationTypes = function (validation)
        {
            validation = validation.toLowerCase();
            if (validation.indexOf("empty") > -1 && validation.indexOf("mandatory") > -1)
            {
                alert("'" + this.object.formIdentifier + "' cannot have both mandatory and empty validation.");
                return [];
            }
            else
            {
                if (!validation)
                    return [];
                else if (validation.indexOf('|') != -1)
                    return validation.split('|');
                else
                    return [validation];
            }
        }

    } (window.sunshine.controls = window.sunshine.controls || {}, jQuery))

} (window.sunshine = window.sunshine || {}, jQuery))
