/**
 * CPanel main JS APP class, manage chart generation,
 * MVC data binding application for sitespeed and JQVMap plugin
 * 
 * @package JREALTIMEANALYTICS::CPANEL::administrator::components::com_jrealtimeanalytics
 * @subpackage js
 * @author Joomla! Extensions Store
 * @copyright (C)2014 Joomla! Extensions Store
 * @license GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html
 */
//'use strict';
(function($) {
	var CPanel = function(DOMViewSelectors) {
		/**
		 * Reference to ChartJS lib object
		 * 
		 * @access private
		 * @var Object
		 */
		var chartJS = new Array();

		/**
		 * Charts options
		 * 
		 * @access private
		 * @var Object
		 */
		var chartOptions = {
			animation : true,
			scaleFontSize : 11,
			scaleOverride : true,
			scaleSteps : 1,
			scaleStepWidth : 50
		};

		/**
		 * Chart data to render, copy from global injected scope
		 * 
		 * @access private
		 * @var Object
		 */
		var chartData = {};

		/**
		 * Element target to render chart
		 * 
		 * @access private
		 * @var HTMLElement
		 */
		var context;

		/**
    	 * Update status selector
    	 * 
    	 * @access private
    	 * @var String
    	 */
    	var updateStatusSelector = '#updatestatus label.bg-danger';
    	
    	/**
    	 * Update process button snippet with placeholder to trigger the update process
    	 * 
    	 * @access private
    	 * @var String
    	 */
    	var updateButtonSnippet = '<button id="updatebtn" data-bs-content="' + COM_JREALTIME_EXPIREON + '%EXPIREON%" class="btn btn-sm btn-primary">' + 
	    							'<span class="icon-upload" aria-hidden="true"></span> ' + COM_JREALTIME_CLICKTOUPDATE + 
	    						  '</button>';
    	
    	/**
    	 * Update progressbar snippet
    	 * 
    	 * @access private
    	 * @var String
    	 */
    	var firstProgress = '<div class="progress">' +
								'<div id="progressBar1" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">' +
									'<label class="visually-hidden">' + COM_JREALTIME_UPDATEPROGRESSTITLE + '</label>' +
								'</div>' +
							'</div>';

		/**
		 * Interact with ChartJS lib to generate charts
		 * 
		 * @access private
		 * @return Void
		 */
		function generateLineChart(elem, context, animation) {
			var elemIndex = $(elem).attr('data-bind').replace(/([{}])/g, "");
			chartData = {};

			// Instance Chart object lib
			chartJS[elemIndex] = new Chart(context);

			// Max value encountered
			var maxValue = 10;

			// Normalize chart data to render
			chartData.labels = new Array();
			chartData.datasets = new Array();
			var subDataSet = new Array();
			$.each(jrealtimeChartData[elemIndex], function(label, value) {
				var labelSuffix = label.replace(/([A-Z])/g, "_$1").toUpperCase()
				chartData.labels[chartData.labels.length] = eval('COM_JREALTIME_' + labelSuffix + '_CHART');
				subDataSet[subDataSet.length] = parseInt(value);
				if (value > maxValue) {
					maxValue = value;
				}
			});

			// Override scale
			var konstant = 1;
			if (maxValue > 100) {
				konstant = 10;
			}
			if (maxValue > 1000) {
				konstant = 80;
			}
			if (maxValue > 10000) {
				konstant = 500;
			}
			if (maxValue > 100000) {
				konstant = 5000;
			}
			chartOptions.scaleStepWidth = parseInt((maxValue * konstant) / (maxValue / 10));
			chartOptions.scaleSteps = parseInt((maxValue / chartOptions.scaleStepWidth) + 1);

			chartData.datasets[0] = {
				fillColor : "rgba(151,187,205,0.5)",
				strokeColor : "rgba(151,187,205,1)",
				pointColor : "rgba(151,187,205,1)",
				pointStrokeColor : "#fff",
				data : subDataSet
			};

			// Override options
			chartOptions.animation = animation;

			// Paint chart on canvas
			chartJS[elemIndex].Line(chartData, chartOptions);
		}
		
		/**
		 * Instantiate JQVMap plugin to render stats view map
		 * 
		 * @access private
		 * @return Void
		 */
		function generateMap() {
			$('div[data-bind="{jr-mapcharts}"]').vectorMap({
			    map: 'world_en',
			    color: '#DEDEDE',
			    hoverOpacity: 0.7,
			    selectedColor: '#666666',
			    enableZoom: true,
			    showTooltip: true,
			    values: jrealtimeChartData['geomap'],
			    scaleColors: ['#B4D6E6', '#4B97BA'],
			    normalizeFunction: 'polynomial',
			    onLabelShow: function(event, label, name, value) {
			    	label.text(name + ': ' + value);
			    }
			});
		}
		
		/**
		 * Perform the remote check to validate the updates status license
		 * If the license is valid the update button will be shown
		 * 
		 * @access private
		 * @return Void 
		 */
		function checkUpdatesLicenseStatus() {
			var updateSnippet = updateButtonSnippet;
			var replacements = {"%EXPIREON%":""};

			// Is there an outdated status?
			if($(updateStatusSelector).length) {
				// Extra object to send to server
				var ajaxParams = { 
						idtask : 'getLicenseStatus',
						param: {}
				     };
				// Unique param 'data'
				var uniqueParam = JSON.stringify(ajaxParams); 

				// Request JSON2JSON
				$.ajax({
			        type: "POST",
			        url: "../administrator/index.php?option=com_jrealtimeanalytics&task=ajaxserver.display&format=json",
			        dataType: 'json',
			        context: this,
			        async: true,
			        data: {data : uniqueParam } , 
			        success: function(data, textStatus, jqXHR)  {
						// If the updates informations are successful go on, ignore every error condition
						if(data.success) {
							replacements = {"%EXPIREON%":data.expireon};
							
							updateSnippet = updateSnippet.replace(/%\w+%/g, function(all) {
								   return replacements[all] || all;
								});
							
							// Now append the update button beside the status label
							$(updateStatusSelector).parent().after(updateSnippet);
							
							// Apply the popover
							[].slice.call(document.querySelectorAll('#updatebtn')).map(function (popoverEl) {
								let popoverInstance = new bootstrap.Popover(popoverEl,{
									template : '<div class="popover"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>',
									trigger:'hover',
									placement:'right'
								});
								return popoverInstance;
							});
						}
		            }
				}); 
			}
		}
		
		/**
		 * Start the managed update process of the componenent showing 
		 * progress bar and error messages to the user
		 * 
		 * @access public
		 * @property prototype
		 * @return void */
		 
		function performComponentUpdate() {
			var context = this;
			
			// Build modal dialog
			var modalDialog =	'<div class="jrealtimemodal modal fade" id="progessModalUpdate" tabindex="-1" role="dialog" aria-labelledby="progressModal" aria-hidden="true">' +
									'<div class="modal-dialog">' +
										'<div class="modal-content">' +
											'<div class="modal-header">' +
								        		'<h4 class="modal-title">' + COM_JREALTIME_UPDATEPROGRESSTITLE + '</h4>' +
							        		'</div>' +
							        		'<div class="modal-body">' +
								        		'<p>' + firstProgress + '</p>' +
								        		'<p id="progressInfo1"></p>' +
							        		'</div>' +
							        		'<div class="modal-footer">' +
								        	'</div>' +
							        	'</div><!-- /.modal-content -->' +
						        	'</div><!-- /.modal-dialog -->' +
						        '</div>';
			// Inject elements into content body
			$('body').append(modalDialog);
			
			var modalOptions = {
					backdrop : 'static',
					keyboard : false
				};
			
			let modalEl = document.querySelector('#progessModalUpdate');
			let modalInstance = new bootstrap.Modal(modalEl, modalOptions);
			modalInstance.show();
			
			modalEl.addEventListener('shown.bs.modal', function(event) {
				$('#progessModalUpdate div.modal-body').css({'width':'90%', 'margin':'auto'});
				$('#progressBar1').css({'width':'50%'});
				// Inform user process initializing
				$('#progressInfo1').empty().append('<p>' + COM_JREALTIME_DOWNLOADING_UPDATE_SUBTITLE + '</p>');
				
				// Extra object to send to server
				var ajaxParams = { 
						idtask : 'downloadComponentUpdate',
						param: {}
				     };
				var uniqueParam = JSON.stringify(ajaxParams); 

				// Requests JSON2JSON chained
				var chained = $.ajax("../administrator/index.php?option=com_jrealtimeanalytics&task=ajaxserver.display&format=json", {
					type : "POST",
					data : {
						data : uniqueParam
					},
					dataType : "json"
				}).then(function(data) {
					$('#progressBar1').css({'width':'75%'});
					// Inform user process initializing
					$('#progressInfo1').empty().append('<p>' + COM_JREALTIME_INSTALLING_UPDATE_SUBTITLE + '</p>');
					
					// Phase 1 OK, go with the next Phase 2
					if(data.result) {
						// Extra object to send to server
						var ajaxParams = { 
								idtask : 'installComponentUpdate',
								param: {}
						     };
						var uniqueParam = JSON.stringify(ajaxParams); 
						return $.ajax("../administrator/index.php?option=com_jrealtimeanalytics&task=ajaxserver.display&format=json", {
							type : "POST",
							data : {
								data : uniqueParam
							},
							dataType : "json"
						});
					} else {
						// Phase 1 KO, stop the process with error here and don't go on
						$('#progressBar1').css({'width':'100%'}).addClass('bg-danger');
						// Append exit message
						$('#progressInfo1').empty().append('<p>' + data.exception_message + '</p>');
						setTimeout(function(){
							// Remove all
							let modalEl = document.querySelector('#progessModalUpdate');
							if(modalEl) {
								bootstrap.Modal.getInstance(modalEl).hide();
							}
						}, 3000);
						
						// Stop the chained promises
						return $.Deferred().reject();
					}
				});
				 
				chained.done(function( data ) {
					// Data retrieved from url2 as provided by the first request
					if(data.result) {
						// Phase 2 OK, set 100% width and mark as completed the whole process
						$('#progressBar1').css({'width':'100%'}).addClass('bg-success');
						// Inform user process initializing
						$('#progressInfo1').empty().append('<p>' + COM_JREALTIME_COMPLETED_UPDATE_SUBTITLE + '</p>');
						
						// Now refresh page
						setTimeout(function(){
							window.location.reload();
						}, 1500);
					} else {
						// Set 100% for progress
						$('#progressBar1').css({'width':'100%'}).addClass('bg-danger');
						// Append exit message
						$('#progressInfo1').empty().append('<p>' + data.exception_message + '</p>');
						setTimeout(function(){
							// Remove all
							let modalEl = document.querySelector('#progessModalUpdate');
							if(modalEl) {
								bootstrap.Modal.getInstance(modalEl).hide();
							}
						}, 3000);
					}
				});
			});
			
			// Remove backdrop after removing DOM modal
			modalEl.addEventListener('hidden.bs.modal',function(){
				$('.modal-backdrop').remove();
				$(this).remove();
			});
		}

		/**
		 * Function dummy constructor
		 * 
		 * @access private
		 * @param String
		 *            contextSelector
		 * @method <<IIFE>>
		 * @return Void
		 */
		(function __construct() {
			// Get target canvas context 2d to render chart
			if (!!document.createElement('canvas').getContext) {
				var resizeRepaintCanvas = function(animation) {
					$.each(DOMViewSelectors, function(k, elem) {
						// Get context
						context = $(elem).get(0).getContext('2d');
						// Get HTMLCanvasElement
						var canvas = $(elem).get(0);
						
						var subConstant = 1;
			        	var currentWindowWidth = $(window).width();
			        	if(currentWindowWidth > 730) {
			        		subConstant = 1.7;
			        	}
			        	// Get parent container width
						var containerWidth = $(canvas).parent().width() / subConstant;
						// Set dinamically canvas width
						canvas.width = containerWidth;
						canvas.height = 200;
						// Repaint canvas contents
						generateLineChart(canvas, context, animation);
					});
				}
				
				// Start generation
				setTimeout(function(){
            		resizeRepaintCanvas(true);
            	}, 200);
				
				$(window).on('resize', function(){
					resizeRepaintCanvas();
        		});
			}

			// Check if there is a sitespeed url to restore from the local storage
			var tooltipInstance = null;
			var dataRoleSitespeedUrl = $('#sitespeed_url');
			var storedSitespeedUrl = localStorage.getItem('jrealtimeSitespeedUrl');
			if(storedSitespeedUrl) {
				dataRoleSitespeedUrl.val(storedSitespeedUrl);
			}
			
			dataRoleSitespeedUrl.on('keyup', function(jqEvent){
				var executeSitespeedTest = $('#execute_sitespeed_test');
				localStorage.setItem('jrealtimeSitespeedUrl', dataRoleSitespeedUrl.val());
				executeSitespeedTest.attr('title', COM_JREALTIME_CPANEL_SITESPEED_EXEC + dataRoleSitespeedUrl.val());
				if(tooltipInstance) {
					tooltipInstance.dispose();
				}
				tooltipInstance = new bootstrap.Tooltip(executeSitespeedTest.get(0),{
					trigger : 'hover',
					placement : 'top',
					html : true
				});
			});
			dataRoleSitespeedUrl.trigger('keyup');

			// Init Sitespeed JS MVC controller
			var siteSpeedApplication = new JRealtimeControllerSitespeed({
				container : 'sitespeed_container',
				databind : 'jr-sitespeed'
			});
			
			// Execute test programmatically
			$('#execute_sitespeed_test').on('click', function(jqEvent) {
				siteSpeedApplication.executeTest();
			});

			// Start map plugin instance
			generateMap();

			// Check updates license status
			setTimeout(function(){
        		checkUpdatesLicenseStatus();
        	}, 500);
			
			// Component updater ignition start
			$(document).on('click', '#updatebtn', function(jqEvent){
				performComponentUpdate();
			});
		}).call(this);
	}

	// On DOM Ready
	$(function() {
		window.JRealtimeCPanel = new CPanel([ '*[data-bind="{chart_period_canvas}"]', '*[data-bind="{chart_generic_canvas}"]' ]);
	});
})(jQuery);