var Graphs = {

	 /**
     * This object keeps data about the option graphs, its filled within init()
     */
    graphs: {},
	
    /**
     * Contains all open positions
     */
    openPositionGraphs: {},

    nextUpdate: null,

    init: function() {

		$('#optionsList .graphContainer').each( function (i) {

		   var chart_id = 'assetChart_' + (i+1);
		   $('<div/>').attr('id', chart_id).addClass('assetChart').appendTo(this);

		   Graphs.graphs[chart_id] = {
				series : {},
				options : {},
				currRate: null,
				itemName: null,
				container:  this,
				plot : null
		   };

		   /** Initialize the graphs on Pro platform only
			* (on fast platform the call is at homeCompact::showGraph)
			*/
		   if (AppData.platformMode == 'pro')
			   Graphs.loadChartData(chart_id);
		 
		   Graphs.startStreaming();

		});

   
    },
	
	startStreaming: function () {

        var page = General.initLightstreamer();

        // Each graph container has an id in this format: graphContainer_<assetId>,
		// near each graph the is the put/call window container in which the customer
		// places his bid.
		// That window contains the option id which advertises that asset in a hidden input.
		//
        // we need to fill up an array of assetIds which will be sent to lightstreamer
        // for subscription.
		//
		// **** There array items are string of the following format:
		//		asset_<assetId>_<optionId>_<whiteLabelName>

        var assetsToSubscribe = [];

		$.each(Graphs.graphs, function(key) {
            
			if (key.indexOf('assetChart_') !== -1) {
				var assetId =  this.container.id.split('_')[1];
                
				if (AppData.platformMode == 'fast'){
                    var optionContainer = $(this.container).parent().parent().prev().prev();
                    var selectedExpireTime = optionContainer.find('div.expireTimeContainer ul li.selected');
                    if (selectedExpireTime.length){
                        var optionId = selectedExpireTime.attr('id').split('_').splice(2,1);
                        optionContainer.next().find('div.putCallFolder input[name="optionId"]').val(optionId);
                    }else{
                         var optionId = $(this.container).parents('li').prev('.applyPosition').find('input[name=optionId]').val();
                    }
                }
				else{
                   var optionContainer = $(this.container).parent().parent();
                   var selectedExpireTime = optionContainer.find('div.expireTimeContainer ul li.selected');
                   if (selectedExpireTime.length){
                        var optionId = selectedExpireTime.attr('id').split('_').splice(2,1);
                        optionContainer.find('div.putCallFolder input[name="optionId"]').val(optionId);
                   }else{
                       var optionId = $(this.container).parent().parent().find('.putCallFolder').find('input[name=optionId]').val();

                       /* option builder graphs does not have pricing rate, therefore the optionId will be 0 */

                       if (typeof(optionId) == 'undefined')
                           optionId = "0";

                   }
                }
                
				this.itemName = 'asset_' + assetId + '_' + optionId + '_' + AppData.whiteLabelName;
				assetsToSubscribe.push (this.itemName);
			}
		});

        if (typeof('SixtySeconds') != 'undefined'  && AppData.platformMode == 'pro' ){
            assetsToSubscribe = SixtySeconds.subscribe(assetsToSubscribe);
        }

        $('div.open_positions ul.positions li.open_position').each(function() {
            var assetId = this.id.split('_')[3];
            var optionId = $(this).attr('optionid');
            var itemName = 'asset_' + assetId + '_' + optionId + '_' + AppData.whiteLabelName;
            //if (-1 === jQuery.inArray( itemName, assetsToSubscribe) ) {
	    /**
 	  *  Fix bug when the open positions are not updated as win/lose when the option is not opened in the box
 	  */
 	  var itemExists = jQuery.inArray(itemName, assetsToSubscribe);
 	  if (-1 ===  itemExists || typeof(itemExists) == 'undefined') {
       
                assetsToSubscribe.push ( itemName );
            }

        });
        
        page.removeTable('assetsTable');
                   
        var assetsTable   = new NonVisualTable(assetsToSubscribe, ['rate', 'id', 'lastUpdated', 'color', 'pricingRate'], "MERGE");
        page.addTable(assetsTable, "assetsTable");
        assetsTable.onItemUpdate =  Graphs.onItemUpdate; //Graphs.onItemUpdate;
    },

	// This method should be called when user selects another asset from the options drop select box
    notifyAssetChange: function( graphContainer ) {

        var chart_id = graphContainer.find('.assetChart').attr('id');

        if (chart_id) {
            Graphs.loadChartData( chart_id );
        }
    },

	/**
     * Calculate next graph update, at every round 30 seconds,
     * if now the time is 12:11:21 then the update will occur in 12:11:30
     */
    calculateNextUpdate: function() {
        var nextUpdate = Math.floor( General.dateTime.getTime() / 30000 ) * 30 + 30;
        return new Date(nextUpdate * 1000);
    },

    /**
     * Loads a given chart data, chart_id is a key in Graphs.graph object,
     * a chart knows which asset data it should load, the asset id is located
     * in its parent container id ( div#graphContainer_<assetId> ).
     *
     * @param string chart_id - chart to update
     */
    loadChartData: function(chart_id, customOption) {
 	 	var graphContainer   = $('#' + chart_id).parent('div.graphContainer');
 	 	var graphContainerId = graphContainer.attr('id');
		//var assetId = $('#' + chart_id).parent('div.graphContainer').attr('id').split('_')[1];

		if (graphContainerId === null){
 	 	      return;
 	      }
 	 	  var assetId = graphContainerId.split('_')[1];
			if (AppData.platformMode == 'pro')
			var boxList = $('#' + chart_id).parent().parent().parent().parent();
		else //Fast (compact) platform
			var boxList = $('#' + chart_id).parent().parent().parent().prev().prev();

		 $.ajax({
                url: AppData.url + 'home/getAssetGraphJSON/' + assetId,
                method: 'GET',
                dataType: 'json',
                success: function (graphData) {
					Graphs.graphs[chart_id].options = graphData.options;
					if(graphData.series.length){
						Graphs.graphs[chart_id].series = [];
						$.each(graphData.series, function(i, data){
							Graphs.graphs[chart_id].series.push(data);
						});
					}
					else{
						Graphs.graphs[chart_id].series = [graphData.series];
						graphData.series =  new Array(graphData.series);
					}
					var graphEL = $('#' + chart_id);

					// Get asset id from its parent container's id'
					var assetId = graphEL.parent('div.graphContainer')
									.attr('id').split('_')[1];

					if (AppData.platformMode == 'pro')
						var optionId = $('#' + chart_id).parent('div.graphContainer').parent().parent().find('.putCallFolder').find('input[name=optionId]').val();
					else //Fast (compact) platform
						var optionId = $('#' + chart_id).parents('li').prev('.applyPosition').find('input[name=optionId]').val();


					var itemName = 'asset_' + assetId + '_' + optionId + '_' + AppData.whiteLabelName;

					Graphs.graphs[chart_id].itemName = itemName;

					var feedId = '#feed_asset_' + chart_id.split('_')[1];

					if (graphData.series.length || graphData.series.data.length) { //graph data is available
                         /* if the graph is hidden - it means that we change asset or expire time */
                        if (AppData.platformMode == 'fast'){
                           
                            /* if the graph is not shown */
                            if (graphEL.parent().parent().parent().hasClass('hidden')){
                                Graphs.startStreaming();
                                return;
                            }
                        }

					//draw the graph
					if($(Graphs.graphs[chart_id].container).parent().is(':visible')){

					    Graphs.redraw(chart_id);
					}

						//Save current point to graphs array
					Graphs.graphs[chart_id].currRate = graphData.series[0].data.pop();
						var lastRate = Graphs.graphs[chart_id].currRate[1].toFixed(graphData.options.yaxis.tickDecimals);
						$(feedId).html(lastRate);

						if (!customOption) { //Regular option
							/*if (typeof Position !== 'undefined' && Position.onRateChange) {
								var positionContainer = $(feedId).parents('.positionContent');
								// fill current rate in the put/call form. (** NOTE: it was disabled before for "fast" platform)
								Position.onRateChange(positionContainer.find('input.rate'), lastRate);
							}*/
						}
					} else { //No data!
						//Empty graph
						Graphs.graphs[chart_id].series[0].data = new Array();
						Graphs.graphs[chart_id].currRate = null;

						//draw the graph
						Graphs.redraw(chart_id);

						if (graphData === 'Not tradeable') {
							$(feedId).html('<div style="position:absolute;width:200px;">Not Tradeable</div>');
						} else {
							$(feedId).html('N/A');
						}
					}


					/* subscribe the items with the LS */
					Graphs.startStreaming();

					if (AppData.platformMode == 'pro'){
						Home.completeLoadingBoxList(boxList);
					}
					
				} //end success()
            });
	
    },

	 /**
     *
     * Called every lightstreamer clock tick.
     *
     * When called first time, initializes lightstreamer graphs
     *
     * Periodically updates all graphs every round 30 seconds.
     * (e.g 12:20:30 and 12:21:00 are proper update periods)
     *
     * @param timeString - current time in HH:MM:SS format
     */
            onUpdateTime : function () {

        if ( Graphs.nextUpdate === null ) {
            Graphs.nextUpdate = Graphs.calculateNextUpdate();
        }


		//Check if its time to update the graph
        if (  Graphs.nextUpdate <= General.dateTime ) {
            Graphs.nextUpdate = Graphs.calculateNextUpdate();
			//Iterate through all the graphs to update them
			$.each(Graphs.graphs, function(key) {
				
                if (Graphs.graphs[key].series) {
                  
					//If rate is valid (1 element is the rate)
					if ( this.currRate && this.currRate[1]) {
                      
						if ( key.indexOf('assetChart') !== -1 &&  Graphs.graphs[key].series[0].data.length >= 119) { //Asset graph
							//Remove the first rate
							Graphs.graphs[key].series[0].data.shift();
							/* Rescale - the scale min is the new first data point time and
							 * the scale max is the latest data point time */
							var firstPoint = Graphs.graphs[key].series[0].data[0];
							Graphs.graphs[key].options.xaxis.min = firstPoint[0];
							Graphs.graphs[key].options.xaxis.max =  this.currRate[0];
						}
						//Add the new rate
						Graphs.graphs[key].series[0].data.push(this.currRate);

						//Redraw the graph
						if ($(Graphs.graphs[key].container).parent().is(':visible')){
	                                                Graphs.redraw(key);
						 }
					}
				}

            }); // end $.each

            Graphs.nextUpdate = Graphs.calculateNextUpdate();
        } // end if


    },

	 /**
     * Lightstreamer callback, update rightmost point of each graph to the
     * newly fetched asset rate.
     */
    onItemUpdate: function(item, itemUpdate, itemName) {
		if ( Graphs.nextUpdate === null ) {
			Graphs.nextUpdate = Graphs.calculateNextUpdate();
		}

        if (itemUpdate.isValueChanged('pricingRate')) {
            var pricingRate = itemUpdate.getNewValue('pricingRate');
            var rate        = itemUpdate.getNewValue('rate');
            // -COLOR HERE
            var color = parseInt(itemUpdate.getNewValue('color'));
            var lastUpdated = itemUpdate.getNewValue('lastUpdated');

            MyPositions.updatePositionPayout(itemName,pricingRate);
            MyPositions.updateMyPayout();
            // Iterate each graph and check if its the one being updated
            $.each(Graphs.graphs, function(key) {
               if (  this.itemName  ==  itemName) {
				   //Update current rate array
				   var unixTime = new Date(AppData.serverDate + " " + lastUpdated);
				   var offset = General.serverOffset + General.browserOffset;
				   this.currRate  = new Array(unixTime.getTime() + offset, parseFloat(pricingRate));
                   
				   if ($(Graphs.graphs[key].container).parent().is(':visible') && Graphs.graphs[key].series[0].data.length > 0) { //At least 1 point
				// if (Graphs.graphs[key].series[0].data.length > 0) { //At least 1 point
					   //At least 2 points
					   if (Graphs.graphs[key].series[0].data.length > 1) {
						   //Remove the last (current) rate
							Graphs.graphs[key].series[0].data.pop();
					   }
						//Add the new rate
						Graphs.graphs[key].series[0].data.push(this.currRate);
						if ( key.indexOf('PositionGraph') !== -1 ) { //Position graph
							//Change the graph scaling if the new rate exceeds the current min/max
							if (this.currRate[1] > Graphs.graphs[key].options.yaxis.max) {
								//The new scale max should be current rate + margin fraction%
								Graphs.graphs[key].options.yaxis.max = this.currRate[1] + this.currRate[1] * AppData.positionGraphMarginFraction;
								//Also add it to min, to keep the rate leveled
								Graphs.graphs[key].options.yaxis.min = Graphs.graphs[key].options.yaxis.min - Graphs.graphs[key].options.yaxis.min * AppData.positionGraphMarginFraction;
							}

							if (this.currRate[1] < Graphs.graphs[key].options.yaxis.min) {
								//The new scale min should be current rate - margin fraction%
								Graphs.graphs[key].options.yaxis.min = this.currRate[1] - this.currRate[1] * AppData.positionGraphMarginFraction;
								//Also add it to maxn, to keep the rate leveled
								Graphs.graphs[key].options.yaxis.max = Graphs.graphs[key].options.yaxis.max + Graphs.graphs[key].options.yaxis.max * AppData.positionGraphMarginFraction;
							}

						} else if ( key.indexOf('assetChart') !== -1 ) {
							//Upgrade rate marking on asset graph
							Graphs.graphs[key].options.grid.markings[0].yaxis.from = this.currRate[1];
							Graphs.graphs[key].options.grid.markings[0].yaxis.to = this.currRate[1];
						}

						
						                    /*
 	 	 		          * If this is pro platform - update the graph always because the graph is always visible
 	 	 		           */
					if (AppData.platformMode == 'pro')
 	 	 	                     if ($('#' + key).is(':visible')){
                                                Graphs.redraw(key);
						 }else{
 	 		                    /* the graph is not visible */
						}
						else{
 	 	 	                         /* if this is fast platform - update the graph only when the graph is visible */
							if ($('#' + key).is(':visible')){
							   Graphs.redraw(key);
							}else{
							 /* the graph is not visible */
							}
						}

					}
				   
                   if ( key.indexOf('assetChart') !== -1 ) {

						// index goes from 0..N and denotes the order of rate reporting boxes
					   // first box is 0, second is 1 etc
					   var index = key.split('_')[1];

                       if(color){

                       		if($('#feed_asset_' + index).hasClass('longDisabled')){
                       			$('#feed_asset_' + index).html(pricingRate).css('color', '#BBCBBB');
                       		}
                       		else{
                       			$('#feed_asset_' + index).html(pricingRate).css('color', '#024301');
                       		}
                       }
					   else{
					   		if($('#feed_asset_' + index).hasClass('longDisabled')){
					   			$('#feed_asset_' + index).html(pricingRate).css('color', '#DAC3C3');
					   		}
					   		else{
					   			$('#feed_asset_' + index).html(pricingRate).css('color', '#C30700');
					   		}

                   		}

						/* update the rate in options builder box */
                        if (AppData.optionsBuilderEnabled){
                            if (typeof(OptionsBuilder != 'undefined') && (typeof Graphs.graphs['assetChart_0'] != 'undefined'))
 	 	 	         OptionsBuilder.onItemUpdate(item,itemUpdate,itemName); //Only call it if there is already a customer (id=0) option builder option
                        }
                   }

                   

				   if (AppData.platformMode == 'fast')
				   // this sets the rate in the box found the put/call form when you click put/call
						$('#putcall_rate_' + index).val(pricingRate);

                   if (typeof Position !== 'undefined' && Position.onRateChange) {
                        var positionContainer = $('#feed_asset_' + index).parents('.positionContent');
                        // fill current rate in the put/call form.
                        Position.onRateChange(positionContainer.find('input.rate'), pricingRate);
                   }

               }

            }); // end $.each

            /* update Sixty Seconds box graph */
            if (typeof(SixtySeconds != 'undefined'  && AppData.platformMode == 'pro' )){
                    SixtySeconds.onItemUpdate(item,itemUpdate,itemName);
            }
        }
    }, // end onItemUpdate()

	redraw : function (chart_id) {
		var graphEL = $('#' + chart_id);
		
		if (Graphs.graphs[chart_id].plot != null) {
			graphEL.unbind();
		}

		// Save the label visibility for after the re-draw
		var labelVisibility = graphEL.find('div.legend').css('visibility');
		
		Graphs.graphs[chart_id].plot = $.plot(graphEL, Graphs.graphs[chart_id].series, Graphs.graphs[chart_id].options);

		//Re-set the visility and update the last hovered rate
		if(labelVisibility && labelVisibility == 'visible') {
			var lastHoveredRate = Graphs.graphs[chart_id].series[0].data[Graphs.graphs[chart_id].lastPos];
			Graphs.showLabel(chart_id, lastHoveredRate[0], lastHoveredRate[1], Graphs.graphs[chart_id].plot);
			graphEL.find('div.legend').css('visibility', labelVisibility);
		}
		
		//Highlight the last rate
		Graphs.graphs[chart_id].plot.highlight(0, Graphs.graphs[chart_id].series[0].data.length-1);


		//Bind the hover event to update the legend with current point
		graphEL.bind("plothover",  function (e, pos, item) {
			Graphs.onGraphHover(pos, Graphs.graphs[chart_id].plot, Graphs.graphs[chart_id].series[0], graphEL);
		});

		graphEL.bind("mouseout",  function (e) {
			graphEL.find('div.legend').css('visibility','hidden');
		});
	},

	onGraphHover : function (pos, plot, series, graphEL) {
		
		if (!series.data.length)
			return;

		var axes = plot.getAxes();
		if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
			pos.y < axes.yaxis.min || pos.y > axes.yaxis.max) {
			return;
		}

		var j;
		var chart_id = graphEL.attr('id');

		var lastElement = (series.data.length-1);
		// find the nearest points, x-wise
		for (j = 0; j < lastElement; ++j) {
			if (series.data[j][0] > pos.x) {
				break;
			}
		}

		if (chart_id.indexOf('oneTouchGraph_') == -1) { //Not one touch graph
			//Save the last position (index of the series data) found
			Graphs.graphs[chart_id].lastPos = j;
		}

		// now interpolate
		var y = 0, p1 = series.data[j-1], p2 = series.data[j];
		if (p1 == null || j == lastElement) { //First or last point
			y = p2[1];
		}else if (p2 == null) {
			y = p1[1];
		} else
			y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);
		

		Graphs.showLabel(chart_id, pos.x, y, plot);

	},

	showLabel : function (chart_id, time, rate, plot) {

		var graphOptions = plot.getOptions();
		var graphEL = $('#' + chart_id);

		//Convert time back to UTC
		var time = (time - General.serverOffset);
		var d = new Date(time + AppData.timeZoneOffset);
		
		var hours =  d.getHours();
		var minutes = d.getMinutes();
		var seconds = d.getSeconds();
		
		if ( hours < 10) hours     = '0' + hours;
        if ( minutes < 10) minutes = '0' + minutes;
        if ( seconds < 10) seconds = '0' + seconds;

		var labelText = "Rate: " + rate.toFixed(graphOptions.yaxis.tickDecimals) + ' Time: ' + hours + ':' + minutes + ':' + seconds;
		legend = graphEL.find('.legendLabel');
		//Update the label element text
		legend.text(labelText);
		
		if (chart_id.indexOf('oneTouchGraph_') == -1) { //Not one touch graph
			//Update the label in the series options
			Graphs.graphs[chart_id].series[0].label = labelText;
		}

		//Show the label
		graphEL.find('div.legend').css('visibility','visible');


	},

	drawOneTouch : function(graphEl) {
		var optionId = graphEl.attr('optionId');
		
		if (optionId > 0) {
		
			$.ajax({
					url: AppData.url + 'home/getOneTouchGraphJSON/' + optionId,
					method: 'GET',
					dataType: 'json',
					success: function (graphData) {
						var options = graphData.options;
						var series = [ graphData.series ];
						var plot = $.plot(graphEl, series, options);

						//Bind the hover event to update the legend with current point
						graphEl.bind("plothover",  function (e, pos, item) {
							Graphs.onGraphHover(pos, plot, series[0], graphEl);
						});

						graphEl.bind("mouseout",  function (e) {
							graphEl.find('div.legend').css('visibility','hidden');
						});
					}
				 });
		}
	},
	
	/**
     * Loads graphs into containers which class is "oneTouchGraph".
     *
     *
     */
    loadOneTouchGraphs: function() {
        // Iterate through containers and initialize their graphs
         $('.oneTouchGraph').each ( function(i) {
			 var el = $(this)
             this.id = 'oneTouchGraph_' + i;
			 Graphs.drawOneTouch(el);
        }); // end $.each

    } // end loadOneTouchGraphs();


};

//Auto init on-ready
$(Graphs.init);
