﻿(function ($)
{
    $.fn.timers = { names: [] };

    $.fn.stopTimer = function (name)
    {
        return this.each(
            function ()
            {
                var $this = $(this);
                name = (name ? name : $this.timers["_default"]);

                if ($this.timers[name] && $this.timers[name].handle)
                {
                    if ($this.timers[name].type == "repeat" || $this.timers[name].type == "repeat-times")
                    {
                        window.clearInterval($this.timers[name].handle);
                    }
                    else
                    {
                        window.clearTimeout($this.timers[name].handle);
                    }

                    $this.timers[name].handle = null;
                }

                $this.timers["_default"] = name;
            }
        );
    };

    $.fn.stopTimers = function (pattern)
    {
        var match = new RegExp((pattern ? pattern : ".*"));

        return this.each(
            function ()
            {
                var $this = $(this);
                for (var i = 0; i < $this.timers.names.length; i++)
                {
                    if (match.exec($this.timers.names[i]) != null)
                    {
                        $this.stopTimer($this.timers.names[i]);
                    }
                }
            }
        );
    };

    $.fn.newTimer = function (name, callback, options)
    {
        options = (options ? options : {});

        return this.each(
            function ()
            {
                var $this = $(this);

                $this.stopTimer(name);

                $this.timers[name] =
                {
                    "name": name,
                    "callback": callback,
                    "defaulttimeout": options.timeout,
                    "defaulttimes": options.times,
                    "defaultrepeat": options.repeat,
                    "defaultimmediate": options.immediate
                };
                $this.timers.names.push(name);

                $this.timers["_default"] = name;
            }
        );
    };

    $.fn.startTimer = function (options)
    {
        options = (options ? options : {});

        return this.each(
            function ()
            {
                var $this = $(this);
                var name = (options.name ? options.name : $this.timers["_default"]);
                var timeout = (options.timeout ? options.timeout : $this.timers[name].defaulttimeout);
                var times = (options.times ? options.times : $this.timers[name].defaulttimes);
                var repeat = (options.repeat != null ? options.repeat : $this.timers[name].defaultrepeat);
                var immediate = (options.immediate != null ? options.immediate : $this.timers[name].defaultimmediate);

                $this.stopTimer(name);

                var timerobj = $this.timers[name];
                if (times && times != 1)
                {
                    if (times > 1)
                    {
                        timerobj.times = (immediate ? times - 1 : times);

                        $this.timers[name].type = "repeat-times";
                        $this.timers[name].handle = window.setInterval(
                            function ()
                            {
                                timerobj.callback.call($this, timerobj);

                                if (--timerobj.times <= 0)
                                {
                                    window.clearInterval(timerobj.handle);
                                    timerobj.handle = null;
                                }
                            }, timeout
                        );
                    }
                }
                else if (repeat)
                {
                    $this.timers[name].type = "repeat";
                    $this.timers[name].handle = window.setInterval(
                        function ()
                        {
                            timerobj.callback.call($this, timerobj);
                        }, timeout
                    );
                }
                else
                {
                    $this.timers[name].type = "timeout";
                    $this.timers[name].handle = window.setTimeout(
                        function ()
                        {
                            timerobj.callback.call($this, timerobj);

                            timerobj.handle = null;
                        },
                        timeout
                    );
                }

                if (immediate)
                {
                    window.setTimeout(
                        function ()
                        {
                            timerobj.callback.call($this, timerobj);
                        }, 1
                    );
                }

                $this.timers["_default"] = name;
            }
        );
    };
    $.fn.delay = function (timeout, callback)
    {
        $this = $(this);
        return this.each(
            function ()
            {
                window.setTimeout(function () { callback.call($this); }, timeout);
            }
        );
    };
})(jQuery);
