let ResponseTimeController = {
	user: '',
	idCliente: '',
	dateFormat: '',
	numPregPerf: '',
	splitCharacter: '',
	typeColors: null,
	colorsHex: [],
	poll: '',
	idPoll: '',
	isPerf: null,
	idMission: '',
	stampMision: '',
	project: '',
	questionsFlag: false,
	questions: [],
	results: [],
	data: [],
	targetsSurvey: [],
	targetsSurveyArray: [],
	surveyValues: null,
	columnName: null,
	columnNameK: null,
	defaultTemplate: null,
	isContinuing: '0',
	startDate: '',
	endDate: '',
	suffix: '',
	participants: [],
	selectedParticipants: [],
	questionTimings: {},
	userTimings: {},

	reset() {
		let self = this;
		self.user = '';
		self.idCliente = '';
		self.dateFormat = '';
		self.numPregPerf = '';
		self.splitCharacter = '';
		self.typeColors = null;
		self.colorsHex = [];
		self.poll = '';
		self.idPoll = '';
		self.isPerf = null;
		self.idMission = '';
		self.stampMision = '';
		self.project = '';
		self.questionsFlag = false;
		self.questions = [];
		self.results = [];
		self.data = [];
		self.targetsSurvey = [];
		self.targetsSurveyArray = [];
		self.surveyValues = null;
		self.columnName = null;
		self.columnNameK = null;
		self.defaultTemplate = null;
		self.isContinuing = '0';
		self.startDate = '';
		self.endDate = '';
		self.suffix = '';
		participants = '';
		selectedParticipants = [];
		questionTimings = {};
		userTimings = {};
	},

	setEvents(suffix = '') {

		let self = this;
		self.reset();
		self.suffix = suffix;

		// Información de administrador
		let userAdmin = JSON.parse(sessionStorage['STCMBackEnd:user']);
		let email = userAdmin.email;
		let email_split = email.split('@');
		self.user = email_split[0].replace('.', '_');
		self.idCliente = userAdmin.idCliente;
		self.dateFormat = userAdmin.formatoFecha;

		// Valores de configuración
		let config = JSON.parse(atob(sessionStorage.getItem('STCMBackEnd:config')));
		self.numPregPerf = config.numPregPerfEnMostreo;
		self.splitCharacter = config.splitCharacter;

		// Plantilla por defecto
		if (self.suffix === '') {
			self.getPlantillaReportesByDefault();
		}

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

		let jsonsubopt = {};
		let nav = '';
		if (self.suffix === '') {
			// Añadir titulo
			$('#page-title').text(pf.const.language.RSC2753);

			// Opciones de header
			jsonsubopt = {
				survey: 'poll',
				question: 'question',
				user: 'user',
				report: 'ddreport' + self.suffix,
			};

			nav = `
				<div class="d-flex justify-content-end align-items-end row m-0">
					${createSubOptionSurvey(jsonsubopt.survey)}
					${createSubOptionQuestion(jsonsubopt.question)}
					${createSubOptionUser(jsonsubopt.user)}
					${createSubOptionGetReport(jsonsubopt.report)}
				</div>
				`;
		} else if (self.suffix === '-me-sam-dyn') {
			// Opciones de header
			jsonsubopt = {
				survey: 'poll',
				question: 'question' + self.suffix,
				user: 'user',
				report: 'ddreport' + self.suffix,
			};

			nav = `
				<div class="d-flex justify-content-end align-items-end row m-0">
					${createSubOptionQuestion(jsonsubopt.question, self.suffix)}
					${createSubOptionUser(jsonsubopt.user)}
					${createSubOptionGetReport(jsonsubopt.report)}
				</div>
				`;
		}

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

		// Botón principal
		$('#ddreport' + self.suffix).addClass('main-button');

		// Secciones ocultas al cargar
		$('#poll').parent().removeClass('col-2');
		$('#poll').parent().removeClass('col-sm-3');
		$('#question' + self.suffix).parent().removeClass('col-2');
		$('#question' + self.suffix).parent().removeClass('col-sm-3');
		$('#startDate' + self.suffix).parent().hide();
		$('#endDate' + self.suffix).parent().hide();

		// Inputs de fecha y hora
		let now = new Date();
		let nYear = now.getFullYear();
		let nMonth = now.getMonth() + 1;
		if (nMonth < 10) {
			nMonth = '0' + nMonth;
		}
		let nDay = now.getDate();
		if (nDay < 10) {
			nDay = '0' + nDay;
		}
		let today = nYear + '-' + nMonth + '-' + nDay;
		self.startDate = today;
		self.endDate = today;

		$('#startDate' + self.suffix).val(self.startDate);
		$('#endDate' + self.suffix).val(self.endDate);

		$('#poll').attr('placeholder', pf.const.language.RSC177);

		self.loadLang();
		self.applyEvents();
	},

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

		// TITLES
		$('.acceptTitle').attr('title', pf.const.language.RSC141);
	},

	applyEvents() {
		let self = this;

		// En caso de venir de edición de misiones
		if (self.suffix === '-me-sam-dyn') {
			// Desactivar el botón de carga de pregunta
			$('#loadSurvey').prop('disabled', true);
			// Desactivar botón en filtros
			$('#loadWithFilters').addClass('spanDisabled');
			// Activar el botón de modal de preguntas
			$('#searchQuestion' + self.suffix).prop('disabled', false);
		}

		// Misiones
		$('#searchPoll').on('click', function () {
			if (self.poll === '') {
				// Parámetro de cliente
				let parameters = {
					idCliente: self.idCliente
				}
				ajaxComunCallWithCallback('getAllSurveysWithMissions', parameters, function (ajaxReturn) {
					if (ajaxReturn) {
						self.poll = ajaxReturn.result;
						self.renderPoll();
					}
				});
			} else {
				$('#pollTable').modal('show', true);
			}
		});

		// Preguntas
		$('#searchQuestion' + self.suffix).on('click', function () {
			if (self.questions.length === 0) {
				let parameters = {
					survey: self.idPoll
				};
				ajaxComunCallWithCallback('getQuestionsSurvey', parameters, function (ajaxReturn) {
					if (ajaxReturn) {
						let size = ajaxReturn.result.length;
						for (let i = 0; i < size; i++) {
							let textWithTags = ajaxReturn.result[i].question;
							let textWithoutTags = textWithTags.replace(/<[^>]*>?/g, '');

							let questionsSQ = {};
							if (ajaxReturn.result[i].type == 'A' || ajaxReturn.result[i].type == 'B' || ajaxReturn.result[i].type == 'F') {
								let sizeK = ajaxReturn.result[i].valuesSQ.length;
								for (let j = 0; j < sizeK; j++) {
									let valuesSQArray = ajaxReturn.result[i].valuesSQ[j].split('|');

									questionsSQ[valuesSQArray[0]] = {
										name: valuesSQArray[1],
										data: []
									};
								}
							}

							let obj = {
								type: ajaxReturn.result[i].type,
								columnName: ajaxReturn.result[i].columnName,
								title: ajaxReturn.result[i].title,
								group_name: ajaxReturn.result[i].group_name,
								question: textWithoutTags.trim(),
								checked: true,
								questionsSQ: questionsSQ
							}
							self.questions.push(obj);
						}

						self.renderQuests();
					}
				});
			} else {
				$('#questTable' + self.suffix).modal('show', true);
			}
		});

		// Users
		$('#searchUser').off().on('click', function () {
			if (self.participants == '') {
				let parameters = {
					country: '',
					consejero: 1,
					enabled: 1,
					staff: 1
				};
				ajaxComunCallWithCallback('getAllUsers', parameters, function (ajaxReturn) {
					if (ajaxReturn) {
						self.participants = ajaxReturn.result;
						self.selectedParticipants = self.participants.map((participant) => participant.email);
						self.renderPool();
					}
				});
			} else {
				if ($.fn.DataTable.isDataTable('#tableUser')) {
					var table = $('#tableUser').DataTable();
					table.destroy();
				}
				self.renderPool();
			}
		});

		// Cargar datos de página a través de los filtros
		$('#loadWithFilters').on('click', function () {
			// En caso de que esté desactivado
			if ($('#loadWithFilters').hasClass('spanDisabled')) {
				return false;
			}

			$('#accept' + self.suffix).trigger('click');
		});

		// Gráficas
		$('#accept' + self.suffix).on('click', function () {

			let selectedQuestions = false;
			let size = self.questions.length;
			for (let i = 0; i < size; i++) {
				if (self.questions[i].checked) {
					selectedQuestions = true;
					break;
				}
			}
			$('#searchUser').prop('disabled', false);
			$('#questTable').modal('hide');
		});

		// Reporte
		$('#ddreport' + self.suffix).on('click', function () {

			let questions = self.questions.map(function name(question) {
				return question.columnName;
			});

			// Parámetros de reporte
			let parameters = {
				idSurvey: self.idPoll,
				questions: JSON.stringify(questions),
				users: JSON.stringify(self.selectedParticipants)
			}

			Promise.all([
				self.getSurveyQuestionTimings(parameters),
				self.getSurveyUserTimings(parameters)
			])
				.then(([questionTimings, userTimings]) => {
					self.questionTimings = questionTimings;
					self.userTimings = userTimings;
					self.requestGraphs();
				})
				.catch(error => {
					console.error('Error:', error.message);
				});
		});
	},

	getSurveyQuestionTimings: function (parameters) {
		return new Promise((resolve, reject) => {
			ajaxComunCallWithCallback('getSurveyQuestionTimings', parameters, function (ajaxReturn) {
				if (ajaxReturn) {
					resolve(ajaxReturn.result);
				} else {
					reject(new Error('Failed to get survey question timings'));
				}
			});
		});
	},

	getSurveyUserTimings: function (parameters) {
		return new Promise((resolve, reject) => {
			ajaxComunCallWithCallback('getSurveyUserTimings', parameters, function (ajaxReturn) {
				if (ajaxReturn) {
					resolve(ajaxReturn.result);
				} else {
					reject(new Error('Failed to get survey user timings'));
				}
			});
		});
	},

	getPlantillaReportesByDefault() {
		let self = this;

		ajaxComunCallWithCallback('getPlantillaReportesByDefault', {}, function (ajaxReturn) {
			if (ajaxReturn) {
				let values = ajaxReturn.result[0];
				self.defaultTemplate = values;

				self.typeColors = values.rangoColores;

				if (self.typeColors == '1') {
					self.colorsHex[0] = values.colorInicio;
					self.colorsHex[1] = values.colorFinal;
				} else {
					self.colorsHex = values.coloresComponenRango;
				}
			}
		});
	},

	renderPoll() {
		let self = this;

		let table = `
				<thead>
					<tr>
						<th scope="col" title="${pf.const.language.RSC177}">${pf.const.language.RSC177}</th>
						<th scope="col" title="${pf.const.language.RSC176}">${pf.const.language.RSC176}</th>
						<th scope="col" title="${pf.const.language.RSC114}">${pf.const.language.RSC114}</th>
						<th scope="col" title="${pf.const.language.RSC116}">${pf.const.language.RSC116}</th>
						<th scope="col" title="${pf.const.language.RSC117}">${pf.const.language.RSC117}</th>
						<th scope="col" title="${pf.const.language.RSC549}">${pf.const.language.RSC549}</th>
					</tr>
				</thead>
	
				<thead class="filtersPoll">
					<tr>
						<td>mision</td>
						<td>proyecto</td>
						<td>active</td>
						<td>startdate</td>
						<td>expires</td>
						<td>country</td>
					</tr>
				</thead>
	
				<tbody>
			`;

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

		let size = self.poll.length;
		for (let i = 0; i < size; i++) {
			// Control de países permitidos
			if (self.poll[i].countries != '' && allowedCountries.indexOf(self.poll[i].countries) == -1) {
				continue;
			}

			if (self.poll[i].idmision == '') {
				continue;
			}

			// Formato de fecha, el servicio devuelve AAAA-MM-DD HH:MM:SS
			let startDate = '-';
			let startDateOrder = '';
			if (self.poll[i].startdate != '') {
				// Para ordenación en columna
				startDateOrder = self.poll[i].startdate.replace(' ', '');

				let dateTimeArrayStart = self.poll[i].startdate.split(' ');
				let dateStart = dateTimeArrayStart[0].replace(/-/g, '/');
				if (self.dateFormat === 'DDMMAAAA') {
					startDate = modifyDateFormat(dateStart);
				} else {
					startDate = dateStart;
				}
			}

			let endDate = '-';
			let endDateOrder = '';
			if (self.poll[i].expires != '') {
				// Para ordenación en columna
				endDateOrder = self.poll[i].expires.replace(' ', '');

				let dateTimeArrayEnd = self.poll[i].expires.split(' ');
				let dateEnd = dateTimeArrayEnd[0].replace(/-/g, '/');
				if (self.dateFormat === 'DDMMAAAA') {
					endDate = modifyDateFormat(dateEnd);
				} else {
					endDate = dateEnd;
				}
			}

			table += `
					<tr id="sid${self.poll[i].sid}" class="c-pointer" data-perf="${self.poll[i].perfilacion}" data-mission="${self.poll[i].idmision}" data-stamp="${self.poll[i].stampMision}" data-project="${self.poll[i].idProject}" data-surveyname="${self.poll[i].surveyls_title}" data-continuing="${self.poll[i].continuingMission}">
						<td class="text-truncate" title="${self.poll[i].idmision}">${self.poll[i].idmision}</td>
						<td class="text-truncate" title="${self.poll[i].NombreProyecto}">${self.poll[i].NombreProyecto}</td>
						<td class="text-center">
							<span class="d-none">${(self.poll[i].active == '1' ? pf.const.language.RSC120 : pf.const.language.RSC121)}</span>
							<input type="checkbox" disabled ${(self.poll[i].active == '1' ? 'checked' : '')}>
						</td>
						<td class="text-truncate" title="${startDate}">
							<span class="d-none">${startDateOrder}</span>
							${startDate}
						</td>
						<td class="text-truncate" title="${endDate}">
							<span class="d-none">${endDateOrder}</span>
							${endDate}
						</td>
						<td class="country text-truncate" title="${self.poll[i].countries}">${self.poll[i].countries}</td>
					</tr>
				`;
		}

		table += `
				</tbody>
			`;

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

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

			if (title == 'active') {
				value = optionsSelectAllYesNo();
			}

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

		let tablePoll = $('#tablePoll').DataTable({
			language: pf.const.language_table,
			scrollY: 300,
			scroller: false,
			paging: true,
			pageLength: 25,
			columnDefs: [
				{ width: '60px', targets: 2 }
			],
			autoWidth: false,
			aaSorting: []
		});

		// Ajuste de columnas
		setTimeout(function () {
			tablePoll.columns.adjust();
		}, 200);

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

		// Apply the search
		applyTheSearch(tablePoll, 'filtersPoll');

		$('#tablePoll tbody').off().on('click', 'tr', function () {
			// Desactivar el botón de carga de pregunta
			$('#loadSurvey').prop('disabled', true);
			// Desactivar botón en filtros
			$('#loadWithFilters').addClass('spanDisabled');
			// Activar el botón de modal de preguntas
			$('#searchQuestion').prop('disabled', false);

			//Limpieza de preguntas
			self.questions = [];

			// Limpieza del contenedor de resultados
			$('#resultsContainer').html('');

			// Misión continua
			if ($(this).data('continuing') == '1') {
				self.isContinuing = '1';
				$('#startDate' + self.suffix).parent().show();
				$('#endDate' + self.suffix).parent().show();
			} else {
				self.isContinuing = '0';
				$('#startDate' + self.suffix).parent().hide();
				$('#endDate' + self.suffix).parent().hide();
			}

			// Datos de misión
			self.idPoll = $(this).attr('id').replace('sid', '');
			self.isPerf = $(this).data('perf');
			self.idMission = $(this).data('mission');
			self.stampMision = $(this).data('stamp');
			self.project = $(this).data('project');

			$('#poll').val(self.idMission);
			$('#poll').attr('title', self.idMission);
			$('#tablePoll tbody tr').css('outline-width', 'initial');
			$('#tablePoll tbody tr').css('outline-style', 'none');
			$('#tablePoll tbody tr').css('outline-color', '#000');
			$('#tablePoll tbody tr').css('font-weight', 'normal');
			$(this).css('outline-width', 'thin');
			$(this).css('outline-style', 'solid');
			$(this).css('outline-color', '#f00');
			$(this).css('font-weight', 'bold');
			$('#closePool').trigger('click');
		});
	},

	renderQuests() {
		let self = this;

		if (self.questionsFlag) {
			$('#tableQuest' + self.suffix).dataTable().fnDestroy();
		} else {
			self.questionsFlag = true;
		}

		let table = `
				<thead>
					<tr>
						<th scope="col" title="${pf.const.language.RSC1316}">${pf.const.language.RSC1316}</th>
						<th scope="col" title="${pf.const.language.RSC366}">${pf.const.language.RSC366}</th>
						<th scope="col" title="${pf.const.language.RSC122}">${pf.const.language.RSC122}</th>
						<th scope="col" title="${pf.const.language.RSC111}">${pf.const.language.RSC111}</th>
					</tr>
				</thead>
	
				<thead class="filtersQuest">
					<tr>
						<td>seleccion</td>
						<td>columnName</td>
						<td>section</td>
						<td>question</td>
					</tr>
				</thead>
	
				<tbody>
			`;

		let size = self.questions.length;
		for (let i = 0; i < size; i++) {
			table += `
					<tr class="c-pointer" data-index="${i}">
						<td class="text-center">
							<input type="checkbox" class="selection" data-index="${i}" ${(self.questions[i].checked ? 'checked' : '')}>
						</td>
						<td title="${self.questions[i].columnName}">${self.questions[i].columnName}</td>
						<td title="${self.questions[i].group_name}">${self.questions[i].group_name}</td>
						<td title="${self.questions[i].question}">${self.questions[i].question}</td>
					</tr>
				`;
		}

		table += `
				</tbody>
			`;

		$('#tableQuest' + self.suffix).html(table);

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

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

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

		let tableQuest = $('#tableQuest' + self.suffix).DataTable({
			language: pf.const.language_table,
			scrollY: 300,
			scroller: false,
			paging: true,
			pageLength: 25,
			columnDefs: [
				{ width: '30px', orderable: false, targets: 0 },
				{ width: '45px', targets: 1 }
			],
			autoWidth: false,
			aaSorting: []
		});

		// Ajuste de columnas
		setTimeout(function () {
			tableQuest.columns.adjust();
		}, 200);

		// Ocultar botones de tabla
		hideTableButtons('tableQuest' + self.suffix);

		// Apply the search
		applyTheSearch(tableQuest, 'filtersQuest');

		// Seleccionar por tr
		$('#tableQuest' + self.suffix + ' tbody tr').off().on('click', function () {
			let index = $(this).data('index');
			let checked = $(this).find('.selection').prop('checked');

			if (!checked) {
				$(this).find('.selection').prop('checked', true);
				self.questions[index].checked = true;
			} else {
				$(this).find('.selection').prop('checked', false);
				self.questions[index].checked = false;
			}
		});

		// Seleccionar por checbox
		$('.selection').off().on('click', function () {
			let index = $(this).data('index');
			let checked = $(this).prop('checked');

			if (checked) {
				$(this).prop('checked', false);
				self.questions[index].checked = false;
			} else {
				$(this).prop('checked', true);
				self.questions[index].checked = true;
			}
		});
	},

	renderPool() {
		let self = this;
		let table = `
			<thead>
				<tr>
					<th class="text-center" scope="col" title="">
						<div class="div-global-selection">
							<input type="checkbox" class="globalSelection">
						</div>
					</th>
					<th scope="col" title="Nombre">Nombre</th>
					<th scope="col" title="E-mail">E-mail</th>
					<th scope="col" title="Rol">Rol</th>
					<th scope="col" title="Perfil">Perfil</th>
				</tr>
			</thead>

			<thead class="filtersPool">
				<tr>
					<td>selector</td>
					<td>name</td>
					<td>email</td>
					<td>role</td>
					<td>profile</td>
				</tr>
			</thead>

			<tbody>
		`;

		let empty = true;
		let size = self.participants.length;
		for (let i = 0; i < size; i++) {
			let participant = self.participants[i];
			if (participant.enabled == 1) {
				empty = false;
				let name = `${participant.nameUser} ${participant.userApellidos} ${participant.userApellidos2}`;
				let checked = self.selectedParticipants.some(p => p === participant.email) ? 'checked' : '';
				table += `
					<tr id="${participant.email}" class="c-pointer check-select">
						<td class="text-center">
							<div class="div-single-selection">
								<input type="checkbox" class="selection" ${checked} data-id="${participant.email}">
							</div>
						</td>
						<td class="text-truncate" title="${name}">${name}</td>
						<td class="text-truncate" title="${participant.email}">${participant.email}</td>
						<td class="text-truncate" title="${participant.role}">${participant.role}</td>
						<td class="text-truncate" title="${participant.profile}">${participant.profile}</td>
					</tr>
				`;
			}
		}

		if (empty) {
			$('#tableUser').removeClass('tRegs');
		} else {
			$('#tableUser').addClass('tRegs')
		}

		table += `
			</tbody>
		`;

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

		// Inject search input
		$('#tableUser .filtersPool td').each(function () {
			let title = $(this).text();
			let value = `<input type="text" class="form-control form-control-sm">`;
			if (title == 'selector') {
				value = `<input type="text" class="form-control form-control-sm" disabled>`;
			}
			$(this).html(value);
		});

		let tableUser = $('#tableUser').DataTable({
			language: self.language,
			scrollY: 300,
			scroller: false,
			paging: true,
			pageLength: 50,
			columnDefs: [
				{ width: '25px', orderable: false, targets: 0 },
				{ width: '80px', targets: 4 }
			],
			autoWidth: false,
			aaSorting: []
		});

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

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

		// Apply the search
		applyTheSearch(tableUser, 'filtersPool');

		self.multiSelectTableEvents();

		$('#tableUser').on('draw.dt', function () {
			self.multiSelectTableEvents();
		});
	},

	multiSelectTableEvents() {
		const self = this;

		inputControl();

		// Add selected useers
		$('#addUsers').off().on('click', function () {
			self.selectedParticipants = self.participants
				.filter(participant => self.selectedParticipants.includes(participant.email))
				.map(participant => participant.email);
			// $('#generateURLs').prop('disabled', self.selectedParticipants.length === 0);
			$('#userTable').modal('hide');
			$('#ddreport' + self.suffix).prop('disabled', self.selectedParticipants.length === 0);
		});

		// Select via tr
		$('#tableUser tbody').off().on('click', 'tr', function (event) {
			if (!$(event.target).is('input.selection') && !$(event.target).closest('.div-single-selection').length) {
				let checkbox = $(this).find('.selection');
				checkbox.prop('checked', !checkbox.prop('checked')).change();
			}
		});

		// Refresh table model
		$('#tableUser input.selection').off().on('change', function () {
			let checkedComp = $(this).prop('checked');
			let email = $(this).data('id');
			if (checkedComp) {
				self.selectedParticipants.push(email);
			} else {
				self.selectedParticipants = self.selectedParticipants.filter(e => e !== email);
			}
			inputControl();
		});

		// Global check
		$('.globalSelection').off().on('change', function () {
			if ($('.globalSelection').prop('checked')) {
				$('.selection').prop('checked', true).change();;
			} else {
				$('.selection').prop('checked', false).change();;
			}
		});

		// Refresh global check on single check
		function inputControl() {
			if ($('.selection').length == $('.selection:checked').length && $('.selection').length > 0) {
				$('.globalSelection').prop('checked', true);
			} else {
				$('.globalSelection').prop('checked', false);
			}
		}
	},

	requestGraphs() {

		let self = this;

		$('#resultsContainer').html('');
		let graphTitle = `Misión: ${self.idMission}`;

		let resultContainer = `
			<div class="row p-2 glass-effect">
				<div class="col-12 p-0">
					<!-- Header -->
					<div class="d-flex justify-content-between p-0 c-pointer">
						<div class="d-flex align-items-center">
							<span class="section-title mx-3">${graphTitle}</span>
						</div>

						<button type="button" class="btn btn-link text-body text-decoration-none arrow" data-toggle="collapse" data-target="#containerCollapse" data-arrow="down" data-sub="1">
							${stcmbackend.svg.chevronDown}
						</button>
					</div>

					<!-- Body -->
					<div id="containerCollapse" class="m-0 p-2 collapse show">

						<!-- Gráfica de Respuestas -->
						<div id="resultChart" class="mb-3">
							<div class="card h-100 px-0">
								<div class="card-body">	
									<div id="graphAnswersContainer" class="graphics c-pointer" data-type="graphAnswers">
										<canvas id="graphAnswers" class="he-350 bg-white"></canvas>
									</div>
								</div>
							</div>
						</div>

						<!-- Table -->
						<div id="resultTable" class="accordion mx-0">
							<div class="card py-0 m-0">
								<div class="d-flex justify-content-end p-3">
									<!-- Botón descargar excel -->
									<button id="exportQuestion" type="button" class="btn button-excel secondary-button ma-le-5" title="${pf.const.language.RSC47}">
										${stcmbackend.svg.download}
										<span>${pf.const.language.RSC47}</span>
									</button>
								</div>
								<div class="card-body p-0">
									<div id="registersContainer" class="m-0 p-0"></div>
								</div>
							</div>
						</div>
					</div>
				</div>
			</div>
		`;

		$('#resultsContainer').append(resultContainer);
		let data = self.userTimings;
		let table = new this.Table(data.headers, data.data);
		table.renderTable('registersContainer');

		// Render chart
		let options = {
			"layout": {
				"padding": {
					"top": 0
				}
			},
			"responsive": true,
			"maintainAspectRatio": false,
			"legend": {
				"display": false,
				"onClick": false
			},
			"scales": {
				"xAxes": [{
					"scaleLabel": {
						"display": true,
						"labelString": "Preguntas",
						"fontSize": 16
					},
					"ticks": {
						"display": true,
						"autoSkip": false,
					}
				}],
				"yAxes": [{
					"scaleLabel": {
						"display": true,
						"labelString": "Tiempo (segundos)",
						"fontSize": 16
					},
					"display": true,
					"ticks": {
						"fontSize": 14,
						"beginAtZero": true
					}
				}]
			},
			"tooltips": {
				"enabled": true,
				callbacks: {
					label: function (tooltipItem, data) {
						var originalLabel = data.datasets[tooltipItem.datasetIndex].originalLabels[tooltipItem.index];
						return originalLabel + ': ' + tooltipItem.yLabel;
					}
				}
			},
			"plugins": {
				"datalabels": {
					"color": 'black',
					"font": {
						"weight": 'bold',
						"size": 16
					}
				}
			},
			"title": {
				"display": true,
				"text": pf.const.language.RSC2753,
				"fontSize": 16,
				'padding': 15
			}
		};
		let chartData = self.questionTimings;
		let gradient = [];
		let quantity = chartData.data.length;
		if (quantity == 2) {
			gradient = self.colorsHex;
		} else {
			if (self.typeColors == 1) {
				gradient = generateColors(self.colorsHex[0], self.colorsHex[1], quantity);
			} else {
				gradient = arrayColors(self.colorsHex, quantity);
			}
		}
		let chart = new this.Chart(chartData.labels, chartData.data, options, gradient);
		chart.render('graphAnswers');
	},

	Table: class {
		html = '';
		_headers = null;
		_data = null;

		constructor(headers, data) {
			this._headers = headers;
			this._data = data;
		}

		renderTable(idContainer) {
			const self = this;
			const keys = self._headers.map(header => header.key);

			let title = `Misión: ${self.idMission}`;
			let headers = ``;
			let filters = ``;
			let body = ``;
			self._headers.forEach(header => {
				headers += `<th scope="col" title="${header.name}">${header.name}</th>`;
				filters += `<td data-key=${header.key}>${header.key}</td>`;
			});

			self._data.forEach(entry => {
				let tableData = '';

				self._headers.forEach(header => {
					const key = header.key;
					if (header.type === 'text') {
						const titleAttr = `title="${entry[key]}"`;
						const className = !isNaN(parseFloat(entry[key])) && isFinite(entry[key]) ? 'text-truncate text-center' : 'text-truncate';
						tableData += `<td class="${className}" ${titleAttr}>${entry[key]}</td>`;
					} else if (header.type === 'check') {
						tableData += `
							<td class="text-center">
								<span class="d-none">${entry[key] !== '' && entry[key] !== '0' ? pf.const.language.RSC120 : pf.const.language.RSC121}</span>
								<input type="checkbox" disabled ${entry[key] !== '' && entry[key] !== '0' ? 'checked' : ''}>
							</td>
						`;
					}
				});

				body += `<tr>${tableData}</tr>`;
			});

			self.html = `
				<table id="registers" class="table table-hover tRegs">
					<thead>
						<tr>${headers}</tr>
					</thead>
					<thead class="filtersResult">
						<tr>${filters}</tr>
					</thead>
					<tbody>${body}</tbody>
				</table>
			`;
			$(`#${idContainer}`).html(self.html);

			// Setup table filters
			$('#registers .filtersResult td').each(function () {
				let key = $(this).text();
				let value = '';
				let header = self._headers.find(header => header.key === key);
				if (header.type === 'text') {
					value = `<input type="text" class="form-control form-control-sm">`;
				} else if (header.type === 'check') {
					value = optionsSelectAllYesNo();
				}
				$(this).html(value);
			});

			// Generate column visibility config
			let hiddenColumns = [];
			self._headers.forEach((header, index) => {
				if (!header.visible) {
					hiddenColumns.push(index);
					$('#registers .filtersResult td[data-key="' + header.key + '"]').hide();
				}
			});

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

			applyTheSearch(dataTable, 'filtersResult');

			$('#exportQuestion').off().on('click', function () {
				$('#resultTable .buttons-excel').trigger('click');
			});

		}

		bindEvents() {
		}
	},

	Chart: class {
		html = '';
		_labels = null;
		_data = null;
		_options = null;
		_chart = null;
		colors = [];

		constructor(labels, data, options, colors = []) {
			this._labels = labels;
			this._data = data;
			this._options = options;
			this.colors = colors;
		}

		render(idContainer) {
			const self = this;
			const ctx = document.getElementById(idContainer).getContext('2d');

			let labels = self._labels.map((question, index) => {
				return `P${index + 1}`;
			});

			self._chart = new Chart(ctx, {
				type: 'bar',
				data: {
					labels: labels,
					datasets: [{
						label: 'Time to Answer (seconds)',
						data: self._data,
						backgroundColor: self.colors,
						borderWidth: 1,
						originalLabels: self._labels
					}]
				},
				options: self._options
			});

		}
	}
};