/** 
 * Displays the text of a tag one letter at a time.
 *
 * Use:
 * // display the entire text in 2 seconds
 * $('h1').typewriter({autorun: true, speed: 2000});
 *
 * // create an instance of the typewriter
 * var tw = $.Typewriter($('h1'), {speed: 1000});
 * tw.reset();
 * tw.run();
 *
 * Copyright 2010, Dimitry Zolotaryov (WebIT.ca)
 * MIT License
 */
(function ($) {

    var typewriter         = null
        , add_markup       = null
        , run_typewriter   = null
        , stop_typewriter  = null
        , reset_typewriter = null
        , show_next        = null
        ;

    /**
     * Adds any additional markup to the target object
     */
    add_markup = function () {
        var chars       = this.jquery.text().split('')
            , text      = ''
            , letters   = 0
            , fadespeed = 0
            ;
        $.each(chars, function (i, chr) {
            if (chr != ' ') {
                text += '<span>' + chr + '</span>';
                letters += 1;
            } else {
                text += chr;
            }
        });
        if (this.options.fadespeed == null) {
            // this is the animation speed of every letter
            this.options.fadespeed = parseInt(this.options.speed / letters);
        }
        this.jquery.html(text);
    }

    /**
     * Shows the next character in a span
     */
    show_next = function () {
        var _this = this
            , animating = null
            ;
        $('span', this.jquery).each(function () {
            if (! $(this).hasClass('vis')) {
                animating = $(this);
                return false;
            }
        });
        if (animating != null) {
            if (this.options.pause) {
                this.animating = setTimeout(function () {
                    animating.show().addClass('vis');
                    _this.show_next();
                }, this.options.fadespeed);
            } else {
                animating
                    .stop()
                    .fadeIn(
                        this.options.fadespeed,
                        function () {
                            animating.addClass('vis');
                            _this.show_next();
                        }
                    );
                this.animating = animating;
            }
        } else {
            this.animating = null;
            this.options.oncomplete(this);
        }
    }

    /**
     * Runs the visual effect
     */
    run_typewriter = function () {
        this.stop();
        this.show_next();
    }

    /**
     * Stops the typewriter
     */
    stop_typewriter = function () {
        if (this.animating != null) {
            try {
                this.animating.stop();
            } catch (e) {
                clearTimeout(this.animating);
            }
            this.animating = null;
        }
    }

    /**
     * Reset the typewriter
     */
    reset_typewriter = function () {
        this.stop();
        $('span', this.jquery)
            .removeClass('vis')
            .hide();
    }

    /** 
     * Constructor for the typewriter object
     */
    typewriter = function (jquery, options) {
        var options = $.extend({}, {
                speed     : 2000,
                fadespeed : null,
                autorun   : false,
                oncomplete: function () {},
                pause     : false
            }, options || {})

            , inst = {
                jquery   : jquery,
                options  : options,
                animating: null,
                augment  : add_markup, 
                run      : run_typewriter,
                stop     : stop_typewriter,
                reset    : reset_typewriter,
                show_next: show_next
            };

        inst.augment();
        if (options.autorun) {
            inst.reset();
            inst.run();
        }
        return inst;
    }

    /** 
     * Extends the jQuery object with the typewriter tool
     */
    $.fn.typewriter = function (options) {
        this.each(function () {
            var t = $(this)
                , tw = typewriter(t, options)
                ;
            t.data('typewriter', tw);
        });
        return this;
    }

    /**
     * Adds the typewriter constructor to the jQuery object
     */
    $.Typewriter = typewriter;

})(jQuery);

