/*
    jQuery News Ticker is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 2 of the License.

    jQuery News Ticker is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with jQuery News Ticker.  If not, see <http://www.gnu.org/licenses/>.
*/
(function($){
        $.fn.ticker = function(options) {
                // Extend our default options with those provided.
                // Note that the first arg to extend is an empty object -
                // this is to keep from overriding our "defaults" object.
                var opts = $.extend({}, $.fn.ticker.defaults, options);

                /* Get the id of the UL to get our news content from */
                var newsID = '#' + $(this).attr('id');

                /* Get the tag type - we will check this later to makde sure it is a UL tag */
                var tagType = $(this).attr('tagName');

                return this.each(function() {
                        /* Internal vars */
                        var settings = {
                                position: 0,
                                time: 0,
                                distance: 0,
                                newsArr: {},
                                play: true,
                                paused: false,
                                contentLoaded: false,
                                dom: {
                                        contentID: '#ticker-content',
                                        titleID: '#ticker-title',
                                        titleElem: '#ticker-title SPAN',
                                        tickerID : '#ticker',
                                        wrapperID: '#ticker-wrapper',
                                        revealID: '#ticker-swipe',
                                        revealElem: '#ticker-swipe SPAN',
                                        controlsID: '#ticker-controls',
                                        prevID: '#prev',
                                        nextID: '#next',
                                        playPauseID: '#play-pause'
                                }
                        };

                        // if we are not using a UL, display an error message and stop any further execution
                        if (tagType != 'UL' && tagType != 'OL' && opts.htmlFeed === true) {
                                debugError('Cannot use <' + tagType.toLowerCase() + '> type of element for this plugin - must of type <ul> or <ol>');
                                return false;
                        }

                        // set the ticker direction
                        opts.direction == 'rtl' ? opts.direction = 'right' : opts.direction = 'left';

                        // lets go...
                        initialisePage();
                        /* Function to get the size of an Object*/
                        function countSize(obj) {
                            var size = 0, key;
                            for (key in obj) {
                                if (obj.hasOwnProperty(key)) size++;
                            }
                            return size;
                        };

                        /* Function for handling debug and error messages */
                        function debugError(obj) {
                                if (opts.debugMode) {
                                        if (window.console && window.console.log) {
                                                window.console.log(obj);
                                        }
                                        else {
                                                alert(obj);
                                        }
                                }
                        }

                        /* Function to setup the page */
                        function initialisePage() {
                                // add our HTML structure for the ticker to the DOM
                                $(settings.dom.wrapperID).append('<div id="' + settings.dom.tickerID.replace('#', '') + '"><div id="' + settings.dom.titleID.replace('#', '') + '"><span><!-- --></span></div><p id="' + settings.dom.contentID.replace('#', '') + '"></p><div id="' + settings.dom.revealID.replace('#', '') + '"><span><!-- --></span></div></div>');
                                $(settings.dom.wrapperID).removeClass('no-js').addClass('has-js ' + opts.direction);
                                // hide the ticker
                                $(settings.dom.tickerElem + ',' + settings.dom.contentID).hide();
                                // add the controls to the DOM if required
                                if (opts.controls) {
                                        // add related events - set functions to run on given event
                                        $(settings.dom.controlsID).live('click mouseover mousedown mouseout mouseup', function (e) {
                                                var button = e.target.id;
                                                if (e.type == 'click') {
                                                        switch (button) {
                                                                case settings.dom.prevID.replace('#', ''):
                                                                        // show previous item
                                                                        settings.paused = true;
                                                                        $(settings.dom.playPauseID).addClass('paused');
                                                                        manualChangeContent(button);
                                                                        break;
                                                                case settings.dom.nextID.replace('#', ''):
                                                                        // show next item
                                                                        settings.paused = true;
                                                                        $(settings.dom.playPauseID).addClass('paused');
                                                                        manualChangeContent(button);
                                                                        break;
                                                                case settings.dom.playPauseID.replace('#', ''):
                                                                        // play or pause the ticker
                                                                        if (settings.play == true) {
                                                                                settings.paused = true;
                                                                                $(settings.dom.playPauseID).addClass('paused');
                                                                                pauseTicker();
                                                                        }
                                                                        else {
                                                                                settings.paused = false;
                                                                                $(settings.dom.playPauseID).removeClass('paused');
                                                                                restartTicker();
                                                                        }
                                                                        break;
                                                        }
                                                }
                                                else if (e.type == 'mouseover' && $('#' + button).hasClass('controls')) {
                                                        $('#' + button).addClass('over');
                                                }
                                                else if (e.type == 'mousedown' && $('#' + button).hasClass('controls')) {
                                                        $('#' + button).addClass('down');
                                                }
                                                else if (e.type == 'mouseup' && $('#' + button).hasClass('controls')) {
                                                        $('#' + button).removeClass('down');
                                                }
                                                else if (e.type == 'mouseout' && $('#' + button).hasClass('controls')) {
                                                        $('#' + button).removeClass('over');
                                                }
                                        });
                                        // add controls HTML to DOM
                                        $(settings.dom.wrapperID).append('<ul id="' + settings.dom.controlsID.replace('#', '') + '"><li id="' + settings.dom.playPauseID.replace('#', '') + '" class="controls"></li><li id="' + settings.dom.prevID.replace('#', '') + '" class="controls"></li><li id="' + settings.dom.nextID.replace('#', '') + '" class="controls"></li></ul>');
                                }
                                if (opts.displayType != 'fade') {
                                // add mouse over on the content
                                $(settings.dom.contentID).mouseover(function () {
                                        if (settings.paused == false) {
                                                pauseTicker();
                                        }
                                }).mouseout(function () {
                                        if (settings.paused == false) {
                                                restartTicker();
                                        }
                                });
                                }
                                // process the content for this ticker
                                processContent();
                        }

                        /* Start to process the content for this ticker */
                        function processContent() {
                                // check to see if we need to load content
                                if (settings.contentLoaded == false) {
                                        // construct content
                                        if (opts.ajaxFeed) {
                                                if (opts.feedType == 'xml') {
                                                        $.ajax({
                                                                url: opts.feedUrl,
                                                                cache: false,
                                                                dataType: opts.feedType,
                                                                async: true,
                                                                success: function(data){
                                                                        count = 0;
                                                                        // get the 'root' node
                                                                        for (var a = 0; a < data.childNodes.length; a++) {
                                                                                if (data.childNodes[a].nodeName == 'rss') {
                                                                                        xmlContent = data.childNodes[a];
                                                                                }
                                                                        }
                                                                        // find the channel node
                                                                        for (var i = 0; i < xmlContent.childNodes.length; i++) {
                                                                                if (xmlContent.childNodes[i].nodeName == 'channel') {
                                                                                        xmlChannel = xmlContent.childNodes[i];
                                                                                }
                                                                        }
                                                                        // for each item create a link and add the article title as the link text
                                                                        for (var x = 0; x < xmlChannel.childNodes.length; x++) {
                                                                                if (xmlChannel.childNodes[x].nodeName == 'item') {
                                                                                        xmlItems = xmlChannel.childNodes[x];
                                                                                        var title, link = false;
                                                                                        for (var y = 0; y < xmlItems.childNodes.length; y++) {
                                                                                                if (xmlItems.childNodes[y].nodeName == 'title') {
                                                                                                        title = xmlItems.childNodes[y].lastChild.nodeValue;
                                                                                                }
                                                                                                else if (xmlItems.childNodes[y].nodeName == 'link') {
                                                                                                        link = xmlItems.childNodes[y].lastChild.nodeValue;
                                                                                                }
                                                                                                if ((title !== false && title != '') && link !== false) {
                                                                                                    settings.newsArr['item-' + count] = { type: opts.titleText, content: '<a href="' + link + '">' + title + '</a>' };                                                                                                    count++;                                                                                                    title = false;                                                                                                    link = false;
                                                                                                }
                                                                                        }
                                                                                }
                                                                        }
                                                                        // quick check here to see if we actually have any content - log error if not
                                                                        if (countSize(settings.newsArr < 1)) {
                                                                                debugError('Couldn\'t find any content from the XML feed for the ticker to use!');
                                                                                return false;
                                                                        }
                                                                        setupContentAndTriggerDisplay();
                                                                        settings.contentLoaded = true;
                                                                }
                                                        });
                                                }
                                                else {
                                                        debugError('Code Me!');
                                                }
                                        }
                                        else if (opts.htmlFeed) {
                                                if($(newsID + ' LI').length > 0) {
                                                        $(newsID + ' LI').each(function (i) {
                                                                // maybe this could be one whole object and not an array of objects?
                                                                settings.newsArr['item-' + i] = { type: opts.titleText, content: $(this).html()};
                                                        });
                                                        setupContentAndTriggerDisplay();
                                                }
                                                else {
                                                        debugError('Couldn\'t find HTML any content for the ticker to use!');
                                                        return false;
                                                }
                                        }
                                        else {
                                                debugError('The ticker is set to not use any types of content! Check the settings for the ticker.');
                                                return false;
                                        }
                                }
                        }

                        function setupContentAndTriggerDisplay() {

                                settings.contentLoaded = true;

                                // update the ticker content with the correct item
                                // insert news content into DOM
                                $(settings.dom.titleElem).html(settings.newsArr['item-' + settings.position].type);
                                $(settings.dom.contentID).html(settings.newsArr['item-' + settings.position].content);

                                // set the next content item to be used - loop round if we are at the end of the content
                                if (settings.position == (countSize(settings.newsArr) -1)) {
                                        settings.position = 0;
                                }
                                else {
                                        settings.position++;
                                }

                                // get the values of content and set the time of the reveal (so all reveals have the same speed regardless of content size)
                                distance = $(settings.dom.contentID).width();
                                time = distance / opts.speed;

                                // start the ticker animation
                                revealContent();
                        }

                        // slide back cover or fade in content
                        function revealContent() {
                                if(settings.play) {
                                        // get the width of the title element to offset the content and reveal
                                        var offset = $(settings.dom.titleElem).width() + 20;
                                        $(settings.dom.revealID).css(opts.direction, offset + 'px');
                                        // show the reveal element and start the animation
                                        if (opts.displayType == 'fade') {
                                                // fade in effect ticker
                                                $(settings.dom.revealID).hide(0, function () {
                                                        $(settings.dom.contentID).css(opts.direction, offset + 'px').fadeIn(opts.fadeInSpeed, postReveal);
                                                });
                                        }
                                        else if (opts.displayType == 'scroll') {
                                                // to code
                                        }
                                        else {
                                                // default bbc scroll effect
                                                $(settings.dom.revealElem).show(0, function () {
                                                        $(settings.dom.contentID).css(opts.direction, offset + 'px').show();
                                                        // set our animation direction
                                                        animationAction = opts.direction == 'right' ? { marginRight: distance + 'px'} : { marginLeft: distance + 'px' };
                                                        $(settings.dom.revealID).css('margin-' + opts.direction, '0px').delay(20).animate(animationAction, time, 'linear', postReveal);
                                                });
                                        }
                                }
                                else {
                                        return false;
                                }
                        };

                        // here we hide the current content and reset the ticker elements to a default state ready for the next ticker item
                        function postReveal() {
                                if(settings.play) {
                                        // we have to separately fade the content out here to get around an IE bug - needs further investigation
                                        $(settings.dom.contentID).delay(opts.pauseOnItems).fadeOut(opts.fadeOutSpeed);
                                        // deal with the rest of the content, prepare the DOM and trigger the next ticker
                                        if (opts.displayType == 'fade') {
                                                $(settings.dom.contentID).fadeOut(opts.fadeOutSpeed, function () {
                                                        $(settings.dom.wrapperID)
                                                                .find(settings.dom.revealElem + ',' + settings.dom.contentID)
                                                                        .hide()
                                                                .end().find(settings.dom.tickerID + ',' + settings.dom.revealID)
                                                                        .show()
                                                                .end().find(settings.dom.tickerID + ',' + settings.dom.revealID)
                                                                        .removeAttr('style');
                                                        setupContentAndTriggerDisplay();
                                                });
                                        }
                                        else {
                                                $(settings.dom.revealID).hide(0, function () {
                                                        $(settings.dom.contentID).fadeOut(opts.fadeOutSpeed, function () {
                                                                $(settings.dom.wrapperID)
                                                                        .find(settings.dom.revealElem + ',' + settings.dom.contentID)
                                                                                .hide()
                                                                        .end().find(settings.dom.tickerID + ',' + settings.dom.revealID)
                                                                                .show()
                                                                        .end().find(settings.dom.tickerID + ',' + settings.dom.revealID)
                                                                                .removeAttr('style');
                                                                setupContentAndTriggerDisplay();
                                                        });
                                                });
                                        }
                                }
                                else {
                                        $(settings.dom.revealElem).hide();
                                }
                        }

                        // pause ticker
                        function pauseTicker() {
                                settings.play = false;
                                // stop animation and show content - must pass "true, true" to the stop function, or we can get some funky behaviour
                                $(settings.dom.tickerID + ',' + settings.dom.revealID + ',' + settings.dom.titleID + ',' + settings.dom.titleElem + ',' + settings.dom.revealElem + ',' + settings.dom.contentID).stop(true, true);
                                $(settings.dom.revealID + ',' + settings.dom.revealElem).hide();
                                $(settings.dom.wrapperID)
                                        .find(settings.dom.titleID + ',' + settings.dom.titleElem).show()
                                                .end().find(settings.dom.contentID).show();
                        }

                        // play ticker
                        function restartTicker() {
                                settings.play = true;
                                settings.paused = false;
                                // start the ticker again
                                postReveal();
                        }

                        // change the content on user input
                        function manualChangeContent(direction) {
                                pauseTicker();
                                switch (direction) {
                                        case 'prev':
                                                if (settings.position == 0) {
                                                        settings.position = countSize(settings.newsArr) -2;
                                                }
                                                else if (settings.position == 1) {
                                                        settings.position = countSize(settings.newsArr) -1;
                                                }
                                                else {
                                                        settings.position = settings.position - 2;
                                                }
                                                $(settings.dom.titleElem).html(settings.newsArr['item-' + settings.position].type);
                                                $(settings.dom.contentID).html(settings.newsArr['item-' + settings.position].content);
                                                break;
                                        case 'next':
                                                $(settings.dom.titleElem).html(settings.newsArr['item-' + settings.position].type);
                                                $(settings.dom.contentID).html(settings.newsArr['item-' + settings.position].content);
                                                break;
                                }
                                // set the next content item to be used - loop round if we are at the end of the content
                                if (settings.position == (countSize(settings.newsArr) -1)) {
                                        settings.position = 0;
                                }
                                else {
                                        settings.position++;
                                }
                        }
                });
        };

        // plugin defaults - added as a property on our plugin function
        $.fn.ticker.defaults = {
                speed: 0.20,
                ajaxFeed: false,
                feedUrl: '',
                feedType: 'xml',
                displayType: 'reveal',
                htmlFeed: true,
                debugMode: true,
                controls: false,
                titleText: '',
                direction: 'ltr',
                pauseOnItems: 5000,
                fadeInSpeed: 600,
                fadeOutSpeed: 300
        };
})(jQuery);

