/** 
 * @fileoverview Insert RSS-fed Modules (AKA Self-maintaining content
 * headlines module). Consist of modules placed on the right side
 * navigation of ibm.com pages which display news from an RSS feed
 * file by using a simple JavaScript code.
 * Architect: David Leip, Developer: Vitor da Cruz Caminha de Siqueira
 * The solution is available under the following creative commons license:
 * http://creativecommons.org/licenses/by-nc-sa/3.0/
 * @version v1.2
 */


/**
 * Clip a text according to the character limit
 * @param {Number} charLimit Maximum number of characters allowed
 * @param {String} lang The ISO 639 language code of the text
 * @param {String} punct The characters to be included in the 
 * end of the text
 * @return {String} The new text respecting the character limit
 */
String.prototype.clipText = function(charLimit, lang, punct) {
    var str = this.toString();
    var words = str.split(" ");
    var ent = /\&([a-zA-Z]{2,6};|#[0-9]{3};)/g;
    var clipStr = "";

    if (str.replace(ent, "_").length <= charLimit) {
        return str;
    }

    if (words.length == 1 && words[0].length > charLimit) {
        return words[0].substring(0, charLimit - punct.length) + punct;
    }

    // Case language is Chinese, Japanese or Korean
    if (lang.match(/(ja|zh|ko)/)) {
        return str.substring(0, charLimit - punct.length) + punct;
    }

    str = "";
    for (var i = 0; i < words.length; i++) {
        clipStr = str + (i === 0 ? "" : " ") + words[i];

        // String has reached the character limit
        // ignore html entities when couting the number of characters
        if ((clipStr.replace(ent, "_") + punct).length > charLimit) {
            // if last character is a puntuaction character
            if (str.substring(str.length, str.length - 1).match(/[\.\?\!]/)) {
                return str;
            }
            // remove last character if is different of a number or a letter
            else if (str.substring(str.length, str.length - 1).match(/[^0-9a-zA-Z]/)) {
                str = str.substring(0, str.length - 1);
            }
            // for any other situation
            return str + punct;
        }
        str = clipStr;
    }
    return str;
}

/**
 * Wrap a text by inserting line breaks "<br />".
 * @param {String} lang The ISO 639 language code of the text
 * @param {Number} charsPerLine Quantity of characters per line before the break
 * @param {Number} maxSpaces Maximum number of breaks allowed
 * @return {String} The new text contating the line breaks
 */
String.prototype.addSpaces = function(lang, charsPerLine, maxSpaces) {
    var str = this.toString();
    var words = str.split(" ");
    var aux = "";
    var spaces = 1;

    if (typeof maxSpaces === 'undefined') {
        maxSpaces = 999;
    }

    // case language is Chinese, Japanese or Korean
    if (lang.substring(0, 2).match(/(ja|zh|ko)/)) {
        var times = Math.ceil(str.length / charsPerLine);
        var chars = 0;

        for (var i = 0; i < times; i++) {
            aux += str.substring(chars, chars + charsPerLine);
            if (i < times - 1) {
                aux += "<br />";
            }
            chars += charsPerLine;
        }
        return aux;
    } else {
        str = "";
        for (var u = 0; u < words.length; u++) {
            if (words[u] === "") {
                continue;
            }
            aux += (aux.length > 0 ? " " : "") + words[u];

            if (aux.replace(/\&([a-zA-Z]{2,6};|#[0-9]{3};)/g, "_").length > charsPerLine) {
                if (spaces >= maxSpaces) {
                    break;
                }
                str += "<br />" + words[u];
                aux = words[u];
                spaces++;
            } else {
                str += (str.length > 0 ? " " : "") + words[u];
            }
        }
        return str;
    }
}

/**
 * Constructor of the IbmRssFedModule object.
 * @param {number} id Identification number of the current object instance
 * @return A new IbmRssFedModule
 */
function IbmRssFedModule(id) {
    this.homePath			= "http://www.ibm.com/common/js/rssdisplaymodule/";
    //this.xmlProxyPath		= "http://www-941.ibm.com/RSS/readxml.php";
    this.xmlProxyPath		= "http://gtt.bluehost.ibm.com/projects/rssmodules/rdm/jsFeed/readxml.php";
    this.id					= id;					// Object id
    this.divId				= "rssdisplay-" + id;	// The id of the div element which will have the module
    this.$obj 				= null;					// Reference to jQuery object


    /**
     * Validate the value of a variable. In case the value is invalid the variable
     * receives a default value and an error message is generated when it is mandatory
     * @param {String} varName The name of the global variable
     * @param {boolean} isMandatory Variable is mandatory (True / False)
     * @param {String} defaultValue Default value to be assigned when the variable value is invalid
     * @param {regExp / Array} validation A Regular Expression, or an Array (containing the minimal numeric value
     * in the first index and the maximum numeric value in the second index) used to validate the variable value.
     * @return {String} A valid value for the variable
     */
    this.checkVariableValue = function(varName, isMandatory, defaultValue, validation) {
        // If a value has not been assigned to the variable
        if (typeof window[varName] === 'undefined') {
            if (isMandatory) {
                this.status = 'error';
            }
        } else if (window[varName] === null && isMandatory) {
            this.status = 'error';
        } else {
            // Reset every parameter so they will not assign wrong values for the next module
            if (window[varName] !== null) {
                // Validate the variable value
                if (validation.constructor === /regexp/.constructor) { // Regular expression?
                    if (validation.test(window[varName])) {
                        return (window[varName]).match(validation)[0];
                    }
                } else if (validation.constructor === [].constructor) { // Array?
                    if (window[varName] >= validation[0] && window[varName] <= validation[1]) {
                        return window[varName];
                    }
                } else if (isMandatory) {
                    this.status = 'error';
                }
            }
        }
        // if a required variable was not defined or its value is not valid
        if (this.status === 'error') {
            errors += '\nPlease you need to set a value for the variable "' + varName + '".';
        }
        return defaultValue;
    };

    this.subhead		= this.checkVariableValue('ibmrssfed_subhead',false, null, /[^\n]+/);
    this.position		= this.checkVariableValue('ibmrssfed_position',false, '1', /[1, 4]/);
    this.getQuantity	= parseInt(this.checkVariableValue('ibmrssfed_getQuantity', false, '6', [2, 10]));
    this.design			= this.checkVariableValue('ibmrssfed_design', false, 'v14', /(v14|v16)/);
    this.LC				= this.checkVariableValue('ibmrssfed_LC', false, 'en', /(en|fr)/);
    this.encoding		= this.checkVariableValue('ibmrssfed_encoding', false, 'utf-8', /utf-8/);
    this.style			= this.checkVariableValue('ibmrssfed_style', false, 'cycle', /(list|cycle|table)/);
    this.placement		= this.checkVariableValue('ibmrssfed_placement', false, 'content-area', /[a-z\-]+/);
    this.clipLevel		= parseInt(this.checkVariableValue('ibmrssfed_clipLevel', false, '60', [10, 100]));
    this.feedUrl		= this.checkVariableValue('ibmrssfed_feedUrl',true, null, /[^\s]+/);
    this.showQuantity	= parseInt(this.checkVariableValue('ibmrssfed_showQuantity', false, '3', [1, 6]));
    this.cycles			= parseInt(this.checkVariableValue('ibmrssfed_cycles', false, 3, [1, 5]));
    this.onTimePause	= parseInt(this.checkVariableValue('ibmrssfed_onTimePause', false, 3, [1, 5]));
    this.fadeDuration	= parseFloat(this.checkVariableValue('ibmrssfed_fadeDuration', false, 1, [0.5, 2]));
    this.random			= this.checkVariableValue('ibmrssfed_random', false, 'no', /(yes|no)/);
    this.selectBy		= this.checkVariableValue('ibmrssfed_selectBy', false, 'asInFeed', /(dateOrder|alphaOrder|asInFeed)/);
    this.pretext		= this.checkVariableValue('ibmrssfed_pretext', false, null, /[^\n]+/);
    this.postText		= this.checkVariableValue('ibmrssfed_postText', false, null, /[^\n]+/);
    this.postLinkText	= this.checkVariableValue('ibmrssfed_postLinkText', false, null, /[^\n]+/);
    this.postLinkUrl	= this.checkVariableValue('ibmrssfed_postLinkUrl', false, null, /[^\n]+/);

    // Other properties
    this.newsitem		= [];			// all news item from the RSS feed
    this.nextNews		= 0;			// index of the news array which correspond to the next news item to be displayed
    this.loopNumber		= 0;			// current loop number being played
    this.timer			= 0;			// timer resposible to display next news
    this.timerFade		= 0;			// timer resposible to manage fade-in / fade-out effect
    this.timerStop		= 0;			// timer responsible to manage auto-stop cycle animation
    this.mouseoverBol	= false;		// if cursor is over the link, pause the cycle animation
    this.fading			= false;		// make the fade-in / out effects perform faster
    this.loaded			= false;		// module has been loaded?
    this.goFaster		= false;		// make the transition of news items faster
    this.rssLang		= "";			// Language of the RSS feed file
    var stopRotation	= false;		// if cycle animation has reached the looping limit
    var errors			= "";


    /**
     * Display and move the tool tip according to the cursor position
     * @param {String} tooltip Text to be displayed in the tool tip
     * @param {Object} e Mouse move event object
     * @return {void} 
     */
    this.moveToolTip = function (tooltip, e) {
        var toolTipWidth = 148;
        var marginTop = (this.design === 'v16' ? -65 : 25);
        var ev = (typeof e === 'undefined' ? window.event : e);
        var coordY = ibmCommon.getEventY(ev);

        if (jQuery.browser.msie) {
            coordY += (document.documentElement.scrollTop + 2);
        }

        if (tooltip) {
            if (typeof tooltip === 'string') {
                jQuery("span.rssdisplay-displaynews:eq(0)", this.$obj).html(tooltip);
            }

            jQuery("span.rssdisplay-displaynews:eq(0)", this.$obj)
                .show()
                .css("width", (toolTipWidth + (screen.width * 0.02)) + 'px')
                .css("marginLeft", (screen.width > 800 ? ev.clientX * 0.1 - 65 : -22) + 'px')
                .css("top", (coordY + marginTop) + 'px')
                .end();
        } else {
            jQuery("span.rssdisplay-displaynews:eq(0)", this.$obj).hide();
        }
    };


    /**
     * Insert a div element into the right side navigation of the page. The RSS-fed Module 
     * and error messages will be placed inside it.
     * @return {void} 
     */
    this.init = function () {
        var that = this;

        // Insert the module div into the right side navigation of the page
        if (this.design === "v16") {
            if (this.placement === "content-area") {
                jQuery("#ibm-content-main").append('<div class="rssdisplay" id="' + this.divId + '"></div>');
            } else if (this.placement === "right-column") {
                jQuery("#ibm-content-sidebar").append('<div class="rssdisplay" id="' + this.divId + '"></div>');
            } else if (jQuery("#" + this.placement).length > 0) {
                jQuery("#" + this.placement).append('<div class="rssdisplay" id="' + this.divId + '"></div>');
            }
        } else {
            jQuery("#right-nav").append('<div class="rssdisplay" id="' + this.divId + '"></div>');
        }

        if (this.id === 0) {
           window.setTimeout(function () {
               that.loadNextIbmRssFedModule();
           }, 80);
        }
    };


    /**
     * Starts to load the module by adding the required CSS style sheets and making a 
     * server-side request to get the news items from an RSS-feed file
     * @return {void} 
     */
    this.load = function () {
        this.$obj = jQuery("#" + this.divId);

        // Try to fix URL if typed incorrectly
        if (this.feedUrl) {
            this.feedUrl.replace(/^www\./, "http://www.");
            this.feedUrl.replace(/^\/\//, "http://");
        }

        // Load main CSS styles
        if (!jQuery("#rdm-styles").length) {
            jQuery('<link href="' + this.homePath + 'rdm.css" rel="stylesheet" media="all" title="www" type="text/css" id="rdm-styles"/>').appendTo('head');
        }

        // Load CSS styles to fix layout issues in MSIE 6.0
        if (jQuery.browser.msie && jQuery.browser.version.match("6.0") && !jQuery("#rdm-styles-ie6").length) {
            jQuery('<link href="' + this.homePath + 'rdm_fix_ie6.css" rel="stylesheet" media="all" title="www" type="text/css" id="rdm-styles-ie6"/>').appendTo('head');
        }

        jQuery.getScript(this.xmlProxyPath + "?url=" + encodeURIComponent(this.feedUrl) + "&id=" + this.id + "&ttl=15");

        displayErrorMessage();
    };


    /**
     * Load RSS-fed Modules in sequence.
     * RSS-fed Modules must be loaded sequentially one after another, avoiding
     * to use too much system resources
     * @return {void} 
     */
    this.loadNextIbmRssFedModule = function () {
        for (var i = 0; i < arrayOfRssFedModule.length; i++) {
            if (!arrayOfRssFedModule[i].loaded) {
                currentRssFedModuleIndex = i;
                arrayOfRssFedModule[i].load();
                return;
            }
        }
    };

    /**
     * Check, organize, and prepare the news items just extracted from the 
     * RSS-fed file in an Array
     * @return {void} 
     */
    this.validate = function() {
        var sortByTitle = function(a, b) {
            var x = a.title.toLowerCase();
            var y = b.title.toLowerCase();
            return ((x < y) ? -1 : ((x > y) ? 1 : 0));
        };

        var sortByDate = function(a, b) {
            var x = new Date(a.date);
            var y = new Date(b.date);
            return ((x < y) ? 1 : ((x > y) ? -1 : 0));
        };

        var sortRandomly = function () {
            return (Math.round(Math.random()) - 0.5);
        };

        /// VALIDATION - important: must be in this order
        if (this.newsitem.length < 1) {
            errors += 'Please check the feed URL address.';
            this.loaded = true;
            this.loadNextIbmRssFedModule();
        } else {
            for (var i = 0; i < this.newsitem.length; i++) {
                // Replace empty links
                if (this.newsitem[i].link === "") {
                    this.newsitem[i].link = "javascript:void(0);";
                }

                // Removes the 'Terms of use' item - present in some IBM RSS feeds
                if (this.newsitem[i].link.match(/ibm\.com\/legal/)) {
                    this.newsitem.splice(i, 1);
                }
            }

            // Which order the RSS-feed data will be taken from the list
            if (this.selectBy === 'dateOrder') {
                // Fix news items with no date tag
                for (i = 0; i < this.newsitem.length; i++) {
                    var day = this.newsitem.length - i;
                    if (this.newsitem[i].date === "") {
                        this.newsitem[i].date = new Date('01/' + day + '/1901');
                    }
                }
                this.newsitem.sort(sortByDate);
            } else if (this.selectBy === "alphaOrder") {
                this.newsitem.sort(sortByTitle);
            }

            // Check: if user wants to display more news items than available in the RSS feed file
            if (this.showQuantity > this.newsitem.length) {
                this.showQuantity = this.newsitem.length;
            }

            // Check: if user wants a pool with more news items than available in the RSS file
            if (this.getQuantity > this.newsitem.length) {
                this.getQuantity = this.newsitem.length;
            }

            // Check: pool cannot have less news items than the quantity of news items being displayed 
            if (this.getQuantity < this.showQuantity) {
                this.getQuantity = this.showQuantity;
            }

            if (this.newsitem.length === 1 || this.showQuantity === 1) {
                if (this.style === 'cycle') this.style = 'list';
            }

            // Remove elements that exceed the getQuantity
            this.newsitem.splice(this.getQuantity, 999);

            // Organise news items ramdonly
            if (this.random === 'yes') {
                this.newsitem.sort(sortRandomly);
            }

            // Remove elements which are no longer necessary
            this.newsitem.splice(this.showQuantity, 999);

            // Clip all news items titles
            for (i = 0; i < this.showQuantity; i++) {
                this.newsitem[i].clipTitle = this.newsitem[i].title.clipText(this.clipLevel, this.rssLang, '...');
            }

            // Convert to seconds
            this.fadeDuration *= 1000;
            this.onTimePause *= 1000;

            // Avoid subheads with multiple lines
            if (this.subhead) {
                if (this.design === 'v14') {
                    this.subhead = this.subhead.addSpaces(this.rssLang, 22, 99);
                    var quantityOfLines = this.subhead.match(/<br \/>/gi);
                    if (quantityOfLines) {
                        if (quantityOfLines.length + 1 > 2) {
                            this.subhead = 'ERROR: Sub-head bar title too long'; // exceed 2 lines ?
                        }
                    }
                }
                if (this.design === 'v16' && this.subhead.length > 28) {
                    this.subhead = 'ERROR: Sub-head bar title too long'; // exceed 1 line ?
                }
            } else {
                this.subhead = 'ERROR: Sub-head bar title missing';
            }
        }

        // Start to load the module
        currentRssFedModuleIndex = this.id;
        jQuery.getScript(this.homePath + this.encoding + "/rdmconfig.js");

        displayErrorMessage();
    };


    /**
     * Only necessary for "cycle" style, the method defines a fixed height for the module. So 
     * when the news items start to rotate, the height will not change between a short and
     * a long news item
     * @return {void} 
     */
    this.resizeModule = function() {
        var charsPerLine = 0;
        var pixelsPerLine = (this.design === 'v14'? 13 : 14);
        var longestNewsItem = 0;
        var quantityOfLines = 0;
        var ent = /\&([a-zA-Z]{2,6};|#[0-9]{3};)/g;
        var spaces = 0;
        var lines = 0;
        var movedElement = null;

        switch (this.rssLang.substring(0, 2)) {
            case "bg": // Bulgarian
                charsPerLine = (this.design === 'v14'? 21 : 27);
                break;
            case "he": // Hebrew
                charsPerLine = (this.design === 'v14'? 25 : 28);
                break;
            case "ja": // Japanese
                charsPerLine = (this.design === 'v14'? 14 : 14);
                break;
            case "ko": // Korean
                charsPerLine = (this.design === 'v14'? 14 : 15);
                break;
            case "sk": // Slovak
                charsPerLine = (this.design === 'v14'? 23 : 29);
                break;
            case "zh": // Chinese and Taiwanese
                charsPerLine = (this.design === 'v14'? 13 : 14);
                break;
            default: // Other languages: da, de, el, en, es, et, fi, hr, hu, it, lt, lv, nl, no, pl, pt, ro, ru, sk, sl, tr, sv
                charsPerLine = (this.design === 'v14'? 22 : 28);
                break;
        }

        for (var i = 0; i < this.showQuantity; i++) {
            this.newsitem[i].clipTitle = this.newsitem[i].clipTitle.addSpaces(this.rssLang, charsPerLine);
            spaces = this.newsitem[i].clipTitle.match(/<br \/>/gi);
            lines = (spaces ? spaces.length : 0) + 1;

            // Store the highest quantity of lines 
            if (lines > quantityOfLines) {
                quantityOfLines = lines;
                longestNewsItem = i;
            }
            // Store the index of the the longest sentence
            else if (lines === quantityOfLines) {
                if (this.newsitem[i].clipTitle.replace(ent, "_").length > this.newsitem[longestNewsItem].clipTitle.replace(ent, "_").length) {
                    longestNewsItem = i;
                }
            }
        }

        // Move the longest news item to the last position
        movedElement = this.newsitem.splice(longestNewsItem, 1);
        this.newsitem.push(movedElement[0]);

        jQuery('div.rssdisplay-opacity', this.$obj).css("height", quantityOfLines * pixelsPerLine);

    };


    /**
     * Insert the HTML code to build the module according to the specified IBM template (v14/v16) 
     * @param {Object} A JSON Object containing text labels in different languages
     * @return {void} 
     */
    this.buildModule = function(config) {
        var subheadClasses = [];
        var str = '';
        var numberOflinks = ((this.style === 'list' || this.style === 'table') ? this.showQuantity : 1);
        var controls = "";
        var changingMoreNewsMsg = "";
        var showingNewsMsg = "";
        var changingOneNewsMsg = "";

        // Create controls for cycle style
        changingOneNewsMsg = config.labels[this.LC].ibmAccess.changingOneNews;
        changingMoreNewsMsg = config.labels[this.LC].ibmAccess.changingMoreNews.replace(/ \d+/, " " + (this.onTimePause / 1000));
        showingNewsMsg = config.labels[this.LC].ibmAccess.showingNews.replace(/ \d+/gi, " " + this.showQuantity);

        controls = 
            '<div class="rssdisplay-controls">' +
            '	<a class="back-button" href="javascript:void(0);" onclick="arrayOfRssFedModule[' + this.id + '].back()"><img src="' + this.homePath + 'buttons/default/back.png" border="0" width="26" height="18" title="' + config.labels[this.LC].ibmAccess.back + '"/></a>' +
            '	<p class="rssdisplay-caption">' +
            '		<span class="show-news-msg"></span><span class="ibm-access show-news-msg">' + showingNewsMsg + '</span>' +
            '	</p>' +
            '	<a class="next-button" href="javascript:void(0);" onclick="arrayOfRssFedModule[' + this.id + '].next()"><img src="' + this.homePath + 'buttons/default/next.png" border="0" width="26" height="18" title="' + config.labels[this.LC].ibmAccess.next + '"/></a>' +
            '</div>';

        // Fix styles for IE browsers when using Asian Character Enconding
        if (jQuery.browser.msie && this.rssLang.substring(0, 2).match(/(ja|zh|ko)/)) {
            jQuery('<link href="' + this.homePath + 'rdm_fix_ie_asian.css" rel="stylesheet" media="all" title="www" type="text/css" id="rdm-styles-ie-asian"/>').appendTo('head');
        }

        /// WRITE THE MODULE FOLLOWING THE TEMPLATE
        // v14 template
        if (this.design === "v14") {
            subheadClasses = ['', 'v14-header-1-small', 'v14-header-4-small', 'v14-header-3-small', 'v14-header-3-small'];

            str += 
                '<table border="0" cellpadding="0" cellspacing="0" width="150">' +
                '<tr>';

            if (this.subhead) {
                str += '<td class="' + subheadClasses[this.position] + '">' + this.subhead + '</td>';
            } else {
                str += 
                    '<td class="lgray">' +
                    '	<img src="//www.ibm.com/i/c.gif" height="1" width="1" alt=""/>' +
                    '</td>';
            }

            str += 
            '</tr>' +
            '<tr>' +
            '	<td>' +
            '		<table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0">';

            if (this.pretext) {
                str += 
                '<tr>' + 
                '	<td class="rssdisplay-pretext" width="150">' +
                '		<p class="small">' + this.pretext + '</p>' +
                '	</td>' +
                '</tr>';
            }

            if (this.style === 'cycle') {
                str += 
                    '<tr class="ibm-access">' +
                    '	<td>' +
                    '		<p class="ibm-access">' + (this.onTimePause / 1000 > 1 ? changingMoreNewsMsg : changingOneNewsMsg) + '</p>' +
                    '	</td>' +
                    '</tr>';
            }

            for (var i = 0; i < numberOflinks; i++) {
                // Insert the html code for every news item
                str += '<tr>';

                if (this.style === 'list') {
                    str += 
                        '<td class="no-padding" width="150">' +
                        '	<table width="143" cellspacing="0" cellpadding="0" border="0">' +
                        '	<tr valign="top">' +
                        '		<td class="ipt" width="18" align="right">' +
                        '			<img class="rssdisplay-arrow" border="0" alt="" width="16" height="16" src="//www.ibm.com/i/v14/icons/fw.gif" align="absmiddle"/>' +
                        '		</td>' +
                        '		<td width="125"><p><a id="' + this.divId + '-news-' + i + '" href="" class="smallplainlink"></a></p></td>' +
                        '	</tr>' +
                        '	</table>' +
                        '</td>';
                } else {
                    str += 
                        '<td width="150">' +
                        '	<div class="rssdisplay-opacity">' +
                        '		<p class="small"><a id="' + this.divId + '-news-' + i + '" href="" class="smallplainlink"></a></p>' +
                        '	</div>' +
                        '</td>';
                }

                str += '</tr>';

                if (i < numberOflinks-1) {
                    str += 
                        '<tr>' +
                        '	<td class="dotted"><img alt="" height="1" width="1" src="//www.ibm.com/i/c.gif"/></td>' +
                        '</tr>';
                }
            }

            if (this.postText) {
                str += 
                    '<tr>' +
                    '	<td class="rssdisplay-postText" width="150">' +
                    '		<p class="small">' + this.postText + '</p>' +
                    '	</td>' +
                    '</tr>';
            }

            str += 
                '<tr>' +
                '	<td>' +
                '		<span class="rssdisplay-displaynews"></span>' +
                '	</td>' +
                '</tr>';
            
            if (this.style === 'cycle') {
                str += 
                    '<tr>' + 
                    '	<td>' + controls + '</td>' +
                    '</tr>';
            }

            if (this.postLinkText && this.postLinkUrl) {
                str += 
                    '<tr>' +
                    '	<td class="dotted">' +
                    '		<img src="//www.ibm.com/i/c.gif" alt="" height="1" width="1">' +
                    '	</td>' +
                    '</tr>' +
                    '<tr>' +
                    '	<td width="150" class="no-padding">' +
                    '		<table border="0" cellpadding="0" cellspacing="0" width="143">' +
                    '		<tr valign="top">';

                // Change the icon of the "Post Link URL" 
                // Please note that it is not being checked the MIME type

                // Is an XML/RSS file?
                if (this.postLinkUrl == this.feedUrl || this.postLinkUrl.replace(/\?.+/, "").match(/(\.rss|\.xml)$/)) {
                str += 
                    '			<td align="right" width="18" class="ipt">' +
                    '				<img src="//www.ibm.com/i/v14/buttons/feed.gif" height="16" width="16" alt=""/>' +
                    '			</td>';
                } else if (!this.postLinkUrl.match(/ibm\.com/)) { // is an external URL?
                str += 
                    '			<td align="right" width="18" class="ipt">' +
                    '				<img src="//www.ibm.com/i/v14/icons/sout.gif" height="16" width="16" alt=""/>' +
                    '			</td>';
                } else { // is an internal URL (belongs to ibm.com domain)?
                str += 
                    '			<td align="right" width="18" class="ipt">' +
                    '				<img src="//www.ibm.com/i/v14/icons/fw.gif" height="16" width="16" alt=""/>' +
                    '			</td>';
                }

                str += 
                    '			<td width="125" style="padding:5px 0 5px 0"><a href="' + this.postLinkUrl + '" class="smallplainlink">' + this.postLinkText + '</a>' +
                    '			</td>'+
                    '		</tr>' +
                    '	</table>' +
                    '	</td>' +
                    '</tr>';
            }
			/*
            if (ibmCommon.cookie.get('w3ibmProfile')) {
                str +=
                    '<tr class="rssdisplay-ibmers-msg">' +
                    '	<td width="150" class="no-padding" style="background-color:#eee">' +
                    '		<table border="0" cellpadding="0" cellspacing="0" width="143">' +
                    '		<tr valign="top">' +
                    '			<td align="right" width="18" class="ipt">' +
                    '				<img src="//www.ibm.com/i/v14/icons/fw_bold.gif" height="16" width="16" alt=""/>' +
                    '			</td>' +
                    '			<td width="125" style="padding:5px 0 5px 0">' +
                    '				<b><a href="' + config.labels[this.LC].htamLinkUrl + '" class="smallplainlink">' +
                    '				<span lang="' + this.LC + '">' + config.labels[this.LC].htamLinkLabel + '</span></a></b>' +
                    '			</td>' +
                    '		</tr>' +
                    '		</table>' +
                    '	</td>' +
                    '</tr>';
            }
			*/

            str +='</table></td></tr></table><br />';

        } else if (this.design === "v16") { // v16 template 
            subheadClasses = ["", "ibm-first", "ibm-second", "ibm-third", "ibm-third"];
            
            var innerTable = '';
            if (this.style === 'table') { //table
                innerTable = "ibm-inner-data-table";
            }

            if (this.subhead) {
                str += 
                    '<div class="ibm-container ' + innerTable + '">' +
                    '	<h2 class="' + subheadClasses[this.position] + '" style="width: auto">' + this.subhead + '</h2>';
            } else {
                str += '<div class="ibm-container ibm-alternate-three">';
            }

            str += '<div class="ibm-container-body">';

            if (this.pretext) {
                str += '<p class="rssdisplay-pretext">' + this.pretext + '</p>';
            }

            if (this.style === 'cycle') {
                str += '<p class="ibm-access">' + (this.onTimePause / 1000 > 1 ? changingMoreNewsMsg : changingOneNewsMsg) + '</p>';
            }

            if (this.style === 'list') {//list
                str += '<ul class="ibm-link-list">';

                for (var i = 0; i < numberOflinks; i++) {
                    str += 
                        '<li class="' + (i === 0 ? 'ibm-first' : '') + '">' +
                        '<a class="ibm-forward-link" id="' + this.divId + '-news-' + i + '" href=""></a>' +
                        '</li>';
                }

                str += '</ul>';

            } 
            
            if (this.style === 'table') {//table
                str += '<table border="0" cellpadding="0" cellspacing="0" class="ibm-data-table" summary="Table with RSS data">'+
                       '<thead><tr>'+
                       '<th scope="col">Date</th>'+
                       '<th scope="col">Title</th>'+
                       '</tr></thead><tbody>';

                if (this.newsitem.length > 0) {
                    for (var i = 0; i < numberOflinks; i++) {
                        str += 
                            '<tr>' +
                            '<td id="' + this.divId + '-date-' + i + '"></td>'+
                            '<td><a class="ibm-feature-link" id="' + this.divId + '-news-' + i + '" href=""></a></td>'+
                            '</tr>';
                    }
                } else {
                        str += 
                            '<tr>' +
                            '<td colspan="2">Currently there are no events.</td>' +
                            '</tr>';
                }

                str += '</tbody></table>';

            }else {
                str += '<div class="rssdisplay-opacity">';

                for (var i = 0; i < numberOflinks; i++) {
                    str += '<p><a class="ibm-feature-link" id="' + this.divId + '-news-' + i + '" href=""></a></p>';
                }

                str += '</div>';
            }

            if (this.postText) {
                str += '<p class="rssdisplay-postText">' + this.postText + '</p>';
            }

            if (this.style === 'cycle') {
                str += controls;
            }

            if (this.postLinkText && this.postLinkUrl) {
                // Change the icon of the "Post Link URL" 
                // Please note that it is not being checked the MIME type

                if (!innerTable) {
                str += 
                    '<div class="ibm-rule"><hr /></div>';
                }
                
                str += 
                    '<ul class="ibm-link-list">' +
                    '	<li class="ibm-first">';

                // Is an XML/RSS file?
                if (this.postLinkUrl == this.feedUrl || this.postLinkUrl.replace(/\?.+/, "").match(/(\.rss|\.xml)$/)) {
                str += 
                    '		<a class="ibm-rss-link" href="' + this.postLinkUrl + '">' + this.postLinkText + '</a>';
                } else if (!this.postLinkUrl.match(/ibm\.com/)) { // is an external URL?
                str += 
                    '		<a class="ibm-external-link" href="' + this.postLinkUrl + '">' + this.postLinkText + '</a>';
                } else { // is an internal URL (belongs to ibm.com domain)?
                str += 
                    '		<a class="ibm-forward-link" href="' + this.postLinkUrl + '">' + this.postLinkText + '</a>';
                }

                str += 
                    '	</li>' +
                    '</ul>';
            }
			/*
            if (ibmCommon.getCookie('w3ibmProfile')) {
                str += 
                    '<div class="rssdisplay-ibmers-msg">' +
                    '	<div class="ibm-rule"><hr /></div>' +
                    '	<p class="ibm-ind-link"><a class="ibm-forward-em-link" href="' + config.labels[this.LC].htamLinkUrl + '">' + config.labels[this.LC].htamLinkLabel + '</a></p>' +
                    '</div>';
            }
			*/

            str +=
                '		<span class="rssdisplay-displaynews"></span>';
                '	</div>';
                '</div>';
        }

        // Insert the html content on the page 
        this.$obj.html(str);

        // Resize the height of the module according to the largest news item
        if (this.style === "cycle") {
            this.resizeModule();
        }

        // Module is built. Start to rotate the news items by a time interval
        this.rotateLinks(false);
        this.loaded = true;
        this.loadNextIbmRssFedModule();
    };


    /**
     * Insert errors messages inside the div element when the building process
     * was unsuccessful
     * @return {void} 
     */
    var displayErrorMessage = function() {
        if (errors != "") {
            this.status = 'error';
            this.$obj
                .hide()
                .html("\n <!-- Errors: " + errors + "-->");
        }
    };


    /**
     * Rotate the news item by a time interval for "cycle" style. Load all 
     * news items for "list" style, just once.
     * @param {Boolean} manualAction Is the cycle animation being performed manually by
     * a user action in the the controls (True) or automatically (False) - without any
     * user interference?
     * @return {void} 
     */
    this.rotateLinks = function(manualAction) {
        var instanceOfObj = this;
        var delay;
        var rotate;

        // Create all news items only once
        if (this.style === 'list' || this.style === 'table') {
            for (var i = 0; i < this.showQuantity; i++) {
                this.setNewsItem(i, i);
            }
        }
        // Rotate news items
        else if (this.style === 'cycle') {
            delay = this.onTimePause;
            rotate = true;

            if (this.nextNews < 0) {
                // Go to the last news item if user tries to go back 
                // when it is being displayed the first news
                this.nextNews = this.showQuantity-1;
            }

            // If the limit of feeds has been reached
            if (this.nextNews >= this.showQuantity) {
                // Start again if has not reached in the loop limit
                if (this.loopNumber < this.cycles-1) {
                    this.nextNews = 0;
                    this.loopNumber++;
                }
                // Stop the cycle animation
                else if (!this.mouseoverBol) {
                    this.stop();
                    stopRotation = true;
                    if (!manualAction) {
                        return;
                    } else {
                        this.nextNews = 0;
                    }
                }
            }

            // cycle animation is NOT paused
            if (!this.mouseoverBol) {
                // Replace the news item for a new one
                this.setNewsItem(0, this.nextNews);

                // Increment the counter
                this.nextNews++;

                // Add the fade-in and fade-out time
                delay += (this.fadeDuration * 2);
            }

            if (stopRotation) {
                return;
            }

            // Set a timer to display next news item
            this.timer = setTimeout(function () { 
                instanceOfObj.rotateLinks(false)
            }, delay);
        }
    };

    /**
     * For "cycle" style, go back to the previous news item.
     * @return {void} 
     */
    this.back = function() {
        if (this.fading || jQuery('div.rssdisplay-opacity', this.$obj).css("opacity") < 0.6 ) {
            return;
        }
        this.goFaster = true;
        this.stop();
        this.nextNews -= 2; // Decrement twice, last interation already incremented the counter
        this.play();
    };


    /**
     * For "cycle" style, go to the next news item.
     * @return {void} 
     */
    this.next = function() {
        if (this.fading || jQuery('div.rssdisplay-opacity', this.$obj).css("opacity") < 0.6 ) {
            return;
        }
        this.goFaster = true;
        this.stop();
        this.play();
    };

    /**
     * For "cycle" style, stop the cycle animation.
     * @return {void} 
     */
    this.stop = function() {
        window.clearTimeout(this.timer);
    };

    /**
     * For "cycle" style, plays the cycle animation (starts to rotate news items).
     * @return {void} 
     */
    this.play = function() {
        this.rotateLinks(true);
    };


    /**
     * For "cycle" style, pause the cycle animation.
     * @param {Boolean} Is mouse over the news item? When mouse out 
     * the news item, this method must be called in order to continue 
     * the cycle animation.
     * @return {void} 
     */
    this.pause = function(pauseBol) {
        this.mouseoverBol = pauseBol;
    };


    /**
     * Set a timer to stop the cycle animation after a specified amount of 
     * seconds and when mouse is over the news item.
     * @param {Boolean} setTimerBol Set up (True) or reset (False) the timer?
     * @param {Number} time Time in seconds to stop the animation
     * @return {void} 
     */
    this.setStopTimer = function(setTimerBol, time) {
        var that = this;

        if (setTimerBol) {
            this.timerStop = setTimeout(function () { 
                that.stop();
            }, time);
        } else {
            window.clearTimeout(this.timerStop);
        }
    };


    /**
     * Creates and set up events, for the only news items which will be displayed in 
     * the "cycle" style or to the group of news items in the "list" style.
     * @param {Number} newsPosition Which news item from the module that must be set up? - 
     * "cycle" style has just one and therefore must be always 0.
     * @param {Number} newsNumber Which item from the Array of news will be taken?
     * @return {void} 
     */
    this.setNewsItem = function(newsPosition, newsNumber) {
        if (this.newsitem.length < 1) {
            return false;
        }

        var href = this.newsitem[newsNumber].link;
        var title = this.newsitem[newsNumber].clipTitle;
        var fulltitle = this.newsitem[newsNumber].title;
        var month_names = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep","Oct", "Nov", "Dec");
        var fixDate = function (dateValue) {
            dateValue = dateValue.replace(/\-/g, " ");
            var arrayOfDate = dateValue.split(" ");
            arrayOfDate[1] = Number(arrayOfDate[1]) -1;
            arrayOfDate[1] = month_names[arrayOfDate[1]];
            dateValue = arrayOfDate.join(" ");

            return dateValue;
        }
        var date = new Date(fixDate(this.newsitem[newsNumber].date));

        var formatNumber = function (numberValue) {
            var str = "";

            if (numberValue < 9) {
                str += "0";
            }
            str += numberValue;
            return str;
        }
       
        var displayDate = month_names[date.getMonth()] + " " + formatNumber(date.getDate()) + " " + formatNumber(date.getHours()) + ":" + formatNumber(date.getMinutes());
        
        var fadeDuration = (this.goFaster ? this.fadeDuration / 2 : this.fadeDuration);
        var that = this;

        if (this.style === "cycle") {
            jQuery('div.rssdisplay-opacity', this.$obj).fadeTo(fadeDuration, 0);
            this.goFaster = false;
        } else {
            fadeDuration = 0;

            // Change arrow icons when link is external
            if (this.design === 'v14') {
                jQuery("img.rssdisplay-arrow:eq(" + newsPosition + ")", this.$obj)
                    .attr("src", (href.match(/ibm\.com/) ? "//www.ibm.com/i/v14/icons/fw.gif" : "//www.ibm.com/i/v14/icons/sout.gif"))
                    .end();
            } else {
                jQuery("ul.ibm-link-list:eq(0) li:eq(" + newsPosition + ") a:eq(0)", this.$obj)
                    .attr("className", (href.match(/ibm\.com/) ? "ibm-forward-link" : "ibm-external-link"))
                    .end();
            }
        }

        window.setTimeout(function () {
            var tooltip = (that.style === "list" ? fulltitle : true);
            var currentNewsItem;

            // Set events for the news item link
            jQuery("#" + that.divId + '-news-' + newsPosition)
                .attr("href", href)
                .html(title)
                .mouseout(function (e) {
                    arrayOfRssFedModule[that.id].pause(false);
                    arrayOfRssFedModule[that.id].setStopTimer(false);
                    arrayOfRssFedModule[that.id].moveToolTip(null, e);
                })
                .mouseover(function () {
                    that.setStopTimer(true, 10 * 1000);
                })
                .end();
                
            jQuery("#" + that.divId + '-date-' + newsPosition).html(displayDate);
            
           	//jQuery("#" + that.divId + '-news-' + newsPosition)[0].onmousemove  = function (e) {
                	//arrayOfRssFedModule[that.id].moveToolTip(tooltip, e);
                	//arrayOfRssFedModule[that.id].pause(true);
//            };

            if (that.style === "cycle") {
                currentNewsItem = newsNumber + 1;
                jQuery("span.show-news-msg:eq(0)", that.$obj).html(currentNewsItem + "/" + that.showQuantity);
                jQuery("span.show-news-msg:eq(1)", that.$obj).html(jQuery("span.show-news-msg:eq(1)", that.$obj).html().replace(/ \d+/, " " + currentNewsItem));
                jQuery("div.rssdisplay-opacity", that.$obj).fadeTo(fadeDuration, 1);
                that.goFaster = false;
            }

            jQuery("span.rssdisplay-displaynews:eq(0)", that.$obj).html(fulltitle);
        }, fadeDuration);
    };

    this.init();
}




/**
 * Construct a new IbmRssFedModule object and stores it into an Array
 * @return {void} 
 */
(function createNewIbmRssFedModule() {
    // Store in an Array all IbmRssFedModule objects
    if (typeof arrayOfRssFedModule === "undefined") {
        arrayOfRssFedModule = [];
        arrayrdm = arrayOfRssFedModule;
    }

    arrayOfRssFedModule.push(new IbmRssFedModule(arrayOfRssFedModule.length));
})();