let AsesoresController = {
	consejeros: null,
	fontSize: null,
	fontName: null,
	colors: null,
	data: [],
	graphs: [],
	countries: null,
	graphAsesores: null,
	countriesToSee: [],
	countriesToSeeDesc: '',
	seeGraphs: true,
	tableFlag: false,
	myChart: null,
	graphFlag: false,
	graphFlagAppVersion: false,
	gdpr: '',
	labelClicked: false,
	appVersionData: [],
	appVersionChart: null,
	loaders: {},
	labels: [],

	reset() {
		let self = this;

		self.consejeros = null;
		self.fontSize = null;
		self.fontName = null;
		self.colors = null;
		self.data = [];
		self.graphs = [];
		self.countries = null;
		self.graphAsesores = null;
		self.countriesToSee = [];
		self.countriesToSeeDesc = '';
		self.seeGraphs = true;
		self.tableFlag = false;
		self.myChart = null;
		self.graphFlag = false;
		self.graphFlagAppVersion = false;
		self.gdpr = sessionStorage['STCMBackEnd:GDPR'];
		self.labelClicked = false;
		self.appVersionData = [];
		self.appVersionChart = null;
		self.loaders = {
			getAnalyticsConsejeros: false,
			getAnalyticsConsejerosAppVersion: false
		};
		self.labels = [
			pf.const.language.RSC580, // Atraidos
			pf.const.language.RSC581, // Registro Iniciado
			pf.const.language.RSC582, // Registro Finalizado
			pf.const.language.RSC583, // Perfilados
			pf.const.language.RSC584, // Licencias Adquiridas
			pf.const.language.RSC585, // Liciencias En Uso
			pf.const.language.RSC32, // Asesores
			pf.const.language.RSC586, // Asesores activos
			pf.const.language.RSC309, // Staff
			pf.const.language.RSC1829, // Administradores
			pf.const.language.RSC587 + ' CLABE', // Asesores sin CLABE
			pf.const.language.RSC588 + ' CLABE' // Asesores con CLABE
		];
	},

	setEvents() {
		let self = AsesoresController;
		self.reset();

		self.loadLanguage();

		// Cargar encabezados del nav
		self.setHeaders(0);

		// Valores de configuración
		let config = JSON.parse(atob(sessionStorage.getItem('STCMBackEnd:config')));
		self.fontName = config.FontAnalytics;
		self.fontSize = config.SizeFontAnalytics;
		self.colors = [];
		if(config.UsarColorDegradado == 0) {
			for(let i = 0; i < config.colores.length; i++) {
				self.colors.push(rgb2hex('rgb(' + config.colores[i].color + ')'));
			}
		} else {
			self.colors[0] = rgb2hex('rgb(' + config.RGBInicio + ')');
			self.colors[1] = rgb2hex('rgb(' + config.RGBFin + ')');
		}

		$('#mGraphs').hide();
		$('#data-table').hide();
		$('#mGraphsAppVersion').hide();

		// Activación de botón de exportar del navegador
		$('#exportSurvey').off().on('click', function() {
			self.getAnalyticsConsejerosToExport();
		});

		// Control de países permitidos por el administrador si solo hay uno
		let countries = JSON.parse(atob(sessionStorage['STCMBackEnd:userCountries']));
		let countriesDesc = atob(sessionStorage['STCMBackEnd:userCountriesDesc']);
		let advisers_country = sessionStorage['home:advisers_country'];
		let advisers_country_desc = sessionStorage['home:advisers_country_desc'];
		if(countries.length === 1) {
			self.countriesToSee = countries;
			self.countriesToSeeDesc = countriesDesc;
			$('#country').val(self.countriesToSeeDesc);
			$('#country').attr('title', self.countriesToSeeDesc);

			$('#mGraphs').show();
			$('.divGraph').show();
			$('#mGraphsAppVersion').show();
			
			// Iniciar spinner
			addLoader();
			self.getConsejeros();
			self.getConsejerosAppVersion();
		} else if(advisers_country != undefined) {
			self.countriesToSee = advisers_country;
			self.countriesToSeeDesc = advisers_country_desc;
			$('#country').val(self.countriesToSeeDesc);
			$('#country').attr('title', self.countriesToSeeDesc);
			sessionStorage.removeItem('home:advisers_country');
			sessionStorage.removeItem('home:advisers_country_desc');

			$('#mGraphs').show();
			$('.divGraph').show();
			$('#mGraphsAppVersion').show();
			
			// Iniciar spinner
			addLoader();
			self.getConsejeros();
			self.getConsejerosAppVersion();
		}
	},

	setHeaders() {
		let self = this;

		// Reducción de Header
		headerSectionHeight(0);

		// Añadir titulo
		$('#page-title').text(pf.const.language.RSC32);

		// Opciones de header
		let jsonsubopt = {
			country: 'country',
			export: 'exportSurvey'
		};

		let nav = `
			<div class="d-flex flex-row-reverse">
				<div class="d-flex">
					<button id="dropdownFilters" type="button" class="btn-nav btn d-flex align-items-center ma-le-5 secondary-button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
						<span class="ml-1">${pf.const.language.RSC1076}</span>

						<span id="svgContainerPage" class="ml-2">
							<svg class="bi bi-chevron-down" width="12" height="12" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
								<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 01.708 0L8 10.293l5.646-5.647a.5.5 0 01.708.708l-6 6a.5.5 0 01-.708 0l-6-6a.5.5 0 010-.708z" clip-rule="evenodd"/>
							</svg>
						</span>
					</button>

					<div id="profileContainerPage" class="dropdown-menu dropdown-menu-right shadow menu-actions" aria-labelledby="dropdownFilters">
						<div class="dropdown-item form-check form-check-inline">
							<input id="viewGraphs" type="checkbox" class="form-check-input" checked>
							<label for="viewGraphs" class="form-check-label c-pointer">${pf.const.language.RSC1387}</label>
						</div>

						<div class="lastElement text-right">
							<span id="loadWithFilters" class="main-color-text c-pointer">${pf.const.language.RSC2523}</span>
						</div>
					</div>

					${createSubOptionExport(jsonsubopt.export)}
				</div>
				${createSubOptionCountrySimple(jsonsubopt.country)}
			</div>
		`;

		// Acciones de página (flex-row-reverse)
		$('#page-actions').html(nav);

		// Botones secundarios
		$('#exportSurvey').addClass('secondary-button');

		// Eventos de dropdown de página
		dropDownPageEvents();

		// País
		let countryModal = new TableCountries(1, 'asesores');
		$('#searchCountry').on('click', function() {
			countryModal.setEvents();
		});

		// Cargar datos de página a través de los filtros
		$('#loadWithFilters').on('click', function() {
			// Cerrar Dropdown
			$('#dropdownFilters').dropdown('toggle');

			// Modificar visores
			if(self.seeGraphs) {
				$('#mGraphs').show();
				$('.divGraph').show();
				$('#mGraphsAppVersion').show();
			} else {
				$('#mGraphs').hide();
				$('.divGraph').hide();
				$('#mGraphsAppVersion').hide();
			}

			// Iniciar spinner
			addLoader();
			self.getConsejeros();
			self.getConsejerosAppVersion();
		});

		$('#viewGraphs').on('change', function() {
			let checkedComp = $(this).prop('checked');

			if(checkedComp) {
				self.seeGraphs = true;
			} else {
				self.seeGraphs = false;
			}
		});
	},

	getConsejeros() {
		let self = this;

		let parameters = {
			country: self.countriesToSee.toString(),
			countryDesc: self.countriesToSeeDesc
		};
		ajaxComunCallWithCallback('getAnalyticsConsejeros', parameters, self.getAnalyticsConsejeros, false);
	},

	// Callback, como sale de zona pierde el this
	getAnalyticsConsejeros(ajaxReturn) {
		let self = AsesoresController;

		let countriesISO = null;

		if(ajaxReturn) {
			// Cargamos los datos del servicio
			self.consejeros = ajaxReturn.result;
			countriesISO = ajaxReturn.result.country;

			if(self.seeGraphs) {
				// Obtener países permitidos
				let allowedCountries = JSON.parse(atob(sessionStorage['STCMBackEnd:userCountries']));

				$('#countriesGraph').html('');

				// Añadir graficas
				if(countriesISO.length > 1) {
					let n = countriesISO.length;
					let html = '';
					for(let i = 0; i < n; i++) {
						// Control de países permitidos
						if(allowedCountries.indexOf(countriesISO[i]) == -1) {
							continue;
						}

						html += `
							<div id="mGraphs${i}" class="row p-2 glass-effect divGraph">
								<div class="col-12 p-0">
									<!-- Header -->
									<div class="d-flex justify-content-between p-0 c-pointer" data-toggle="collapse" data-target="#collapseOne${i}">
										<div class="d-flex align-items-center">
											<span class="section-title mx-3">${pf.const.language.RSC2170} ${countriesISO[i]}</span>
										</div>

										<!-- Botón Collapse -->
										<button type="button" class="btn btn-link text-body text-decoration-none registerView" data-toggle="collapse" data-target="#collapseOne${i}" aria-expanded="true" aria-controls="collapseOne${i}">
											${stcmbackend.svg.chevronDown}
										</button>
									</div>

									<div id="collapseOne${i}" class="m-0 px-3 pt-3 pb-2 collapse show section-body heightGraph">
										<canvas id="graphAsesores${i}" class="bg-white c-pointer"></canvas>
									</div>
								</div>
							</div>
						`;
					}

					$('#countriesGraph').html(html);
				}

				// Mirar si quedan menos del 5% de las licencias
				let ratio = self.consejeros.total.totalLicenciasEnUso / self.consejeros.total.totalLicenciasAdquiridas;
				if(ratio >= 1.05) {
					let content = `
						<p>${pf.const.language.RSC1254}</p>

						<div class="form-group">
							<label for="numLicensesAlert" class="fw-500">${pf.const.language.RSC1255}</label>
							<input id="numLicensesAlert" type="number" class="form-control" value="">
						</div>
					`;
					let objInfo = {
						accept: {
							text: pf.const.language.RSC377
						},
						cancel: {
							text: pf.const.language.RSC57
						}
					};

					let alertTitle = pf.const.language.RSC519;
					pf.utils.showInfoDialogCustomWidthAcceptCancelNewStyle(alertTitle, content, objInfo, '500px', function() {
						let numLicenses = $('#numLicensesAlert').val();

						// Servicio de envío de información.
						self.sendEmailLicences(numLicenses);
					}, function() {});
				}

				if(countriesISO.length > 1) {
					let j = countriesISO.length;
					for(let i = 0; i < j; i++) {
						// Control de países permitidos
						if(allowedCountries.indexOf(countriesISO[i]) == -1) {
							continue;
						}
						self.graphCountry(countriesISO[i], `#graphAsesores${i}`);
						self.graphsEventsCountry(countriesISO[i], i);
					}
				}

				self.graph('#graphAsesores');
				self.graphsEvents();
			}

			let desAtr = self.consejeros.desgloseConsejerosActivos;
			let desAtrSize = desAtr.length;
			self.data = [];
			for(let i = 0; i < desAtrSize; i++) {
				desAtr[i]['admin'] = '0';
				self.data.push(desAtr[i]);
			}

			// Incluir administradores a la tabla de asesores
			let desAdmin = self.consejeros.desgloseAdminPanel;
			let desAdminSize = desAdmin.length;
			for(let i = 0; i < desAdminSize; i++) {
				let obj = {
					userEmail: desAdmin[i].userEmail,
					userNombre: desAdmin[i].userNombre,
					userApellidos: desAdmin[i].userApellidos,
					userApellidos2: '',
					countryISO: desAdmin[i].countryISO,
					country: desAdmin[i].country,
					region: '',
					edad: '',
					genero: '',
					NSE: '',
					registered: desAdmin[i].registered,
					welcome: desAdmin[i].welcome,
					consejero: desAdmin[i].consejero,
					staff: desAdmin[i].staff,
					admin: '1',
					clabe: desAdmin[i].clabe,
					enabled: desAdmin[i].enabled
				};

				self.data.push(obj);
			}

			self.table();

			// Control de spinner
			self.loaders.getAnalyticsConsejeros = true;
			spinnerControl(self.loaders);
		}
	},

	getAnalyticsConsejerosToExport() {
		let self = this;

		let reqName = 'getAnalyticsConsejerosToExport';

		let date = new Date();
		let stamp = date.getFullYear().toString() + (date.getMonth() + 1).toString() + date.getDate().toString() + date.getHours().toString() + date.getMinutes().toString();
		let nameExcel = pf.const.language.RSC32 + '_' + stamp;

		let cabeceras = [
			pf.const.language.RSC136, // E-mail
			pf.const.language.RSC123, // Nombre
			pf.const.language.RSC1626, // Apellido 1
			pf.const.language.RSC1627, // Apellido 2
			pf.const.language.RSC550, // País
			pf.const.language.RSC564, // Estado
			pf.const.language.RSC597, // Región
			pf.const.language.RSC607, // Ciudad
			pf.const.language.RSC565, // Edad
			pf.const.language.RSC151, // Género
			pf.const.language.RSC598, // NSE
			pf.const.language.RSC1899, // Consumidor
			pf.const.language.RSC1948, // Segmentación
			pf.const.language.RSC558, // Registro
			pf.const.language.RSC559, // Bienvenida
			pf.const.language.RSC560, // Asesor
			pf.const.language.RSC309, // Staff
			pf.const.language.RSC163, // Administrador
			pf.const.language.RSC308, // Cuenta clabe
			pf.const.language.RSC1718, // Estado de perfilación
			pf.const.language.RSC126, // Activo
			pf.const.language.RSC303, // Nombre de usuario
			pf.const.language.RSC113, // Fecha de creación
			pf.const.language.RSC562, // Último mensaje
			pf.const.language.RSC563, // Última videocall
			pf.const.language.RSC561, // Fecha de modificación
			pf.const.language.RSC1306, // Fecha última apertura de App
			pf.const.language.RSC1716 // CPG 
		];

		let parametros = [
			'userEmail',
			'userNombre',
			'userApellidos',
			'userApellidos2',
			'country',
			'region',
			'questionMunicipio',
			'ciudad',
			'edad',
			'genero',
			'NSE',
			'consumo',
			'segmentations',
			'registered',
			'welcome',
			'consejero',
			'staff',
			'admin',
			'clabe',
			'observaciones',
			'enabled',
			'username',
			'creationDate',
			'lastMessage',
			'lastVideoCall',
			'modificationDate',
			'lastAppVisualizationDate',
			'cpgs'
		];

		if(self.gdpr == '1') {
			cabeceras = [
				pf.const.language.RSC136, // E-mail
				pf.const.language.RSC550, // País
				pf.const.language.RSC564, // Estado
				pf.const.language.RSC597, // Región
				pf.const.language.RSC607, // Ciudad
				pf.const.language.RSC565, // Edad
				pf.const.language.RSC151, // Género
				pf.const.language.RSC598, // NSE
				pf.const.language.RSC1899, // Consumidor
				pf.const.language.RSC1948, // Segmentación
				pf.const.language.RSC558, // Registro
				pf.const.language.RSC559, // Bienvenida
				pf.const.language.RSC560, // Asesor
				pf.const.language.RSC309, // Staff
				pf.const.language.RSC163, // Administrador
				pf.const.language.RSC308, // Cuenta clabe
				pf.const.language.RSC1718, // Estado de perfilación
				pf.const.language.RSC126, // Activo
				pf.const.language.RSC303, // Nombre de usuario
				pf.const.language.RSC113, // Fecha de creación
				pf.const.language.RSC562, // Último mensaje
				pf.const.language.RSC563, // Última videocall
				pf.const.language.RSC561, // Fecha de modificación
				pf.const.language.RSC1306, // Fecha última apertura de App
				pf.const.language.RSC1716 // CPG 
			];

			parametros = [
				'userEmail',
				'country',
				'region',
				'questionMunicipio',
				'ciudad',
				'edad',
				'genero',
				'NSE',
				'consumo',
				'segmentations',
				'registered',
				'welcome',
				'consejero',
				'staff',
				'admin',
				'clabe',
				'observaciones',
				'enabled',
				'username',
				'creationDate',
				'lastMessage',
				'lastVideoCall',
				'modificationDate',
				'lastAppVisualizationDate',
				'cpgs'
			];
		}

		if(sessionStorage['STCMBackEnd:Consumer'] == 0) {
			if(self.gdpr == '1') {
				cabeceras.splice(8, 1);
				parametros.splice(8, 1);
			} else {
				cabeceras.splice(11, 1);
				parametros.splice(11, 1);
			}
		}

		let values = {
			action: reqName,
			token: sessionStorage['STCMBackEnd:token'],
			country: self.countriesToSee.toString(),
			countryDesc: self.countriesToSeeDesc,
			nameExcel: nameExcel,
			cabeceras: cabeceras,
			parametros: parametros
		};

		let generator = new DocumentsGenerator(values);
		generator.start();
	},

	getConsejerosAppVersion() {
		let self = this;

		let parameters = {
			country: self.countriesToSee.toString(),
			countryDesc: self.countriesToSeeDesc
		};
		ajaxComunCallWithCallback('getAnalyticsConsejerosAppVersion', parameters, self.getAnalyticsConsejerosAppVersion, false);
	},

	// Callback, como sale de zona pierde el this
	getAnalyticsConsejerosAppVersion(ajaxReturn) {
		let self = AsesoresController;

		let countriesISO = null;

		if(ajaxReturn) {
			// Cargamos los datos del servicio
			self.appVersionData = ajaxReturn;
			countriesISO = ajaxReturn.country;

			if(self.seeGraphs) {
				// Obtener países permitidos
				let allowedCountries = JSON.parse(atob(sessionStorage['STCMBackEnd:userCountries']));

				$('#countriesGraphAppVersion').html('');

				// Añadir graficas
				if(countriesISO.length > 1) {
					let n = countriesISO.length;
					let html = '';
					for(let i = 0; i < n; i++) {
						// Control de países permitidos
						if(allowedCountries.indexOf(countriesISO[i]) == -1) {
							continue;
						}

						html += `
							<div id="mGraphsAppVersion${i}" class="row p-2 glass-effect divGraph">
								<div class="col-12 p-0">
									<!-- Header -->
									<div class="d-flex justify-content-between p-0 c-pointer" data-toggle="collapse" data-target="#collapseOneAppVersion${i}">
										<div class="d-flex align-items-center">
											<span class="section-title mx-3">${pf.const.language.RSC2016} ${countriesISO[i]}</span>
										</div>

										<!-- Botón Collapse -->
										<button type="button" class="btn btn-link text-body text-decoration-none registerView" data-toggle="collapse" data-target="#collapseOneAppVersion${i}" aria-expanded="true" aria-controls="collapseOneAppVersion${i}">
											${stcmbackend.svg.chevronDown}
										</button>
									</div>

									<div id="collapseOneAppVersion${i}" class="m-0 px-3 pt-3 pb-2 collapse show section-body heightGraph">
										<canvas id="graphAsesoresAppVersion${i}" class="bg-white c-pointer"></canvas>
									</div>
								</div>
							</div>
						`;
					}

					$('#countriesGraphAppVersion').append(html);
				}

				// Carga de Versiones de App por país
				if(countriesISO.length > 1) {
					let j = countriesISO.length;
					for(let i = 0; i < j; i++) {
						// Control de países permitidos
						if(allowedCountries.indexOf(countriesISO[i]) == -1) {
							continue;
						}
						self.graphCountryAppVersion(countriesISO[i], `#graphAsesoresAppVersion${i}`);
						self.graphsEventsCountryAppVersion(countriesISO[i], i);
					}
				}

				self.graphAppVersion('#graphAsesoresAppVersion');
				self.graphsEventsAppVersion();
			}

			// Control de spinner
			self.loaders.getAnalyticsConsejerosAppVersion = true;
			spinnerControl(self.loaders);
		}
	},

	graph(id) {
		let self = AsesoresController;

		let labels = self.labels;

		let data = [
			self.consejeros.total.totalAtraidos,
			self.consejeros.total.totalAtraidos - self.consejeros.total.totalRegistrados,
			self.consejeros.total.totalRegistrados,
			self.consejeros.total.totalPerfilados,
			self.consejeros.total.totalLicenciasAdquiridas,
			self.consejeros.total.totalLicenciasEnUso,
			self.consejeros.total.totalConsejeros,
			self.consejeros.total.totalConsejerosActivos,
			self.consejeros.total.totalStaff,
			self.consejeros.total.totalAdminPanel,
			self.consejeros.total.totalConsejerosSinClabe,
			self.consejeros.total.totalConsejeros - self.consejeros.total.totalConsejerosSinClabe
		];

		if(data[1] < 0) {
			data[1] = 0;
		}
		if(data[10] < 0) {
			data[10] = 0;
		}

		// COLORES
		let gradient = arrayColors(self.colors, 11);

		Chart.defaults.global.defaultFontSize = self.fontSize;
		Chart.defaults.global.defaultFontFamily = self.fontName;

		let titleText = pf.const.language.RSC32 + ': ' + self.consejeros.total.totalAtraidos;

		let options = {
			layout: {
				padding: {
					top: -20
				}
			},
			title: {
				display: true,
				text: titleText,
				padding: 26
			},
			scales: {
				xAxes: [{
					barPercentage: 0.5,
					ticks: {
						display: true,
						autoSkip: false
					}
				}],
				yAxes: [{
					display: false,
					ticks: {
						fontSize: 14,
						beginAtZero: true
					}
				}]
			},
			responsive: true,
			maintainAspectRatio: false,
			legend: {
				display: false,
				position: 'right',
				onClick: false
			},
			tooltips: {
				enabled: false
			},
			plugins: {
				datalabels: {
					color: 'black',
					font: {
						weight: 'bold'
					},
					anchor: 'end',
					align: 'end',
					formatter(value, context) {
						return value;
					},
					listeners: {
						click(context) {
							label = context.dataIndex // Label seleccionada
							self.labelClicked = true;
							self.loadAsesoresModal(label);
						}
					}
				}
			},
			onClick(e) {
				// getElementsAtEvent permite recoger los datos de las barras en la gráfica y de ellas se puede tomar el índice
				var activePoints = this.getElementsAtEvent(e);
				if(activePoints.length != 0) {
					var selectedIndex = activePoints[0]._index;
					label = selectedIndex // Label seleccionada
					self.labelClicked = true;
					self.loadAsesoresModal(label);
				}
			}
		}

		// Ticks X en horizontal con salto de linea
		// Ancho del contenedor de la gráfica
		let divParentWidth = $('#graphAsesores').parent().css('width');
		// Número de columnas de la gráfica
		let nColumns = 11;
		// Ancho del contenedor entre el número de columnas
		let maxwidth = Math.floor(parseInt(divParentWidth) / nColumns);
		// Ancho de la columna entre el tamaño de la fuente
		//let maxwidthFont = Math.floor(maxwidth / 18);
		let maxwidthFont = Math.ceil(maxwidth / self.fontSize) + 2;

		// Etiquetas del eje X
		let xLabels = labels;
		// Comprobación de la primera palabra de los labes para ejecutar formato horizontal o diagonal
		let controlH = true;
		let xSize = xLabels.length;
		for(let i = 0; i < xSize; i++) {
			let words = xLabels[i].toString().split(' ');
			let wSize = words.length;
			for(let j = 0; j < wSize; j++) {
				if(words[j].length > maxwidthFont) {
					controlH = false;
					break;
				}
			}
			if(!controlH) {
				break;
			}
		}

		if(controlH) {
			options.scales.xAxes[0].ticks['minRotation'] = 0;
			options.scales.xAxes[0].ticks['maxRotation'] = 0;

			options.scales.xAxes[0].ticks['callback'] = function(value, index, values) {
				let formmatedvalue = formatLabel(value, maxwidthFont);
				return formmatedvalue;
			}
		} else {
			options.scales.xAxes[0].ticks['callback'] = function(value, index, values) {
				if(value.length < 18) {
					return value;
				} else {
					return value.substr(0, 14) + '...';
				}
			};
		}

		if(self.graphFlag) {
			self.myChart.destroy();
		} else {
			self.graphFlag = true;
		}

		let ctx = $(id);
		// Radio de ángulos
		options.cornerRadius = 6;
		self.myChart = new Chart(ctx, {
			type: 'bar',
			data: {
				labels: labels,
				datasets: [{
					data: data,
					backgroundColor: gradient,
				}]
			},
			options: options
		});
	},

	loadAsesoresModal(label, countryGraph) {
		let self = this;

		// Título del modal - título que se utiliza en la creación del Excel
		let titleExcel = pf.const.language.RSC32;

		let size = self.countriesToSee.length;

		// countryGraph se utiliza en el caso de cargar los datos en las gráficas generadas por país
		// y no en la tabla principal de asesores
		let country = '';

		if(countryGraph != null) {
			country = countryGraph;
		} else {
			for(let i = 0; i < size; i++) {
				country += self.countriesToSee[i] + ',';
			}
			country = country.substring(0, country.length - 1);
		}

		switch(label) {
			case 0:
				titleExcel = pf.const.language.RSC580;
				self.getAnalyticsConsejerosInfo(country, 'desgloseAtraidos', titleExcel);
				break;
			case 1:
				titleExcel = pf.const.language.RSC581;
				self.getAnalyticsConsejerosInfo(country, 'desgloseRegistroIniciado', titleExcel);
				break;
			case 2:
				titleExcel = pf.const.language.RSC582;
				self.getAnalyticsConsejerosInfo(country, 'desgloseRegistrados', titleExcel);
				break;
			case 3:
				titleExcel = pf.const.language.RSC583;
				self.getAnalyticsConsejerosInfo(country, 'desglosePerfilados', titleExcel);
				break;
			case 4:
				// Licencias adquiridas - No hay que mostrar nada
				return;
			case 5:
				// Licencias en uso - No hay que mostrar nada
				return;
			case 6:
				titleExcel = pf.const.language.RSC32;
				self.getAnalyticsConsejerosInfo(country, 'desgloseConsejeros', titleExcel);
				break;
			case 7:
				titleExcel = pf.const.language.RSC586;
				self.getAnalyticsConsejerosInfo(country, 'desgloseConsejerosActivos', titleExcel);
				break;
			case 8:
				titleExcel = pf.const.language.RSC309;
				self.getAnalyticsConsejerosInfo(country, 'desgloseStaff', titleExcel);
				break;
			case 9:
				titleExcel = pf.const.language.RSC1829;
				self.getAnalyticsConsejerosInfo(country, 'desgloseAdminPanel', titleExcel);
				break;
			case 10:
				titleExcel = pf.const.language.RSC587 + ' CLABE';
				self.getAnalyticsConsejerosInfo(country, 'desgloseConsejerosSinClabe', titleExcel);
				break;
			case 11:
				titleExcel = pf.const.language.RSC587 + ' CLABE';
				self.getAnalyticsConsejerosInfo(country, 'desgloseConsejerosConClabe', titleExcel);
				break;
		}
	},

	loadAsesoresModalAppVersion(label, countryGraph, showButton) {
		let self = this;

		// Título del modal - título que se utiliza en la creación del Excel
		let titleExcel = pf.const.language.RSC32;

		let size = self.countriesToSee.length;

		// countryGraph se utiliza en el caso de cargar los datos en las gráficas generadas por país
		// y no en la tabla principal de asesores
		let country = '';

		if(countryGraph != null) {
			country = countryGraph;
		} else {
			for(let i = 0; i < size; i++) {
				country += self.countriesToSee[i] + ',';
			}
			country = country.substring(0, country.length - 1);
		}

		self.getAnalyticsConsejerosInfo(country, 'desgloseVersion', titleExcel, label, showButton);
	},

	createModal(filteredData, titleExcel, showButton) {
		let self = this;

		$('#asesoresBodyButtons').html(
			`<button id="exportDetail" type="button" class="btn main-button ma-le-5" title="${pf.const.language.RSC47}">
				${stcmbackend.svg.download}
				<span>${pf.const.language.RSC47}</span>
			</button>`
		);

		if(showButton == true) {
			$('#asesoresBodyButtons').prepend(`
				<button id="notifyDetail" type="button" class="btn btn-nav d-flex align-items-center secondary-button" title="${pf.const.language.RSC2011}">
					${stcmbackend.svg.bellWithoutColor}
					<span>${pf.const.language.RSC2011}</span>
				</button>
			`);

			$('#notifyDetail').off().on('click', function() {
				let emailArray = [];
				for(let i = 0; i < filteredData.length; i++) {
					let user = filteredData[i];
					emailArray.push(user);
				}
				self.sendNotifications(emailArray);
			});
		}

		let nameSurnameHead = `
			<th scope="col" title="${pf.const.language.RSC123}">${pf.const.language.RSC123}</th>
			<th scope="col" title="${pf.const.language.RSC1626}">${pf.const.language.RSC1626}</th>
			<th scope="col" title="${pf.const.language.RSC1627}">${pf.const.language.RSC1627}</th>
		`;

		let nameSurnameFilter = `
			<td>userNombre</td>
			<td>userApellidos</td>
			<td>userApellidos2</td>
		`;

		if(self.gdpr == '1') {
			nameSurnameHead = '';
			nameSurnameFilter = '';
		}

		let table = `
			<table id="tableAsesores" class="table table-hover tr-pointer tRegs">
				<thead>
					<tr>
						<th scope="col" title="${pf.const.language.RSC136}">${pf.const.language.RSC136}</th>
						${nameSurnameHead}
						<th scope="col" title="${pf.const.language.RSC550}">${pf.const.language.RSC550}</th>
					</tr>
				</thead>

				<thead class="filtersUser">
					<tr>
						<td>userEmail</td>
						${nameSurnameFilter}
						<td>pais</td>
					</tr>
				</thead>

				<tbody>
		`;

		size = filteredData.length;
		for(let i = 0; i < size; i++) {
			let nameSurnameBody = `
				<td class="text-truncate" title="${filteredData[i].userNombre}">${((filteredData[i].userNombre == '' || !filteredData[i].userNombre) ? '-' : filteredData[i].userNombre)}</td>
				<td class="text-truncate" title="${filteredData[i].userApellidos}">${((filteredData[i].userApellidos == '' || !filteredData[i].userApellidos) ? '-' : filteredData[i].userApellidos)}</td>
				<td class="text-truncate" title="${filteredData[i].userApellidos2}">${((filteredData[i].userApellidos2 == '' || !filteredData[i].userApellidos2) ? '-' : filteredData[i].userApellidos2)}</td>
			`;

			if(self.gdpr == '1') {
				nameSurnameBody = '';
			}

			table += `
				<tr id="${i}" class="user_selected edit-group" data-id="${i}">
					<td class="text-truncate" title="${filteredData[i].userEmail}">${(filteredData[i].userEmail != '' ? filteredData[i].userEmail : '-')}</td>
					${nameSurnameBody}
					<td class="text-truncate" title="${filteredData[i].country}">${((filteredData[i].country == '' || !filteredData[i].country) ? '-' : filteredData[i].country)}</td>
				</tr>
			`;
		}

		table += `
				</tbody>
			</table>
		`;

		$('#asesoresBody').html(table);

		// Setup - add a text input to each footer cell
		$('#tableAsesores .filtersUser td').each(function() {
			let title = $(this).text();
			let value = `<input type="text" class="form-control form-control-sm">`;

			if(title === 'edit') {
				value = `<input type="text" class="form-control form-control-sm" disabled>`;
			}

			$(this).html(value);
		});

		let dataTable = $('#tableAsesores').DataTable({
			retrieve: true,
			language: pf.const.language_table,
			scrollY: 300,
			scroller: false,
			paging: true,
			pageLength: 25,
			autoWidth: false,
			aaSorting: [],
			dom: 'Bfrtip',
			buttons: [{
				extend: 'excelHtml5',
				text: titleExcel,
				className: 'd-none',
				title: titleExcel,
				customize(xlsx) {
					dataTablesExcelCustomize(xlsx);
				}
			}]
		});

		setTimeout(function() {
			dataTable.columns.adjust();
		}, 200);

		// Apply the search
		applyTheSearch(dataTable, 'filtersUser');

		// Ocultar botones de tabla
		hideTableButtons('tableAsesores');

		// Exportar tabla
		$('#exportDetail').off().on('click', function() {
			$('#asesoresBody .buttons-excel').trigger('click');
		});

		$('#asesoresModal').modal('show');
	},

	graphCountry(i, id) {
		let self = AsesoresController;

		let labels = self.labels;

		let data = [
			self.consejeros[i].totalAtraidos,
			self.consejeros[i].totalAtraidos - self.consejeros[i].totalRegistrados,
			self.consejeros[i].totalRegistrados,
			self.consejeros[i].totalPerfilados,
			self.consejeros[i].totalLicenciasAdquiridas,
			self.consejeros[i].totalLicenciasEnUso,
			self.consejeros[i].totalConsejeros,
			self.consejeros[i].totalConsejerosActivos,
			self.consejeros[i].totalStaff,
			self.consejeros[i].totalAdminPanel,
			self.consejeros[i].totalConsejerosSinClabe,
			self.consejeros[i].totalConsejeros - self.consejeros[i].totalConsejerosSinClabe
		];

		// COLORES
		let gradient = arrayColors(self.colors, 11);

		Chart.defaults.global.defaultFontSize = self.fontSize;
		Chart.defaults.global.defaultFontFamily = self.fontName;

		let titleText = pf.const.language.RSC32 + ': ' + self.consejeros[i].totalAtraidos;

		let options = {
			layout: {
				padding: {
					top: -20
				}
			},
			title: {
				display: true,
				text: titleText,
				padding: 26
			},
			scales: {
				xAxes: [{
					barPercentage: 0.5,
					ticks: {
						display: true,
						autoSkip: false
					}
				}],
				yAxes: [{
					display: false,
					ticks: {
						fontSize: 14,
						beginAtZero: true
					}
				}]
			},
			responsive: true,
			maintainAspectRatio: false,
			legend: {
				display: false,
				position: 'right',
				onClick: false
			},
			tooltips: {
				enabled: false
			},
			plugins: {
				datalabels: {
					color: 'black',
					font: {
						weight: 'bold'
					},
					anchor: 'end',
					align: 'end',
					formatter(value, context) {
						return value;
					},
					listeners: {
						click(context) {
							label = context.dataIndex // Label seleccionada
							self.labelClicked = true;
							self.loadAsesoresModal(label, i);
						}
					}
				}
			},
			onClick(e) {
				// getElementsAtEvent permite recoger los datos de las barras en la gráfica y de ellas se puede tomar el índice
				var activePoints = this.getElementsAtEvent(e);
				if(activePoints.length != 0) {
					var selectedIndex = activePoints[0]._index;
					label = selectedIndex // Label seleccionada
					self.labelClicked = true;
					self.loadAsesoresModal(label, i);
				}
			}
		}

		// Ticks X en horizontal con salto de linea
		// Ancho del contenedor de la gráfica
		let divParentWidth = $(id).parent().css('width');
		// Número de columnas de la gráfica
		let nColumns = 11;
		// Ancho del contenedor entre el número de columnas
		let maxwidth = Math.floor(parseInt(divParentWidth) / nColumns);
		// Ancho de la columna entre el tamaño de la fuente
		//let maxwidthFont = Math.floor(maxwidth / 18);
		let maxwidthFont = Math.ceil(maxwidth / self.fontSize) + 2;

		// Etiquetas del eje X
		let xLabels = labels;
		// Comprobación de la primera palabra de los labes para ejecutar formato horizontal o diagonal
		let controlH = true;
		let xSize = xLabels.length;
		for(let i = 0; i < xSize; i++) {
			let words = xLabels[i].toString().split(' ');
			let wSize = words.length;
			for(let j = 0; j < wSize; j++) {
				if(words[j].length > maxwidthFont) {
					controlH = false;
					break;
				}
			}
			if(!controlH) {
				break;
			}
		}

		if(controlH) {
			options.scales.xAxes[0].ticks['minRotation'] = 0;
			options.scales.xAxes[0].ticks['maxRotation'] = 0;

			options.scales.xAxes[0].ticks['callback'] = function(value, index, values) {
				let formmatedvalue = formatLabel(value, maxwidthFont);
				return formmatedvalue;
			}
		} else {
			options.scales.xAxes[0].ticks['callback'] = function(value, index, values) {
				if(value.length < 18) {
					return value;
				} else {
					return value.substr(0, 14) + '...';
				}
			};
		}

		let ctx = $(id);
		// Radio de ángulos
		options.cornerRadius = 6;
		let myChart = new Chart(ctx, {
			type: 'bar',
			data: {
				labels: labels,
				datasets: [{
					data: data,
					backgroundColor: gradient,
				}]
			},
			options: options
		});
	},

	table() {
		let self = this;

		$('#registers').html('');
		if(self.tableFlag) {
			$('#registers').dataTable().fnDestroy();
		} else {
			self.tableFlag = true;
		}

		$('#data-table').show();

		let nameSurnameHead = `
			<th scope="col" title="${pf.const.language.RSC123}">${pf.const.language.RSC123}</th>
			<th scope="col" title="${pf.const.language.RSC1626}">${pf.const.language.RSC1626}</th>
			<th scope="col" title="${pf.const.language.RSC1627}">${pf.const.language.RSC1627}</th>
		`;
		let nameSurnameFilter = `
			<td>Nombre</td>
			<td>Apellido 1</td>
			<td>Apellido 2</td>
		`;

		// Control GDPR
		if(self.gdpr == '1') {
			nameSurnameHead = '';
			nameSurnameFilter = '';
		}

		let table = `
			<thead>
				<tr>
					<th scope="col" title="${pf.const.language.RSC136}">${pf.const.language.RSC136}</th>
					${nameSurnameHead}
					<th scope="col" title="${pf.const.language.RSC550}">${pf.const.language.RSC550}</th>
					<th scope="col" title="${pf.const.language.RSC564}">${pf.const.language.RSC564}</th>
					<th scope="col" title="${pf.const.language.RSC565}">${pf.const.language.RSC565}</th>
					<th scope="col" title="${pf.const.language.RSC151}">${pf.const.language.RSC151}</th>
					<th scope="col" title="${pf.const.language.RSC598}">${pf.const.language.RSC598}</th>
					<th scope="col" title="${pf.const.language.RSC558}">${pf.const.language.RSC558}</th>
					<th scope="col" title="${pf.const.language.RSC559}">${pf.const.language.RSC559}</th>
					<th scope="col" title="${pf.const.language.RSC560}">${pf.const.language.RSC560}</th>
					<th scope="col" title="${pf.const.language.RSC309}">${pf.const.language.RSC309}</th>
					<th scope="col" title="${pf.const.language.RSC163}">${pf.const.language.RSC163}</th>
					<th scope="col" title="Clabe">Clabe</th>
					<th scope="col" title="${pf.const.language.RSC126}">${pf.const.language.RSC126}</th>
					<th scope="col" title="${pf.const.language.RSC777}">${pf.const.language.RSC777}</th>
				</tr>
			</thead>

			<thead class="filtersResult">
				<tr>
					<td>E-mail</td>
					${nameSurnameFilter}
					<td>Pais</td>
					<td>Estado</td>
					<td>Edad</td>
					<td>Genero</td>
					<td>NSE</td>
					<td>Registro</td>
					<td>Bienvenida</td>
					<td>Asesor</td>
					<td>Staff</td>
					<td>Administrador</td>
					<td>Clabe</td>
					<td>Activo</td>
					<td>Informacion</td>
				</tr>
			</thead>

			<tbody>
		`;

		// Obtener países permitidos
		let allowedCountries = JSON.parse(atob(sessionStorage['STCMBackEnd:userCountries']));
		let size = self.data.length;

		for(let i = 0; i < size; i++) {
			// Control de países permitidos
			if(allowedCountries.indexOf(self.data[i].countryISO) == -1) {
				continue;
			}

			let infoEye = '';
			if(self.data[i].welcome == 1 && self.data[i].admin === '0') {
				infoEye = `
					<button type="button" class="btn table-button main-color-text searchInfo" data-toggle="modal" data-target="#infoModal">
						${stcmbackend.svg.bigEyeWithoutColor}
					</button>
				`;
			}

			if(self.data[i].userNombre == null) {
				self.data[i].userNombre = '';
			}
			if(self.data[i].userApellidos == null) {
				self.data[i].userApellidos = '';
			}
			if(self.data[i].userApellidos2 == null) {
				self.data[i].userApellidos2 = '';
			}

			let nameSurnameBody = `
				<td class="text-truncate" title="${self.data[i].userNombre.trim()}">${self.data[i].userNombre.trim()}</td>
				<td class="text-truncate" title="${self.data[i].userApellidos.trim()}">${self.data[i].userApellidos.trim()}</td>
				<td class="text-truncate" title="${(self.data[i].userApellidos2 == null ? '' : self.data[i].userApellidos2)}">${(self.data[i].userApellidos2 == null ? '' : self.data[i].userApellidos2)}</td>
			`;

			// Control GDPR
			if(self.gdpr == '1') {
				nameSurnameBody = '';
			}

			table += `
				<tr>
					<td class="text-truncate" title="${self.data[i].userEmail.trim()}">${self.data[i].userEmail.trim()}</td>
					${nameSurnameBody}
					<td class="text-truncate" title="${(self.data[i].country == null ? '' : self.data[i].country)}">${(self.data[i].country == null ? '' : self.data[i].country)}</td>
					<td class="text-truncate" title="${(self.data[i].region == null ? '' : self.data[i].region)}">${(self.data[i].region == null ? '' : self.data[i].region)}</td>
					<td class="text-truncate" title="${(self.data[i].edad == null ? '' : self.data[i].edad)}">${(self.data[i].edad == null ? '' : self.data[i].edad)}</td>
					<td class="text-truncate" title="${(self.data[i].genero == null ? '' : self.data[i].genero)}">${(self.data[i].genero == null ? '' : self.data[i].genero)}</td>
					<td class="text-truncate" title="${(self.data[i].NSE == null ? '' : self.data[i].NSE)}">${(self.data[i].NSE == null ? '' : self.data[i].NSE)}</td>
					<td class="text-center">
						<span class="d-none">${(self.data[i].registered == '1' ? pf.const.language.RSC120 : pf.const.language.RSC121)}</span>
						<input type="checkbox" disabled ${(self.data[i].registered == '1' ? 'checked' : '')}>
					</td>
					<td class="text-center">
						<span class="d-none">${(self.data[i].welcome == '1' ? pf.const.language.RSC120 : pf.const.language.RSC121)}</span>
						<input type="checkbox" disabled ${(self.data[i].welcome == '1' ? 'checked' : '')}>
					</td>
					<td class="text-center">
						<span class="d-none">${(self.data[i].consejero == '1' ? pf.const.language.RSC120 : pf.const.language.RSC121)}</span>
						<input type="checkbox" disabled ${(self.data[i].consejero == '1' ? 'checked' : '')}>
					</td>
					<td class="text-center">
						<span class="d-none">${(self.data[i].staff == '1' ? pf.const.language.RSC120 : pf.const.language.RSC121)}</span>
						<input type="checkbox" disabled ${(self.data[i].staff == '1' ? 'checked' : '')}>
					</td>
					<td class="text-center">
						<span class="d-none">${(self.data[i].admin == '1' ? pf.const.language.RSC120 : pf.const.language.RSC121)}</span>
						<input type="checkbox" disabled ${(self.data[i].admin == '1' ? 'checked' : '')}>
					</td>
					<td class="text-center">
						<span class="d-none">${((self.data[i].clabe == '' || self.data[i].clabe == '0') ? pf.const.language.RSC121 : pf.const.language.RSC120)}</span>
						<input type="checkbox" disabled ${((self.data[i].clabe == '' || self.data[i].clabe == '0') ? '' : 'checked')}>
					</td>
					<td class="text-center">
						<span class="d-none">${(self.data[i].enabled == '1' ? pf.const.language.RSC120 : pf.const.language.RSC121)}</span>
						<input type="checkbox" disabled ${(self.data[i].enabled == '1' ? 'checked' : '')}>
					</td>
					<td class="text-center" data-file="${self.data[i].userEmail}">
						${infoEye}
					</td>
				</tr>
			`;
		}

		table += `
			</tbody>
		`;

		$('#registers').html(table);

		// Setup - add a text input to each footer cell
		$('#registers .filtersResult td').each(function() {
			let title = $(this).text();
			let value = `<input type="text" class="form-control form-control-sm">`;

			if(title == 'Registro' || title == 'Bienvenida' || title == 'Asesor' || title == 'Staff' || title == 'Clabe' || title == 'Activo' || title == 'Administrador') {
				value = optionsSelectAllYesNo();
			}

			$(this).html(value);
		});

		let dataTable = $('#registers').DataTable({
			retrieve: true,
			language: pf.const.language_table,
			pageLength: 25,
			autoWidth: false,
			rowGroup: {
				endRender(rows, group) {
					return group + ': ' + pf.const.language.RSC146 + ' (' + rows.count() + ')';
				},
				dataSrc: 0
			},
			order: [[0, 'asc']],
			dom: 'Bfrtip',
			buttons: [{
				extend: 'excelHtml5',
				text: pf.const.language.RSC32,
				className: 'd-none',
				title: pf.const.language.RSC32,
				customize(xlsx) {
					dataTablesExcelCustomize(xlsx);
				}
			}]
		});

		// Ocultar botones de tabla
		hideTableButtons('registers');

		// Exportar tabla
		$('#export').off().on('click', function() {
			$('#data-table .buttons-excel').trigger('click');
		});

		// Apply the search
		applyTheSearch(dataTable, 'filtersResult');

		dataTable.rowGroup().disable().draw();
		$('#nestBy').hide();

		// Creación de select principal de agrupamiento
		// Arrays de datos
		let name = [];

		$.each($('#registers thead th'), function() {
			name.push($(this).text());
		});

		let options1 = `<option value="-1">${pf.const.language.RSC130}</option>`;
		for(let i = 0; i < name.length; i++) {
			options1 += `<option value="${i}">${name[i]}</option>`;
		}
		$('#groupBy').html(options1);

		// Función de agrupamiento anidado
		function nestBy() {
			$('#nestBy').html('');
			let options2 = `<option value="-1">${pf.const.language.RSC131}</option>`;
			for(let i = 0; i < name.length; i++) {
				if(i == $('#groupBy').val()) {
					continue;
				} else {
					options2 += `<option value="${i}">${name[i]}</option>`;
				}
			}
			$('#nestBy').html(options2);

			// Evento de anidado
			$('#nestBy').off().on('change', function() {
				let valueGroup = $('#groupBy').val();

				if($('#nestBy').val() === '-1') {
					dataTable.rowGroup().dataSrc(valueGroup);
					dataTable.order([[valueGroup, 'asc']]).draw();
				} else {
					let valueNest = $('#nestBy').val();
					dataTable.rowGroup().dataSrc([valueGroup, valueNest]);
					dataTable.order([[valueGroup, 'asc'], [valueNest, 'asc']]).draw();
				}
			});
		}

		// Evento de agrupamiento
		$('#groupBy').on('change', function() {
			if($('#groupBy').val() === '-1') {
				dataTable.rowGroup().disable().draw();
				$('#nestBy').hide();
			} else {
				let value = $('#groupBy').val();

				dataTable.rowGroup().enable().draw();
				$('#nestBy').show();

				dataTable.rowGroup().dataSrc(value);
				dataTable.order([[value, 'asc']]).draw();

				// Recreación de agrupamiento secundario
				nestBy();
			}
		});

		self.tableEvents();

		$('#data-table').on('draw.dt', function() {
			self.tableEvents();
		});
	},

	tableEvents() {
		let self = this;

		// Petición de información del usuario
		$('.searchInfo').off().on('click', function() {
			let email = $(this).parent().attr('data-file');
			let userInfo = '';
			let size = self.data.length;
			for(let i = 0; i < size; i++) {
				if(email == self.data[i].userEmail) {
					userInfo = self.data[i];
					break;
				}
			}
			self.renderUserInfo(userInfo);
		});
	},

	renderUserInfo(userInfo) {
		let self = this;

		let info = `
			<table id="tableUserInfo" class="table table-hover" style="margin: 0 !important;">
				<thead class="d-none">
					<tr>
						<th>nombre</th>
						<th>valor</th>
					</tr>
				</thead>

				<tbody>
					<tr>
						<td title="${pf.const.language.RSC123}"><strong>${pf.const.language.RSC123}</strong></td>
						<td title="${(userInfo.userNombre || '')}">${(userInfo.userNombre || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC780}"><strong>${pf.const.language.RSC780}</strong></td>
						<td title="${(userInfo.userApellidos || '')}">${(userInfo.userApellidos || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC781}"><strong>${pf.const.language.RSC781}</strong></td>
						<td title="${(userInfo.userApellidos2 || '')}">${(userInfo.userApellidos2 || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC550}"><strong>${pf.const.language.RSC550}</strong></td>
						<td title="${(userInfo.country || '')}">${(userInfo.country || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC550} ISO"><strong>${pf.const.language.RSC550} ISO</strong></td>
						<td title="${(userInfo.countryISO || '')}">${(userInfo.countryISO || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC597} ISO"><strong>${pf.const.language.RSC597} ISO</strong></td>
						<td title="${(userInfo.region || '')}">${(userInfo.region || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC303}"><strong>${pf.const.language.RSC303}</strong></td>
						<td title="${(userInfo.username || '')}">${(userInfo.username || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC785}"><strong>${pf.const.language.RSC785}</strong></td>
						<td title="${(userInfo.userEmail || '')}">${(userInfo.userEmail || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC565}"><strong>${pf.const.language.RSC565}</strong></td>
						<td title="${(userInfo.edad || '')}">${(userInfo.edad || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC151}"><strong>${pf.const.language.RSC151}</strong></td>
						<td title="${(userInfo.genero || '')}">${(userInfo.genero || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC308}"><strong>${pf.const.language.RSC308}</strong></td>
						<td title="${(userInfo.clabe || '')}">${(userInfo.clabe || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC1718}"><strong>${pf.const.language.RSC1718}</strong></td>
						<td title="${(userInfo.observaciones || '')}">${(userInfo.observaciones || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC113}"><strong>${pf.const.language.RSC113}</strong></td>
						<td title="${(userInfo.creationDate || '')}">${(userInfo.creationDate || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC558}"><strong>${pf.const.language.RSC558}</strong></td>
						<td title="${(userInfo.registered == 1 ? pf.const.language.RSC120 : pf.const.language.RSC121)}">${(userInfo.registered == 1 ? pf.const.language.RSC120 : pf.const.language.RSC121)}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC126}"><strong>${pf.const.language.RSC126}</strong></td>
						<td title="${(userInfo.enabled == 1 ? pf.const.language.RSC120 : pf.const.language.RSC121)}">${(userInfo.enabled == 1 ? pf.const.language.RSC120 : pf.const.language.RSC121)}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC309}"><strong>${pf.const.language.RSC309}</strong></td>
						<td title="${(userInfo.staff == 1 ? pf.const.language.RSC120 : pf.const.language.RSC121)}">${(userInfo.staff == 1 ? pf.const.language.RSC120 : pf.const.language.RSC121)}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC124}"><strong>${pf.const.language.RSC124}</strong></td>
						<td title="${(userInfo.consejero == 1 ? pf.const.language.RSC120 : pf.const.language.RSC121)}">${(userInfo.consejero == 1 ? pf.const.language.RSC120 : pf.const.language.RSC121)}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC559}"><strong>${pf.const.language.RSC559}</strong></td>
						<td title="${(userInfo.welcome == 1 ? pf.const.language.RSC120 : pf.const.language.RSC121)}">${(userInfo.welcome == 1 ? pf.const.language.RSC120 : pf.const.language.RSC121)}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC562}"><strong>${pf.const.language.RSC562}</strong></td>
						<td title="${(userInfo.lastMessage || '')}">${(userInfo.lastMessage || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC563}"><strong>${pf.const.language.RSC563}</strong></td>
						<td title="${(userInfo.lastVideoCall || '')}">${(userInfo.lastVideoCall || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC561}"><strong>${pf.const.language.RSC561}</strong></td>
						<td title="${(userInfo.modificationDate || '')}">${(userInfo.modificationDate || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC1306}"><strong>${pf.const.language.RSC1306}</strong></td>
						<td title="${(userInfo.lastAppVisualizationDate || '')}">${(userInfo.lastAppVisualizationDate || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC618}"><strong>${pf.const.language.RSC618}</strong></td>
						<td title="${(userInfo.consumo == 1 ? pf.const.language.RSC120 : pf.const.language.RSC121)}">${(userInfo.consumo == 1 ? pf.const.language.RSC120 : pf.const.language.RSC121)}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC1894}"><strong>${pf.const.language.RSC1894}</strong></td>
						<td title="${(userInfo.NSESum || '')}">${(userInfo.NSESum || '')}</td>
					</tr>
					<tr>
						<td title="${pf.const.language.RSC1716}"><strong>${pf.const.language.RSC1716}</strong></td>
						<td title="${(userInfo.cpgs || '')}">${(userInfo.cpgs || '')}</td>
					</tr>
				</tbody>
			</table>
		`;
		$('#infoBody').html(info);

		let tableUserInfo = $('#tableUserInfo').DataTable({
			retrieve: true,
			language: pf.const.language_table,
			paging: false,
			searching: false,
			ordering: false,
			autoWidth: false
		});

		$('#confirm').off().on('click', function() {
			self.profilingCheck(userInfo.userEmail);
		});
	},

	profilingCheck(email) {
		let parameters = {
			email: email
		};
		ajaxComunCallWithCallback('getIfUserPerfila', parameters, function(ajaxReturn) {
			if(ajaxReturn) {
				let messageArray = ajaxReturn.result.split('.');
				let infoTitle = pf.const.language.RSC115;
				let infoContent = messageArray[0] + '.<br>' + messageArray[1];
				let infoBtn = pf.const.language.RSC132;
				pf.utils.showInfoDialogCustomWidth(infoTitle, infoContent, infoBtn, '500px', function() {});
			}
		});
	},

	loadLanguage() {
		pf.rsc.translateByTag('text');

		// TITLES
		$('.exportTitle').attr('title', pf.const.language.RSC47);
	},

	// Gráfica a pantalla completa
	graphsEvents() {
		let self = this;

		$('#mGraphs .section-body').off().on('click', function() {
			if(self.labelClicked) {
				$('#graphicsViewer').hide();
				self.labelClicked = false;
			} else {
				$('#graphicsViewer').show();

				self.labelClicked = false;

				let labels = self.labels;

				let data = [
					self.consejeros.total.totalAtraidos,
					self.consejeros.total.totalAtraidos - self.consejeros.total.totalRegistrados,
					self.consejeros.total.totalRegistrados,
					self.consejeros.total.totalPerfilados,
					self.consejeros.total.totalLicenciasAdquiridas,
					self.consejeros.total.totalLicenciasEnUso,
					self.consejeros.total.totalConsejeros,
					self.consejeros.total.totalConsejerosActivos,
					self.consejeros.total.totalStaff,
					self.consejeros.total.totalAdminPanel,
					self.consejeros.total.totalConsejerosSinClabe,
					self.consejeros.total.totalConsejeros - self.consejeros.total.totalConsejerosSinClabe
				];

				if(data[1] < 0) {
					data[1] = 0;
				}
				if(data[10] < 0) {
					data[10] = 0;
				}

				// COLORES
				let gradient = arrayColors(self.colors, 11);

				let ctx = document.getElementById('graphViewer').getContext('2d');

				Chart.defaults.global.defaultFontSize = self.fontSize;
				Chart.defaults.global.defaultFontFamily = self.fontName;

				let titleText = pf.const.language.RSC32 + ': ' + self.consejeros.total.totalAtraidos;

				// Ya que los hover del plugin 'datalabels' y de ChartJS se superponen entre ellos,
				// hay que controlar en que momento mostrar el elemento como clickable
				let controlHover = false;

				let options = {
					layout: {
						padding: {
							top: 0
						}
					},
					responsive: true,
					maintainAspectRatio: false,
					scales: {
						xAxes: [{
							barPercentage: 0.5,
							ticks: {
								display: true,
								autoSkip: false
							}
						}],
						yAxes: [{
							display: false,
							ticks: {
								fontSize: 14,
								beginAtZero: true
							}
						}]
					},
					legend: {
						display: false
					},
					title: {
						display: true,
						text: titleText,
						fontSize: 20,
						padding: 26
					},
					tooltips: {
						enabled: false
					},
					plugins: {
						datalabels: {
							color: 'black',
							font: {
								weight: 'bold'
							},
							anchor: 'end',
							align: 'end',
							formatter(value, context) {
								return value;
							},
							listeners: {
								click(context) {
									label = context.dataIndex // Label seleccionada
									self.labelClicked = true;
									self.loadAsesoresModal(label);
								},
								enter(context) {
									label = context.dataIndex // Label seleccionada
									// Lic. Adquiridas y Lic. en Uso - No se muestran como clickables
									if(label != 4 && label != 5) {
										context.hovered = true;
										document.getElementById('graphViewer').style.cursor = 'pointer';
									}
								},
								leave(context) {
									context.hovered = false;
									document.getElementById('graphViewer').style.cursor = 'default';
								},
							}
						}
					},
					onClick(e) {
						// getElementsAtEvent permite recoger los datos de las barras en la gráfica y de ellas se puede tomer el índice
						var activePoints = this.getElementsAtEvent(e);
						if(activePoints.length != 0) {
							var selectedIndex = activePoints[0]._index;
							label = selectedIndex // Label seleccionada
							self.labelClicked = true;
							self.loadAsesoresModal(label);
						}
					},
					onHover(e) {
						var activePoints = this.getElementsAtEvent(e);
						if(activePoints.length != 0) {
							// Lic. Adquiridas y Lic. en Uso - No se muestran como clickables
							if(activePoints[0]._index != 4 && activePoints[0]._index != 5) {
								document.getElementById('graphViewer').style.cursor = 'pointer';
								controlHover = true;
							}
						} else {
							if(controlHover) {
								document.getElementById('graphViewer').style.cursor = 'default';
								controlHover = false;
							}
						}
					}
				};

				// Ancho del contenedor de la gráfica
				let divParentWidth = $('#graphViewer').parent().css('width');
				// Número de columnas de la gráfica
				let nColumns = 11;
				// Ancho del contenedor entre el número de columnas
				let maxwidth = Math.floor(parseInt(divParentWidth) / nColumns);
				// Ancho de la columna entre el tamaño de la fuente
				let maxwidthFont = Math.ceil(maxwidth / self.fontSize) + 2;

				// Etiquetas del eje X
				let xLabels = labels;
				// Comprobación de la primera palabra de los labes para ejecutar formato horizontal o diagonal
				let controlH = true;
				let xSize = xLabels.length;
				for(let i = 0; i < xSize; i++) {
					let words = xLabels[i].toString().split(' ');
					let wSize = words.length;
					for(let j = 0; j < wSize; j++) {
						if(words[j].length > maxwidthFont) {
							controlH = false;
							break;
						}
					}
					if(!controlH) {
						break;
					}
				}

				if(controlH) {
					options.scales.xAxes[0].ticks['minRotation'] = 0;
					options.scales.xAxes[0].ticks['maxRotation'] = 0;

					options.scales.xAxes[0].ticks['callback'] = function(value, index, values) {
						let formmatedvalue = formatLabel(value, maxwidthFont);
						return formmatedvalue;
					}
				}

				// Radio de ángulos
				options.cornerRadius = 6;
				let dataChart = {
					type: 'bar',
					data: {
						labels: labels,
						datasets: [{
							data: data,
							backgroundColor: gradient,
						}]
					},
					options: options
				};

				let chart = new Chart(ctx, dataChart);
				self.graphAsesores = chart
			}
		});

		$('#downloadGraph').off().on('click', function() {
			/*Get image of canvas element*/
			let url_base64jp = document.getElementById('graphViewer').toDataURL('image/jpg');
			/*get download button (tag: <a></a>) */
			let a = document.getElementById('downloadGraph');
			/*insert chart image url to download button (tag: <a></a>) */
			a.href = url_base64jp;
		});

		$('#closeGraphic').off().on('click', function() {
			self.labelClicked = false;
			self.graphAsesores.destroy();
			$('#graphicsViewer').hide();
		});
	},

	graphsEventsCountry(iso, index) {
		let self = this;

		$('#mGraphs' + index + ' .section-body').off().on('click', function() {
			if(self.labelClicked) {
				$('#graphicsViewer').hide();
				self.labelClicked = false;
			} else {
				$('#graphicsViewer').show();
				self.labelClicked = false;

				let labels = self.labels;

				let data = [
					self.consejeros[iso].totalAtraidos,
					self.consejeros[iso].totalAtraidos - self.consejeros[iso].totalRegistrados,
					self.consejeros[iso].totalRegistrados,
					self.consejeros[iso].totalPerfilados,
					self.consejeros[iso].totalLicenciasAdquiridas,
					self.consejeros[iso].totalLicenciasEnUso,
					self.consejeros[iso].totalConsejeros,
					self.consejeros[iso].totalConsejerosActivos,
					self.consejeros[iso].totalStaff,
					self.consejeros[iso].totalAdminPanel,
					self.consejeros[iso].totalConsejerosSinClabe,
					self.consejeros[iso].totalConsejeros - self.consejeros[iso].totalConsejerosSinClabe
				];

				// COLORES
				let gradient = arrayColors(self.colors, 11);

				let ctx = document.getElementById('graphViewer').getContext('2d');

				Chart.defaults.global.defaultFontSize = self.fontSize;
				Chart.defaults.global.defaultFontFamily = self.fontName;

				let titleText = pf.const.language.RSC32 + ': ' + self.consejeros[iso].totalAtraidos;

				// Ya que los hover del plugin 'datalabels' y de ChartJS se superponen entre ellos,
				// hay que controlar en que momento mostrar el elemento como clickable
				let controlHover = false;

				let options = {
					layout: {
						padding: {
							top: 0
						}
					},
					responsive: true,
					maintainAspectRatio: false,
					scales: {
						xAxes: [{
							barPercentage: 0.5,
							ticks: {
								display: true,
								autoSkip: false
							}
						}],
						yAxes: [{
							display: false,
							ticks: {
								fontSize: 14,
								beginAtZero: true
							}
						}]
					},
					legend: {
						display: false
					},
					title: {
						display: true,
						text: titleText,
						fontSize: 20,
						padding: 26
					},
					tooltips: {
						enabled: false
					},
					plugins: {
						datalabels: {
							color: 'black',
							font: {
								weight: 'bold'
							},
							anchor: 'end',
							align: 'end',
							formatter(value, context) {
								return value;
							},
							listeners: {
								click(context) {
									label = context.dataIndex // Label seleccionada
									self.labelClicked = true;
									self.loadAsesoresModal(label, iso);
								},
								enter(context) {
									label = context.dataIndex // Label seleccionada
									// Lic. Adquiridas y Lic. en Uso - No se muestran como clickables
									if(label != 4 && label != 5) {
										context.hovered = true;
										document.getElementById('graphViewer').style.cursor = 'pointer';
									}
								},
								leave(context) {
									context.hovered = false;
									document.getElementById('graphViewer').style.cursor = 'default';
								}
							}
						}
					},
					onClick(e) {
						// getElementsAtEvent permite recoger los datos de las barras en la gráfica y de ellas se puede tomer el índice
						var activePoints = this.getElementsAtEvent(e);
						if(activePoints.length != 0) {
							var selectedIndex = activePoints[0]._index;
							label = selectedIndex // Label seleccionada
							self.labelClicked = true;
							self.loadAsesoresModal(label, iso);
						}
					},
					onHover(e) {
						var activePoints = this.getElementsAtEvent(e);
						if(activePoints.length != 0) {
							// Lic. Adquiridas y Lic. en Uso - No se muestran como clickables
							if(activePoints[0]._index != 4 && activePoints[0]._index != 5) {
								document.getElementById('graphViewer').style.cursor = 'pointer';
								controlHover = true;
							}
						} else {
							if(controlHover) {
								document.getElementById('graphViewer').style.cursor = 'default';
								controlHover = false;
							}
						}
					}
				};

				// Ancho del contenedor de la gráfica
				let divParentWidth = $('#graphViewer').parent().css('width');
				// Número de columnas de la gráfica
				let nColumns = 11;
				// Ancho del contenedor entre el número de columnas
				let maxwidth = Math.floor(parseInt(divParentWidth) / nColumns);
				// Ancho de la columna entre el tamaño de la fuente
				let maxwidthFont = Math.ceil(maxwidth / self.fontSize) + 2;

				// Etiquetas del eje X
				let xLabels = labels;
				// Comprobación de la primera palabra de los labes para ejecutar formato horizontal o diagonal
				let controlH = true;
				let xSize = xLabels.length;
				for(let i = 0; i < xSize; i++) {
					let words = xLabels[i].toString().split(' ');
					let wSize = words.length;
					for(let j = 0; j < wSize; j++) {
						if(words[j].length > maxwidthFont) {
							controlH = false;
							break;
						}
					}
					if(!controlH) {
						break;
					}
				}

				if(controlH) {
					options.scales.xAxes[0].ticks['minRotation'] = 0;
					options.scales.xAxes[0].ticks['maxRotation'] = 0;

					options.scales.xAxes[0].ticks['callback'] = function(value, index, values) {
						let formmatedvalue = formatLabel(value, maxwidthFont);
						return formmatedvalue;
					}
				}

				// Radio de ángulos
				options.cornerRadius = 6;
				let dataChart = {
					type: 'bar',
					data: {
						labels: labels,
						datasets: [{
							data: data,
							backgroundColor: gradient,
						}]
					},
					options: options
				};

				let chart = new Chart(ctx, dataChart);
				self.graphAsesores = chart
			}
		});

		$('#downloadGraph').off().on('click', function() {
			/*Get image of canvas element*/
			let url_base64jp = document.getElementById('graphViewer').toDataURL('image/jpg');
			/*get download button (tag: <a></a>) */
			let a = document.getElementById('downloadGraph');
			/*insert chart image url to download button (tag: <a></a>) */
			a.href = url_base64jp;
		});

		$('#closeGraphic').off().on('click', function() {
			self.labelClicked = false;
			self.graphAsesores.destroy();
			$('#graphicsViewer').hide();
		});
	},

	sendEmailLicences(numLicenses) {
		let user = JSON.parse(JSONuser);
		let userMail = user.email;

		let parameters = {
			email: userMail,
			numlicencias: numLicenses
		};
		ajaxComunCallWithCallback('sendEmailLicences', parameters, function(ajaxReturn) {
			if(ajaxReturn) {
				let successTitle = pf.const.language.RSC32;
				let successContent = pf.const.language.RSC1021;
				pf.utils.showInfoDialog(successTitle, successContent);
			}
		});
	},

	clickEvents(data) {
		let self = this;

		self.countriesToSee = [];
		self.countriesToSeeDesc = '';

		let size = data.length;
		for(let i = 0; i < size; i++) {
			self.countriesToSee.push(data[i].isocode);
			self.countriesToSeeDesc += data[i].descripcion + ',';
		}
		self.countriesToSeeDesc = self.countriesToSeeDesc.substring(0, self.countriesToSeeDesc.length - 1);

		$('#country').val(self.countriesToSeeDesc);
		$('#country').attr('title', self.countriesToSeeDesc);

		// Cargar tabla
		if(self.seeGraphs) {
			$('#mGraphs').show();
			$('.divGraph').show();
			$('#mGraphsAppVersion').show();
		} else {
			$('#mGraphs').hide();
			$('.divGraph').hide();
			$('#mGraphsAppVersion').hide();
		}

		$('#data-table').show();

		// Iniciar spinner
		addLoader();
		self.getConsejeros();
		self.getConsejerosAppVersion();
	},

	getAnalyticsConsejerosInfo(country, type, title, version, showButton) {
		let self = this;

		// Control usuarios sin versión de aplicación 
		// REVISAR FUNCIONAMIENTO: Control adicional label on click. Ya que la versión viene dada por el evento onClick de la gráfica
		// se tiene que controlar que cuando sea 'Sin Versión / No Versión', envíe el valor de '-' nuevamente.
		if(version == '' ||version == 'Sin Versión' ||version == 'No Version') {
			version = '-';
		}

		let parameters = {
			country: country,
			type: type,
			version: version
		};
		ajaxComunCallWithCallback('getAnalyticsConsejerosInfo', parameters, function(ajaxReturn) {
			if(ajaxReturn) {
				self.createModal(ajaxReturn.result, title, showButton);
			}
		});
	},

	graphAppVersion(id) {
		let self = this;

		let data = self.appVersionData.appVersionGeneral.data;
		let labels = self.appVersionData.appVersionGeneral.labels;

		// En caso de que haya algún label vacía (''), se cambia por 'Sin Versión'
		for(let index = 0; index < labels.length; index++) {
			if(labels[index] == '' || labels[index] == ' ') {
				labels[index] = pf.const.language.RSC2017;
			}
		}

		if(data[1] < 0) {
			data[1] = 0;
		}
		if(data[10] < 0) {
			data[10] = 0;
		}

		// COLORES
		let gradient = arrayColors(self.colors, 11);

		Chart.defaults.global.defaultFontSize = self.fontSize;
		Chart.defaults.global.defaultFontFamily = self.fontName;

		let titleText = pf.const.language.RSC32 + ': ' + self.appVersionData.appVersionGeneral.total;

		let options = {
			layout: {
				padding: {
					top: -20
				}
			},
			title: {
				display: true,
				text: titleText,
				padding: 26
			},
			scales: {
				xAxes: [{
					barPercentage: 0.5,
					ticks: {
						display: true,
						autoSkip: false
					}
				}],
				yAxes: [{
					display: false,
					ticks: {
						fontSize: 14,
						beginAtZero: true
					}
				}]
			},
			responsive: true,
			maintainAspectRatio: false,
			legend: {
				display: false,
				position: 'right',
				onClick: false
			},
			tooltips: {
				enabled: false
			},
			plugins: {
				datalabels: {
					color: 'black',
					font: {
						weight: 'bold'
					},
					anchor: 'end',
					align: 'end',
					formatter(value, context) {
						return value;
					},
					listeners: {
						click(context) {
							//
						}
					}
				}
			},
			onClick(e) {
				// getElementsAtEvent permite recoger los datos de las barras en la gráfica y de ellas se puede tomer el índice
				var activePoints = this.getElementsAtEvent(e);
				if(activePoints.length != 0) {
					var selectedIndex = activePoints[0]._model.label;
					label = selectedIndex // Label seleccionada
					self.labelClicked = true;
					self.loadAsesoresModalAppVersion(label, null, true);
				}
			}
		}

		// Ticks X en horizontal con salto de linea
		// Ancho del contenedor de la gráfica
		let divParentWidth = $('#graphAsesoresAppVersion').parent().css('width');
		// Número de columnas de la gráfica
		let nColumns = 11;
		// Ancho del contenedor entre el número de columnas
		let maxwidth = Math.floor(parseInt(divParentWidth) / nColumns);
		// Ancho de la columna entre el tamaño de la fuente
		//let maxwidthFont = Math.floor(maxwidth / 18);
		let maxwidthFont = Math.ceil(maxwidth / self.fontSize) + 2;

		// Etiquetas del eje X
		let xLabels = labels;
		// Comprobación de la primera palabra de los labes para ejecutar formato horizontal o diagonal
		let controlH = true;
		let xSize = xLabels.length;
		for(let i = 0; i < xSize; i++) {
			let words = xLabels[i].toString().split(' ');
			let wSize = words.length;
			for(let j = 0; j < wSize; j++) {
				if(words[j].length > maxwidthFont) {
					controlH = false;
					break;
				}
			}
			if(!controlH) {
				break;
			}
		}

		if(controlH) {
			options.scales.xAxes[0].ticks['minRotation'] = 0;
			options.scales.xAxes[0].ticks['maxRotation'] = 0;

			options.scales.xAxes[0].ticks['callback'] = function(value, index, values) {
				let formmatedvalue = formatLabel(value, maxwidthFont);
				return formmatedvalue;
			}
		} else {
			options.scales.xAxes[0].ticks['callback'] = function(value, index, values) {
				if(value.length < 18) {
					return value;
				} else {
					return value.substr(0, 14) + '...';
				}
			};
		}

		if(self.graphFlagAppVersion) {
			self.appVersionChart.destroy();
		} else {
			self.graphFlagAppVersion = true;
		}

		let ctx = $(id);
		// Radio de ángulos
		options.cornerRadius = 6;
		self.appVersionChart = new Chart(ctx, {
			type: 'bar',
			data: {
				labels: labels,
				datasets: [{
					data: data,
					backgroundColor: gradient,
				}]
			},
			options: options
		});
	},

	graphsEventsAppVersion() {
		let self = this;

		$('#mGraphsAppVersion .section-body').off().on('click', function() {
			if(self.labelClicked) {
				$('#graphicsViewer').hide();
				self.labelClicked = false;
			} else {
				$('#graphicsViewer').show();

				self.labelClicked = false;

				let data = self.appVersionData.appVersionGeneral.data;
				let labels = self.appVersionData.appVersionGeneral.labels;

				// En caso de que haya algún label vacía (''), se cambia por 'Sin Versión'
				for(let index = 0; index < labels.length; index++) {
					if(labels[index] == '' || labels[index] == ' ') {
						labels[index] = pf.const.language.RSC2017;
					}
				}

				if(data[1] < 0) {
					data[1] = 0;
				}
				if(data[10] < 0) {
					data[10] = 0;
				}

				// COLORES
				let gradient = arrayColors(self.colors, 11);

				let ctx = document.getElementById('graphViewer').getContext('2d');

				Chart.defaults.global.defaultFontSize = self.fontSize;
				Chart.defaults.global.defaultFontFamily = self.fontName;

				let titleText = pf.const.language.RSC32 + ': ' + self.consejeros.total.totalAtraidos;

				// Ya que los hover del plugin 'datalabels' y de ChartJS se superponen entre ellos,
				// hay que controlar en que momento mostrar el elemento como clickable
				let controlHover = false;

				let options = {
					layout: {
						padding: {
							top: 0
						}
					},
					responsive: true,
					maintainAspectRatio: false,
					scales: {
						xAxes: [{
							barPercentage: 0.5,
							ticks: {
								display: true,
								autoSkip: false
							}
						}],
						yAxes: [{
							display: false,
							ticks: {
								fontSize: 14,
								beginAtZero: true
							}
						}]
					},
					legend: {
						display: false
					},
					title: {
						display: true,
						text: titleText,
						fontSize: 20,
						padding: 26
					},
					tooltips: {
						enabled: false
					},
					plugins: {
						datalabels: {
							color: 'black',
							font: {
								weight: 'bold'
							},
							anchor: 'end',
							align: 'end',
							formatter(value, context) {
								return value;
							},
							listeners: {
								click(context) {
									//
								},
								enter(context) {
									label = context.dataIndex // Label seleccionada
									// Lic. Adquiridas y Lic. en Uso - No se muestran como clickables
									if(label != 4 && label != 5) {
										context.hovered = true;
										document.getElementById('graphViewer').style.cursor = 'pointer';
									}
								},
								leave(context) {
									context.hovered = false;
									document.getElementById('graphViewer').style.cursor = 'default';
								}
							}
						}
					},
					onClick(e) {
						// getElementsAtEvent permite recoger los datos de las barras en la gráfica y de ellas se puede tomer el índice
						var activePoints = this.getElementsAtEvent(e);
						if(activePoints.length != 0) {
							var selectedIndex = activePoints[0]._model.label;
							label = selectedIndex // Label seleccionada
							self.labelClicked = true;
							self.loadAsesoresModalAppVersion(label, null, true);
						}
					},
					onHover(e) {
						var activePoints = this.getElementsAtEvent(e);
						if(activePoints.length != 0) {
							// Lic. Adquiridas y Lic. en Uso - No se muestran como clickables
							if(activePoints[0]._index != 4 && activePoints[0]._index != 5) {
								document.getElementById('graphViewer').style.cursor = 'pointer';
								controlHover = true;
							}
						} else {
							if(controlHover) {
								document.getElementById('graphViewer').style.cursor = 'default';
								controlHover = false;
							}
						}
					}
				};

				// Ancho del contenedor de la gráfica
				let divParentWidth = $('#graphViewer').parent().css('width');
				// Número de columnas de la gráfica
				let nColumns = 11;
				// Ancho del contenedor entre el número de columnas
				let maxwidth = Math.floor(parseInt(divParentWidth) / nColumns);
				// Ancho de la columna entre el tamaño de la fuente
				let maxwidthFont = Math.ceil(maxwidth / self.fontSize) + 2;

				// Etiquetas del eje X
				let xLabels = labels;
				// Comprobación de la primera palabra de los labes para ejecutar formato horizontal o diagonal
				let controlH = true;
				let xSize = xLabels.length;
				for(let i = 0; i < xSize; i++) {
					let words = xLabels[i].toString().split(' ');
					let wSize = words.length;
					for(let j = 0; j < wSize; j++) {
						if(words[j].length > maxwidthFont) {
							controlH = false;
							break;
						}
					}
					if(!controlH) {
						break;
					}
				}

				if(controlH) {
					options.scales.xAxes[0].ticks['minRotation'] = 0;
					options.scales.xAxes[0].ticks['maxRotation'] = 0;

					options.scales.xAxes[0].ticks['callback'] = function(value, index, values) {
						let formmatedvalue = formatLabel(value, maxwidthFont);
						return formmatedvalue;
					}
				}

				// Radio de ángulos
				options.cornerRadius = 6;
				let dataChart = {
					type: 'bar',
					data: {
						labels: labels,
						datasets: [{
							data: data,
							backgroundColor: gradient,
						}]
					},
					options: options
				};

				let chart = new Chart(ctx, dataChart);
				self.graphAsesores = chart
			}
		});
	},

	graphCountryAppVersion(i, id) {
		let self = this;

		let data = self.appVersionData[i].data;
		let labels = self.appVersionData[i].labels;

		// En caso de que haya algún label vacía (''), se cambia por 'Sin Versión'
		for(let index = 0; index < labels.length; index++) {
			if(labels[index] == '' || labels[index] == ' ') {
				labels[index] = pf.const.language.RSC2017;
			}
		}

		// COLORES
		let gradient = arrayColors(self.colors, 11);

		Chart.defaults.global.defaultFontSize = self.fontSize;
		Chart.defaults.global.defaultFontFamily = self.fontName;

		let titleText = pf.const.language.RSC32 + ': ' + self.appVersionData[i].total;

		let options = {
			layout: {
				padding: {
					top: -20
				}
			},
			title: {
				display: true,
				text: titleText,
				padding: 26
			},
			scales: {
				xAxes: [{
					barPercentage: 0.5,
					ticks: {
						display: true,
						autoSkip: false
					}
				}],
				yAxes: [{
					display: false,
					ticks: {
						fontSize: 14,
						beginAtZero: true
					}
				}]
			},
			responsive: true,
			maintainAspectRatio: false,
			legend: {
				display: false,
				position: 'right',
				onClick: false
			},
			tooltips: {
				enabled: false
			},
			plugins: {
				datalabels: {
					color: 'black',
					font: {
						weight: 'bold'
					},
					anchor: 'end',
					align: 'end',
					formatter(value, context) {
						return value;
					},
					listeners: {
						click(context) {
							//
						}
					}
				}
			},
			onClick(e) {
				// getElementsAtEvent permite recoger los datos de las barras en la gráfica y de ellas se puede tomer el índice
				var activePoints = this.getElementsAtEvent(e);
				if(activePoints.length != 0) {
					var selectedIndex = activePoints[0]._model.label;
					label = selectedIndex // Label seleccionada
					self.labelClicked = true;
					self.loadAsesoresModalAppVersion(label, i, true);
				}
			}
		}

		// Ticks X en horizontal con salto de linea
		// Ancho del contenedor de la gráfica
		let divParentWidth = $(id).parent().css('width');
		// Número de columnas de la gráfica
		let nColumns = 11;
		// Ancho del contenedor entre el número de columnas
		let maxwidth = Math.floor(parseInt(divParentWidth) / nColumns);
		// Ancho de la columna entre el tamaño de la fuente
		//let maxwidthFont = Math.floor(maxwidth / 18);
		let maxwidthFont = Math.ceil(maxwidth / self.fontSize) + 2;

		// Etiquetas del eje X
		let xLabels = labels;
		// Comprobación de la primera palabra de los labes para ejecutar formato horizontal o diagonal
		let controlH = true;
		let xSize = xLabels.length;
		for(let i = 0; i < xSize; i++) {
			let words = xLabels[i].toString().split(' ');
			let wSize = words.length;
			for(let j = 0; j < wSize; j++) {
				if(words[j].length > maxwidthFont) {
					controlH = false;
					break;
				}
			}
			if(!controlH) {
				break;
			}
		}

		if(controlH) {
			options.scales.xAxes[0].ticks['minRotation'] = 0;
			options.scales.xAxes[0].ticks['maxRotation'] = 0;

			options.scales.xAxes[0].ticks['callback'] = function(value, index, values) {
				let formmatedvalue = formatLabel(value, maxwidthFont);
				return formmatedvalue;
			}
		} else {
			options.scales.xAxes[0].ticks['callback'] = function(value, index, values) {
				if(value.length < 18) {
					return value;
				} else {
					return value.substr(0, 14) + '...';
				}
			};
		}

		let ctx = $(id);
		// Radio de ángulos
		options.cornerRadius = 6;
		let myChart = new Chart(ctx, {
			type: 'bar',
			data: {
				labels: labels,
				datasets: [{
					data: data,
					backgroundColor: gradient,
				}]
			},
			options: options
		});
	},

	graphsEventsCountryAppVersion(iso, index) {
		let self = this;

		$('#mGraphsAppVersion' + index + ' .section-body').off().on('click', function() {
			if(self.labelClicked) {
				$('#graphicsViewer').hide();
				self.labelClicked = false;
			} else {
				$('#graphicsViewer').show();
				self.labelClicked = false;

				let data = self.appVersionData[iso].data;
				let labels = self.appVersionData[iso].labels;

				// En caso de que haya algún label vacía (''), se cambia por 'Sin Versión'
				for(let i = 0; i < labels.length; i++) {
					if(labels[i] == '' || labels[i] == ' ') {
						labels[i] = pf.const.language.RSC2017;
					}
				}

				// COLORES
				let gradient = arrayColors(self.colors, 11);

				let ctx = document.getElementById('graphViewer').getContext('2d');

				Chart.defaults.global.defaultFontSize = self.fontSize;
				Chart.defaults.global.defaultFontFamily = self.fontName;

				let titleText = pf.const.language.RSC32 + ': ' + self.appVersionData[iso].total;

				// Ya que los hover del plugin 'datalabels' y de ChartJS se superponen entre ellos,
				// hay que controlar en que momento mostrar el elemento como clickable
				let controlHover = false;

				let options = {
					layout: {
						padding: {
							top: 0
						}
					},
					responsive: true,
					maintainAspectRatio: false,
					scales: {
						xAxes: [{
							barPercentage: 0.5,
							ticks: {
								display: true,
								autoSkip: false
							}
						}],
						yAxes: [{
							display: false,
							ticks: {
								fontSize: 14,
								beginAtZero: true
							}
						}]
					},
					legend: {
						display: false
					},
					title: {
						display: true,
						text: titleText,
						fontSize: 20,
						padding: 26
					},
					tooltips: {
						enabled: false
					},
					plugins: {
						datalabels: {
							color: 'black',
							font: {
								weight: 'bold'
							},
							anchor: 'end',
							align: 'end',
							formatter(value, context) {
								return value;
							},
							listeners: {
								click(context) {
									//
								},
								enter(context) {
									//
									},
								leave(context) {
									//
								}
							}
						}
					},
					onClick(e) {
						// getElementsAtEvent permite recoger los datos de las barras en la gráfica y de ellas se puede tomer el índice
						var activePoints = this.getElementsAtEvent(e);
						if(activePoints.length != 0) {
							var selectedIndex = activePoints[0]._model.label;
							label = selectedIndex // Label seleccionada
							self.labelClicked = true;
							self.loadAsesoresModalAppVersion(label, iso, true);
						}
					},
					onHover(e) {
						var activePoints = this.getElementsAtEvent(e);
						if(activePoints.length != 0) {
							// Lic. Adquiridas y Lic. en Uso - No se muestran como clickables
							if(activePoints[0]._index != 4 && activePoints[0]._index != 5) {
								document.getElementById('graphViewer').style.cursor = 'pointer';
								controlHover = true;
							}
						} else {
							if(controlHover) {
								document.getElementById('graphViewer').style.cursor = 'default';
								controlHover = false;
							}
						}
					}
				};

				// Ancho del contenedor de la gráfica
				let divParentWidth = $('#graphViewer').parent().css('width');
				// Número de columnas de la gráfica
				let nColumns = 11;
				// Ancho del contenedor entre el número de columnas
				let maxwidth = Math.floor(parseInt(divParentWidth) / nColumns);
				// Ancho de la columna entre el tamaño de la fuente
				let maxwidthFont = Math.ceil(maxwidth / self.fontSize) + 2;

				// Etiquetas del eje X
				let xLabels = labels;
				// Comprobación de la primera palabra de los labes para ejecutar formato horizontal o diagonal
				let controlH = true;
				let xSize = xLabels.length;
				for(let i = 0; i < xSize; i++) {
					let words = xLabels[i].toString().split(' ');
					let wSize = words.length;
					for(let j = 0; j < wSize; j++) {
						if(words[j].length > maxwidthFont) {
							controlH = false;
							break;
						}
					}
					if(!controlH) {
						break;
					}
				}

				if(controlH) {
					options.scales.xAxes[0].ticks['minRotation'] = 0;
					options.scales.xAxes[0].ticks['maxRotation'] = 0;

					options.scales.xAxes[0].ticks['callback'] = function(value, index, values) {
						let formmatedvalue = formatLabel(value, maxwidthFont);
						return formmatedvalue;
					}
				}

				// Radio de ángulos
				options.cornerRadius = 6;
				let dataChart = {
					type: 'bar',
					data: {
						labels: labels,
						datasets: [{
							data: data,
							backgroundColor: gradient,
						}]
					},
					options: options
				};

				let chart = new Chart(ctx, dataChart);
				self.graphAsesores = chart
			}
		});

		$('#downloadGraph').off().on('click', function() {
			/*Get image of canvas element*/
			let url_base64jp = document.getElementById('graphViewer').toDataURL('image/jpg');
			/*get download button (tag: <a></a>) */
			let a = document.getElementById('downloadGraph');
			/*insert chart image url to download button (tag: <a></a>) */
			a.href = url_base64jp;
		});

		$('#closeGraphic').off().on('click', function() {
			self.labelClicked = false;
			self.graphAsesores.destroy();
			$('#graphicsViewer').hide();
		});
	},

	sendNotifications(emailArray) {
		let self = this;

		let content = `
			<p>${pf.const.language.RSC2012}</p>

			<textarea id="sendNotifications" class="w-100" name="sendNotifications" rows="4" cols="50"></textarea>

			<div class="form-inline">
				<input id="linkStores" type="checkbox" value="">
				<label class="pl-1" for="linkStores">${pf.const.language.RSC2013}</label>
			</div>
		`;

		let objInfo = {
			accept: {
				text: pf.const.language.RSC377
			},
			cancel: {
				text: pf.const.language.RSC57
			}
		};

		let alertTitle = pf.const.language.RSC2011;
		pf.utils.showInfoDialogCustomWidthAcceptCancelNewStyle(alertTitle, content, objInfo, '500px', function() {
			let config = JSON.parse(atob(sessionStorage.getItem('STCMBackEnd:config')));
			let notifyUser = config.SYSNotifUser;
			let mensaje = $('#sendNotifications').val()

			if($('#linkStores').is(':checked')) {
				if(config.URLAndroid != '') {
					mensaje += ' App Android: ' + config.URLAndroid;
				}
				if(config.URLiOS != '') {
					mensaje += ' App iOS: ' + config.URLiOS;
				}
			}

			self.sendNotificationMessage(notifyUser, emailArray, mensaje);
		}, function() {});
	},

	sendNotificationMessage(notifyUser, emailArray, mensaje) {
		let parameters = {
			from: notifyUser,
			emailsToSend: JSON.stringify(emailArray),
			message: mensaje,
			idlist: ''
		};
		ajaxComunCallWithCallback('postMessageMultiple', parameters, function(ajaxReturn) {
			if(ajaxReturn) {
				let alertTitle = pf.const.language.RSC2011;
				let alertText = pf.const.language.RSC401;
				pf.utils.showInfoDialog(alertTitle, alertText);
			}
		});
	}
};