/**
 * Javascript class TeletraderHttpPush
 *
 * @category Public
 * @package  BM
 * @author   Rico Sonntag <rico.sonntag@netresearch.de>
 * @version  $Id: http.push.teletrader.js 1428 2010-09-30 08:57:23Z rico.sonntag $
 */

/**
 * The function checks if a given element already exists in an array
 *
 * @param array
 * @param element
 *
 * @return boolean
 */
function in_array(array, element)
{
    for (var i = 0, l = array.length; i < l; ++i) {
        if (array[i] == element) {
            return true;
        }
    }

    return false;
}

/**
 * TeletraderHttpPush
 */
function TeletraderHttpPush()
{
    var _authToken  = null;
    var _symbolList = {};
    var _fids       = [];
    var _ajaxUrl    = null;
    var _self       = this;
    var _prefix     = '';

    // number of symbols to subscribe at once
    var _maxSubscriptionsAtOnce = 3;

    /**
     * Set field ids of requested values
     *
     * @param array fids Field ids
     *
     * @access public
     */
    this.setFids = function(fids)
    {
        _fids = (fids instanceof Array) ? fids : [];
    };

    /**
     * Set ajax request url
     *
     * @param url
     *
     * @access public
     */
    this.setAjaxUrl = function(url)
    {
        _ajaxUrl = url;
    };

    /**
     * Set prefix to force realtime for special cases
     *
     * @param prefix
     *
     * @access public
     */
    this.setPrefix = function(prefix)
    {
        _prefix = prefix + '_';
    };

    /**
     * The function parses the document and extracts all updatable fields and
     * returns a list with the field information.
     *
     * @access private
     */
    this.prepareSymbols = function()
    {
        var symbolIds = jQuery(':regex(id, ' + _prefix + 'real_tts-([0-9]*)_([^.]*))');

        // No symbols found
        if (!symbolIds.length) {
            return;
        }

        var idList = {};

        // Parse document using some regular expression to match the tt ids
        jQuery.each(symbolIds, function() {
            var id      = this.id;
            var element = jQuery(this);

            if (!idList[id]) {
                idList[id] = 0;
            }

            // Set an unique id to all fields
            // (counting the number of duplicated elements)
            id = id + '_' + (++idList[id]);

            // Set id to the element
            element.attr('id', id);

            // Splitt up id
            var splitted   = id.split('_');
            var startIndex = 1;

            if (splitted[1].indexOf('tts-') == -1) {
                startIndex = 2;
            }

            var ttid  = splitted[startIndex];
            var field = splitted[startIndex + 1];

            // Filter all static fields except date and time
            if ((field === 'static-date') || (field === 'static-time')) {
                field = 'dateTime';
            }

            if (field.indexOf('static') == -1) {
                if (!_symbolList[ttid]) {
                    _symbolList[ttid] = {
                        'id'         : ttid.substring(ttid.indexOf('-') + 1),
                        'fields'     : [],
                        'css'        : element.css('background-color'),
                        'elements'   : [],
                        'lastvalues' : []
                    };
                }

                if (!in_array(_symbolList[ttid].fields, field)) {
                    _symbolList[ttid].fields.push(field);
                    _symbolList[ttid].elements[field] = [];
                    _symbolList[ttid].lastvalues[field] = parseFloat(
                        element.html()
                            .replace(/€/,  '')
                            .replace(/ /,  '')
                            .replace(/\+/, '')
                            .replace(/\./, '')
                            .replace(/\,/, '.')
                    );
                }

                _symbolList[ttid].elements[field].push(element);
            }
        });
    };

    /**
     * Get a new security token
     *
     * @access private
     * @return response
     */
    function getNewAuthorizationToken()
    {
        // Ajax request
        return jQuery.ajax({
            'url'      : _ajaxUrl,
            'type'     : 'GET',
            'dataType' : 'text',
            'async'    : false
        }).responseText;
    }

    /**
     * Perform an animation to visualize the change of an value
     *
     * @access public
     *
     * @param item
     * @param value
     * @param startColor
     * @param endColor
     * @param duration
     */
    this.animateChange = function(item, value, startColor, endColor, duration)
    {
        duration = duration || 500;

        item
            // Perform some fadein / fadeout of the background colors
            .animate({ 'backgroundColor' : startColor }, {
                'duration' : duration,
                'complete' : function() {
                    item.html(value);
                }
            })
            .animate({ 'backgroundColor' : endColor }, duration)

            // Force background color reset
            .css('background-color', endColor);
    };

    /**
     * Set a new value to a specified field, performing some
     * change animation if the value differs from the previous one.
     *
     * @access public
      *
     * @param item
     * @param ttSymbol
     * @param eventValue
     * @param field
     */
    this.setValue = function(item, ttSymbol, eventValue, field)
    {
        var lastValue = _symbolList[ttSymbol].lastvalues[field];

        // only show different values
        if (eventValue !== lastValue) {
            _symbolList[ttSymbol].lastvalues[field] = eventValue;

            eventValue = parseFloat(eventValue);
            lastValue = parseFloat(lastValue);

            var endColor  = _symbolList[ttSymbol].css;
            var startColor = '#33cc00'; // green

            if (eventValue < lastValue) {
                startColor = '#ff9797'; // red
            }

            var sign     = '';
            var decimals = 2;

            if ((field == 'change') || (field == 'changePercent')) {
                if (eventValue < 0.0) {
                    item
                        .removeClass('vup')
                        .addClass('vdown');

                    jQuery('#' + ttSymbol + '_static-arrow')
                        .removeClass('arrowup')
                        .addClass('arrowdown');
                }
                else {
                    sign = '+';

                    item
                        .removeClass('vdown')
                        .addClass('vup');

                    jQuery('#' + ttSymbol + '_static-arrow')
                        .removeClass('arrowdown')
                        .addClass('arrowup');
                }
            }

            if ((field == 'bidSize') ||
                (field == 'askSize') ||
                (field == 'tradeVolume') ||
                (field == 'volume') ||
                (field == 'turnoverValue')) {
                decimals = 0;
            }

            // format the result
            var formattedValue = sign +
                number_format(eventValue, decimals, ',', '.');

            // perform change animation
            _self.animateChange(item, formattedValue, startColor, endColor);
        }
    };

    /**
     * Adjust the date value of all related fields
     *
     * @param string ttSymbol Teletrader symbol id
     * @param string newDate  The new date value to set
     *
     * @access public
     */
    this.changeDate = function(ttSymbol, newDate)
    {
        jQuery('[id*="' + _prefix + 'real_' + ttSymbol + '_static-date_"]')
            .each(function() {
                jQuery(this).html(newDate);
            });
    };

    /**
     * Adjust the time value of all related fields
     *
     * @param string ttSymbol Teletrader symbol id
     * @param string newTime  The new time value to set
     *
     * @access public
     */
    this.changeTime = function(ttSymbol, newTime)
    {
        jQuery('[id*="' + _prefix + 'real_' + ttSymbol + '_static-time_"]')
            .each(function() {
                jQuery(this).html(newTime);
            });
    };

    /**
     * Handle the channel response
     *
     * @param event
     *
     * @access public
     */
    this.handleResponse = function(event)
    {
        if (event.data) {
            for (var field in event.data) {
                if (event.data.hasOwnProperty(field)) {
                    var ttSymbol = 'tts-' + event.data.symbolId;

                    // Special handling for date/time
                    if (field == 'dateTime') {
                        _self.changeDate(ttSymbol, event.data[field].substring( 0, 10));
                        _self.changeTime(ttSymbol, event.data[field].substring(11));
                    }
                    else {
                        if (typeof(_symbolList[ttSymbol].elements[field]) !== 'undefined') {
                            // Get all current not animated elements of the given field

                            var elementLength = _symbolList[ttSymbol].elements[field].length;

                            if (elementLength) {
                                for (var i = 0; i < elementLength; ++i) {
                                    _self.setValue(
                                        _symbolList[ttSymbol].elements[field][i],
                                        ttSymbol,
                                        event.data[field],
                                        field
                                    );
                                }
                            }
                        }
                    }
                }
            }
        }
    };

    /**
     * This function performs a batch subscription of the given list of items.
     *
     * @param items
     */
    this.doBatchSubscription = function(items)
    {
        // Subscribe all given elements at once
        _cometd.batch(function() {
            for (var i = 0; i < items.length; ++i) {
                _cometd.subscribe(
                    '/teletrader/symbols/' + _symbolList[items[i]].id + '/',
                    this,
                    _self.handleResponse,

                    // Only subscribe to the requested fields for each symbol
                    // to preserve bandwith and unnecessary updates
                    { 'ext' :
                        { 'teletrader' :
                            {
                                'FIDs' : _symbolList[items[i]].fields.join(', ')
                            }
                        }
                    }
                );
            }
        });
    };

    /**
     * Subscribes all extracted symbols to the symbols channel
     *
     * @access public
     */
    this.subscribeSymbols = function()
    {
        var helperList = [];

        // Group at least _maxSubscriptionsAtOnce items together
        // to save requests
        for (var symbol in _symbolList) {
            if (_symbolList.hasOwnProperty(symbol)) {
                helperList.push(symbol);

                if (helperList.length >= _maxSubscriptionsAtOnce) {
                    this.doBatchSubscription(helperList);
                    helperList = [];
                }
            }
        }

        // Perform batch subscription of grouped elements
        if (helperList.length >= 1) {
            this.doBatchSubscription(helperList);
        }
    };

    /**
     * Connect event
     *
     * @access public
     */
    this.connected = function()
    {
        // perform subscription of symbols
        _self.subscribeSymbols();
    };

    /**
     * Disconnect event
     *
     * @access public
     */
    this.disconnected = function()
    {
    };

    /**
     * Initialize the connection to the http push server
     *
     * @access public
     */
    this.init = function()
    {
        this.prepareSymbols();

        if ((_symbolList === null) || jQuery.isEmptyObject(_symbolList)) {
            return;
        }

        _authToken = getNewAuthorizationToken();

        var handShakeParams =
            { 'ext' :
                { 'teletrader' :
                    {
                        'AuthToken' : _authToken
                    }
                }
            };

        // add field ids if provided
        if (_fids.length) {
            handShakeParams.ext.teletrader.SymbolFIDs = _fids.join(', ');
        }

        // call parent init
        this.parent.init.call(this, handShakeParams);
    };
}

TeletraderHttpPush.prototype             = new HttpPush();
TeletraderHttpPush.prototype.constructor = TeletraderHttpPush;
TeletraderHttpPush.prototype.parent      = HttpPush.prototype;

