// Last updated 2011-08-11
(function($){

$.fn.linksTicker = function linksTicker(opts)
{
    function linksTickerObj(options, me, $ctr)
    {
        function getInt(n)
        {
            return parseInt(n,10).toString() == 'NaN' ? 0 : parseInt(n,10);
        }
        var settings = {'speed': 1200, 'pause': 3000, 'hoverPause': true, 'truncate': 90, 'truncateText': '...'}
        $.extend(settings, options);

        if(!$ctr.size()) return false;
        var $allLinks, n, numLinks, cw, speed;
        var fadeIn = false, wipeOut = false;
        var selfRef = this;

        selfRef.pausing = 0;
        selfRef.hovered = 0;

        if(settings.rss || settings.atom)
        {
            $ctr.html('');
            this.linksTickerCB = function(r)
            {
                if(!r.query || !r.query.results) return false;
                var data = r.query.results[settings.rss ? 'item' : 'entry'];
                var links = '', href = '';
                for(t in data)
                {
                    if(!settings.noHref) href = ' href="' + (data[t].link.href || data[t].link) + '" target="' + (settings.target || '_blank') + '"';
                    links += '<a' + href + '>' + (data[t].title.content || data[t].title) + '</a>';
                }
                if(links)
                {
                    $ctr.html(links);
                    init();
                    animateLink();
                }
            }
        }

        function init()
        {
            $allLinks = $ctr.find('a');
            if(!$allLinks.size()) return false;
            $allLinks.css({'display': 'none', 'white-space': 'nowrap', 'position': 'relative'});
            if(!settings.rss && !settings.atom && settings.target)  $allLinks.attr('target', settings.target.toString());

            settings.truncate = getInt(settings.truncate);
            settings.speed = getInt(settings.speed);
            settings.pause = getInt(settings.pause);
            settings.limit = getInt(settings.limit);
            settings.animOutTop = 0 - getInt(settings.animOutTop);
            settings.animInTop = 0 - getInt(settings.animInTop);
            if(typeof settings.animOutSpeed == 'undefined') settings.animOutSpeed = wipeOut ? settings.speed : 300;
            settings.animOutSpeed = getInt(settings.animOutSpeed);
            if(settings.animIn && settings.animIn.toString().toLowerCase() == 'fade') fadeIn = true;
            if(settings.animOut && settings.animOut.toString().toLowerCase() == 'wipe') wipeOut = true;
            settings.truncateText = settings.truncateText.toString();

            if(settings.limit) $allLinks = $allLinks.slice(0, settings.limit);
            if(settings.noHref && !settings.rss && !settings.atom) $allLinks.removeAttr('href');

            if(settings.truncate)
            {
                $allLinks.each(function(){
                    var t = $(this).text();
                    var t2 = t.substr(0, settings.truncate);
                    if(t2.length < t.length)
                    {
                        if(settings.truncateWord) t2 = t2.replace(/\s+$|(\s)(\S*)$/, '').replace(/\W+$/, '').replace(/&nbsp;/g, ' ');
                        t2 += settings.truncateText;
                    }
                    $(this).text(t2);
                });
            }

            selfRef.hovered = 0;
            if(settings.hoverPause) $allLinks.hover(function(){selfRef.hovered=1}, function(){selfRef.hovered=0;selfRef.hideThenNext(this,settings.pause)});
            n = 0;
            numLinks = $allLinks.size();
            cw = $ctr.width();
            selfRef.pausing = 1;
        }

        function animateLink()
        {
            if(n == numLinks) n = 0;
            var $a = $ctr.find('> a:eq(' + (n++) + ')');
            var w = $a.css({'display': 'inline-block', 'visibility': 'hidden', 'opacity': (fadeIn ? 0 : 1), 'width': '', top: (fadeIn ? settings.animInTop : 0)}).width();
            $a.css({'visibility': 'visible', 'width': 0});
            selfRef.pausing = 1;

            if(fadeIn)
                $a.animate({'opacity': 1, top: 0}, settings.speed).delay(settings.pause).animate({'left': '+=0'}, 0, function(){selfRef.pausing = 0;if(!selfRef.hovered)selfRef.hideThenNext(this,0,w)});
            else
                $a.animate({'width': w}, (settings.speed/cw) * w, 'linear').delay(settings.pause).animate({'left': '+=0'}, 0, function(){selfRef.pausing = 0;if(!selfRef.hovered)selfRef.hideThenNext(this,0,w)});
        }

        this.hideThenNext = function(t,d,w)
        {
            function finish(){$allLinks.hide();animateLink()};

            if(!selfRef.pausing && !selfRef.lock)
            {
                selfRef.pausing = 1;
                selfRef.lock = 0;

                if(wipeOut)
                    $(t).delay(d).animate({'width': 0}, (settings.animOutSpeed/cw) * w, 'linear', finish);
                else
                    $(t).delay(d).animate({'opacity': 0, 'top': settings.animOutTop}, settings.animOutSpeed, finish);
            }
            if(selfRef.lock) selfRef.lockVars = [t,w];
        }

        $(function(){
            if(settings.rss || settings.atom)
            {
                var yqlQuery = 'http://query.yahooapis.com/v1/public/yql?q=select%20title%2C';
                var limit = settings.limit ? ('%20LIMIT%20' + settings.limit) : '';
                
                if(settings.rss)
                    yqlQuery += 'link%20from%20rss%20where%20url%3D%22' + encodeURIComponent(settings.rss);
                else
                    yqlQuery += 'link.href%20from%20atom%20where%20link.rel%3D%22alternate%22%20and%20url%3D%22' + encodeURIComponent(settings.atom);
    
                yqlQuery += '%22' + limit + '&format=json&callback=' + me + '.linksTickerCB';
                $.getScript(yqlQuery);
            }
            else
            {
                init();
                animateLink();
            }
        });
    }

    function kill(c)
    {
        c.find('a').unbind('mouseenter').unbind('mouseleave').clearQueue();
        c.removeData('self_reference');
    }
    
    if(typeof opts == 'string') var findMe = this.data('self_reference');

    if(opts == 'pause')
    {
        if(findMe) window[findMe].lock = 1;
    }
    else if(opts == 'continue')
    {
        var lv;
        if(findMe && window[findMe] && (lv = window[findMe].lockVars))
        {
            window[findMe].lock = 0;
            window[findMe].pausing = 0;
            window[findMe].hideThenNext(lv[0], 0, lv[1]);
            window[findMe].lockVars = false;
        }
    }
    else if(opts == 'kill')
    {
        kill(this);
    }
    else
    {
        kill(this);
        var me = '_linksTicker' + Math.random().toString().substr(2);
        this.data('self_reference', me);
        window[me] = new linksTickerObj(opts, me, this);
    }

    return this;
}

})(jQuery);
