<?php
namespace App\Custom;

use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Request;

use App\Models\Mailer;

use Carbon\Carbon;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use DateTime;
use DateInterval;

//TODO: PHPEXCEL OBSOLETO -> PARA EL FUTURO -> PhpSpreadsheet
//require __DIR__ . "/Classes/PHPExcel.php";

class Misc {

	//const KEY   = "KeyFiDeLitAS2016"; // you can change it

	const KEY = '20335754655';

	private static function TYPEENCRYPT() {
		return env('TYPEENCRYPT');
	}


	//--  METO AUXILIAR PARA GENERAR SUB-ETIQUETAS (NO, SI, PARCIAL ACTUALIZADO, REAPERTURA POR ALTA, ETC)  --//

	public static function etiquetas_aprobado($aprobacion_parcial) {
		$etiquetas = self::etiquetas();
		return $etiquetas[$aprobacion_parcial];
	}



	public static function etiquetas() {
		return $etiquetas = array('NO', 'SI', 'PARCIAL ACTUALIZADO', 'REAPERTURA POR ALTA');
	}



	private static function safe_b64encode($string) {
		$data = base64_encode($string);
		$data = str_replace(array('+', '/', '='), array('-', '_', ''), $data);
		return $data;
	}

	private static function safe_b64decode($string) {
		$data = str_replace(array('-', '_'), array('+', '/'), $string);
		$mod4 = strlen($data) % 4;
		if ($mod4) {
			$data .= substr('====', $mod4);
		}
		return base64_decode($data);
	}

	public static function encrypt(string $data): string {

		if ($data == null) {
			return $data;
		}

		$ivSize = openssl_cipher_iv_length(self::TYPEENCRYPT());
		$iv = openssl_random_pseudo_bytes($ivSize);
		// $iv = $ivSize;
		$encrypted = openssl_encrypt($data, self::TYPEENCRYPT(), self::KEY, OPENSSL_RAW_DATA, $iv);
		$hmac = hash_hmac('sha256', $encrypted, self::KEY, true);
		$cifrado = base64_encode($iv . $hmac . $encrypted);
		return $cifrado;
	}

	//TODO VERIFICAR DESPUES
	public static function decrypt(string $data): string {
		if ($data == null) {
			return $data;
		}
		$c = base64_decode($data);
		//            
		$ivlen = openssl_cipher_iv_length(self::TYPEENCRYPT());
		//      
		$iv = substr($c, 0, $ivlen); // CLAVE ALEATORIO GENERADO
		$hmac = substr($c, $ivlen, 32); // HASH
		$ciphertext_raw = substr($c, $ivlen + 32); // DATOS ENCRIPTADO
		//
		$decrypted = openssl_decrypt($ciphertext_raw, self::TYPEENCRYPT(), self::KEY, OPENSSL_RAW_DATA, $iv);

		return trim($decrypted);
	}

	// USE ESTA FUNCION PARA SABER SI EL STRING A DECIPTAR ES BASE64 - TB
	//public static function is_base64($s){
	//  return (bool) preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $s);
	//}

	/*
	  //Método público que se encarga de encriptar una cadena
	  public static function encrypt($value){ 
		if(!$value){return false;}
		$text = $value;
		$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
		$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
		$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, self::KEY, $text, MCRYPT_MODE_ECB, $iv);
		return trim(self::safe_b64encode($crypttext)); 
	  }

	  //Método público que se encarga de desencriptar únicamente lo que este encriptado con el método encrypt
	  public static function decrypt($value){
		if(!$value){return false;}
		$crypttext = self::safe_b64decode($value); 
		$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
		$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
		$decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, self::KEY, $crypttext, MCRYPT_MODE_ECB, $iv);
		return trim($decrypttext);
	  }
	*/
	//Método para agilizar el envio de emails desde Fidelitas
	public static function enviarMail($view = '', $to = '', $content = '', $subject = "Fidelitas") {
		Mailer::initialize();
		Mailer::from("no-reply@fidelitas.com.ar");
		// echo("MISC 93");
		// dd($to);
		Mailer::to($to);
		$content = \View::make($view)->with('content', $content)->render();
		Mailer::text($content, $subject);
		return Mailer::send();
	}

	public static function obtenerTokenSeccion($secciones = '') {
		$usuario = Session::get('usuario');
		$usuario->preferencias = [];
		$hora_actual = date("h:i:s");
		$token = Request::input('_token');
		//$clientes = SQLConnection::obtenerCliente($usuario->user_id);
		$clientes = SQLConnection::obtenerCliente(ENV('ID_INFORME_COMERCIAL'), $usuario->user_id);
		if (!$clientes) {
			$usuario->user_id = 15342812;//sa
			$clientes = SQLConnection::obtenerCliente(ENV('ID_INFORME_COMERCIAL'), $usuario->user_id);
		}
		foreach ($clientes as $cliente) {
			$cliente_ordenado[$cliente->id_producto] = $cliente;

		}

		$datos = new \stdClass;
		$datos->token = $token;
		$datos->usuario = $usuario;
		$datos->user_id = $usuario->user_id;
		$datos->usuario->client_id = 2254875;//fidelitas
		$datos->usuario->cliente = $cliente_ordenado;
		$datos->hora_actual = $hora_actual;
		$datos->secciones = $secciones;
		$datos->usuario->sesion_externa = true;

		if ($secciones == 'led_balances') {
			$datos->usuario->acceso_led = '1';
		}

		$datos = Misc::encrypt(json_encode($datos));
		return $datos;
	}

	/*
	public static function parsearBusquedaPadron($campo){
	  $campo = preg_replace("/ {2,}/", " ", trim($campo));
	  $exploded = explode(" ",$campo);
	  $full_search = "";
	  if(sizeof($exploded) <= 1){
		$full_search = "\"*".$campo."*\"";
	  }else{
		foreach($exploded as $key => $part){
		  if($key == 0){
			$full_search = "\"*".$part."*\"";
			if($exploded[1] == ""){
			  $full_search = "\"*".$campo."*\"";
			  break;
			}  
		  }else{
			$full_search .= " NEAR "."\"*".$part."*\"";
		  }
		}
	  }
	  return $full_search;

	}
	*/

	/*
	  public static function parsearBusquedaPadron($campo){
		$campo = self::limpiarString($campo);
		$exploded = explode(" ", $campo);
		$full_search = "";
		if (sizeof($exploded) == 1 && strlen($campo) > 2) {
		  return "\"".$campo."\"";
		} elseif ((sizeof($exploded) == 2) && ((strlen($exploded[0]) + strlen($exploded[1])) > 2)) {
		  return "\"".$exploded[0]."\" NEAR "."\"*".$exploded[1]."*\"";
		} elseif (sizeof($exploded) > 2) {
		  foreach($exploded as $key => $part) {
			if($key == 0 && $part != '') {
			  $full_search = "\"".$part."\"";
			} elseif ($part != '') {
			  $full_search .= " NEAR "."\"*".$part."*\"";
			}
		  }
		  return $full_search;
		}
		return $full_search;
	  }
	*/

	public static function parsearBusquedaPadron($campo) {
		$campo = self::limpiarString($campo);
		$exploded = explode(" ", $campo);
		$full_search = "";
		if (sizeof($exploded) == 1 && strlen($campo) > 2) {
			return "\"" . $campo . "*\"";
		} elseif (((sizeof($exploded) == 2) && ((strlen($exploded[0]) + strlen($exploded[1])) > 2)) || (sizeof($exploded) > 2)) {
			foreach ($exploded as $key => $part) {
				if ($part != '') {
					if ($part == 'Y') {
						continue;
					}
					$part = (strlen($part > 1)) ? "\"*" . $part . "*\"" : "\"" . $part . "*\"";
					if ($key == 0) {
						$full_search = $part;
					} else {
						$full_search .= " NEAR " . $part;
					}
				}
			}
			return $full_search;
		}
		return $full_search;
	}

	//Método que calcula el Score sólo con central de deudores de momento.
	public static function calcularScore($situaciones = array(), $maximo_score = 1000) {
		$puntaje_situacion = 100;
		$score = 0;
		if ($situaciones) {
			foreach ($situaciones as $situacion) {
				switch ($situacion->situacion) {
					case '01':
						$score = $puntaje_situacion;
						break;
					case '02':
						$score = (int) $puntaje_situacion / 2;
						break;
					case '03':
						$score = 0;
						break;
					case '04':
					case '05':
						$score = 0;
						# code...
						break;
				}
			}
		}
		return $score;
	}

	//Método que reemplazar caracteres a saltos de linea
	public static function ReemplazarCaracteres($array = array()) {
		return str_replace(array("\r\n", "\n", "\\r", "\\n"), '<br>', $array);
	}

	public static function obtenerColoresEnv() {
		foreach ($_ENV as $key => $value) {
			if (strpos($key, 'COLOR_') === 0) {
				$env[$key] = $value;
			}
		}
		return $env;
	}

	/* Método que sirve interpretar valores de la base de datos y convertirlos a lo que se requiera */
	public static function interpretarDB($cadena) {
		$cadena = strtoupper($cadena);
		if ($cadena == 'N' || $cadena == 'NI') {
			return 'NO INSCRIPTO';
		} else if ($cadena == 'AC' || $cadena == 'S') {
			return 'ACTIVO';
		} else if ($cadena == 'EX') {
			return 'EXENTO';
		} else if ($cadena == 'NA') {
			return 'NO ALCANZADO';
		} else if ($cadena == 'XN') {
			return 'EXENTO NO ALCANZADO';
		} else if ($cadena == 'AN') {
			return 'ACTIVO NO ALCANZADO';
		} else if ($cadena == 'NC') {
			return 'NO CORRESPONDE';
		}

	}
	public static function truncate($text, $chars = 250) {
		$text = $text . " ";
		$text = substr($text, 0, $chars);
		$text = substr($text, 0, strrpos($text, ' '));
		$text = $text . "...";
		return $text;
	}


	/*
	  Este es un ejemplo de como usar el exportar a excel
		$array[0]['cuit'] = '20335754655';
		$array[0]['nombre'] = 'Leonel Turchetto';
		Misc::ExportarEmpleadosExcel($array,'nombre_file');
	*/

	public static function ExportarEmpleadosExcel($data = '', $nombre_file = 'sin_nombre') {
		// Create new PHPExcel object
		$objPHPExcel = new \PHPExcel();
		// Set document properties
		$objPHPExcel->getProperties()->setCreator("Fidelitas")
			->setTitle("Empleados");
		// Add some data
		$objPHPExcel->setActiveSheetIndex(0)->setCellValue('A1', 'Cuit');
		$objPHPExcel->setActiveSheetIndex(0)->setCellValue('B1', 'Nombre');

		foreach ($data as $key => $value) {
			$objPHPExcel->setActiveSheetIndex(0)->setCellValue('A' . ($key + 2), $value['cuit']);
			$objPHPExcel->setActiveSheetIndex(0)->setCellValue('B' . ($key + 2), $value['nombre']);
		}
		// Redirect output to a client’s web browser (Excel2007)
		header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
		header('Content-Disposition: attachment;filename="{$nombre_file}.xlsx"');
		header('Cache-Control: max-age=0');
		// If you're serving to IE 9, then the following may be needed
		header('Cache-Control: max-age=1');

		// If you're serving to IE over SSL, then the following may be needed
		header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
		header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
		header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
		header('Pragma: public'); // HTTP/1.0

		$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
		$objWriter->save('php://output');
		exit;
	}

	public static function restriccionPermiso($permiso = '') {
		//return true; solo para desarrollo
		//return false; 
		if (ENV('DB_SQL_HOST') == '192.168.121.26' || ENV('DB_SQL_DATABASE') == 'fidetest') {
			return true;
		}
		/*
		$sesion_permisos = \Session::get('permisos');
		foreach ($sesion_permisos as $sesion_permiso){
			if ($sesion_permiso->service_id == $permiso){
				return true;
			}
		}  
		*/
		return true;
	}

	public static function obtenerPermisosNavigator() {
		$menu = [];
		//Lista "LEGALES"
		$menu['CENDEU'] = self::restriccionPermiso('CENDEU');
		$menu['DEUDORES'] = self::restriccionPermiso('DEUDORES');
		$menu['JUDICIALES'] = self::restriccionPermiso('JUDICIALES');
		$menu['MOROSIDAD'] = self::restriccionPermiso('MOROSIDAD');
		//Lista "PRODUCCION"
		$menu['BALANCE'] = self::restriccionPermiso('BALANCE');
		$menu['DATOGRAL'] = self::restriccionPermiso('DATOGRAL');
		$menu['SOCDIR'] = self::restriccionPermiso('SOCDIR');
		$menu['PERSONAL'] = self::restriccionPermiso('PERSONAL');
		$menu['NOMINA'] = self::restriccionPermiso('NOMINA');
		$menu['SOCIEDADES'] = self::restriccionPermiso('SOCIEDADES');
		$menu['SEGUROS'] = self::restriccionPermiso('SEGUROS');
		$menu['EDICTOS'] = self::restriccionPermiso('EDICTOS');
		$menu['SCORE'] = self::restriccionPermiso('SCORE');
		$menu['PADRONES'] = self::restriccionPermiso('PADRONES');
		$menu['ADMINLED'] = self::restriccionPermiso('ADMINLED');
		return $menu;
	}
	public static function obtenerPermisosNavigatorNoCuit() {
		$menu = [];
		//Lista "LEGALES"
		$menu['JUDICIALES'] = self::restriccionPermiso('JUDICIALES');
		$menu['CENDEU'] = self::restriccionPermiso('CENDEU');
		$menu['COMERCIAL'] = self::restriccionPermiso('COMERCIAL');
		$menu['PROCESOS'] = self::restriccionPermiso('PROCESOS');
		$menu['MISAPORTES'] = self::restriccionPermiso('MISAPORTES');
		$menu['TABLAGRAL'] = self::restriccionPermiso('TABLAGRAL');
		$menu['ENTIDAD'] = self::restriccionPermiso('ENTIDAD');
		$menu['TERMINOS'] = self::restriccionPermiso('TERMINOS');
		$menu['REPOCONS'] = self::restriccionPermiso('REPOCONS');
		//a agregar.
		$menu['FUENPROC'] = self::restriccionPermiso('FUENPROC');
		$menu['FUENTES'] = self::restriccionPermiso('FUENTES');
		$menu['TAREAS'] = self::restriccionPermiso('TAREAS');
		$menu['FIDEEXT'] = self::restriccionPermiso('FIDEEXT');
		$menu['ICOMERCIAL'] = self::restriccionPermiso('ICOMERCIAL');
		$menu['DCLEANING'] = self::restriccionPermiso('DCLEANING');
		$menu['SCORE'] = self::restriccionPermiso('SCORE');
		$menu['PADRONES'] = self::restriccionPermiso('PADRONES');
		$menu['ADMINLED'] = self::restriccionPermiso('ADMINLED');
		$menu['PREPAGO'] = self::restriccionPermiso('PREPAGO');
		$menu['ASIGNACUITMASIVO'] = self::restriccionPermiso('ASIGNACUITMASIVO');
		$menu['A_VERIFICACION_DOCS'] = self::restriccionPermiso('A_VERIFICACION_DOCS');
		return $menu;
	}

	public static function diccionarioCuits($cuit) {
		$cuit = str_replace(" ", "", $cuit);
		$cuit = str_replace(".", "", $cuit);
		$cuit = str_replace(",", "", $cuit);
		$cuit = str_replace("-", "", $cuit);
		$pre_cuit = substr($cuit, 0, 2); // parte izquierda del cuit
		$pos_cuit = substr($cuit, strlen($cuit) - 1, 1); // parte derecha del cuit
		$center_cuit = substr($cuit, 2, strlen($cuit) - 3);// parte central del cuit
		$cuits[] = '"' . $cuit . '"'; // todo junto, sin separador de miles
		$cuits[] = '"' . $pre_cuit . ',' . $center_cuit . ',' . $pos_cuit . '"';
		$cuits[] = '"' . $pre_cuit . '.' . $center_cuit . '.' . $pos_cuit . '"';
		$cuits[] = '"' . $pre_cuit . '-' . $center_cuit . '-' . $pos_cuit . '"';
		$cuits[] = '"' . $pre_cuit . ' ' . $center_cuit . ' ' . $pos_cuit . '"';
		$cuits[] = '"' . $pre_cuit . ',' . number_format(intval($center_cuit), 0, "", ",") . ',' . $pos_cuit . '"';//separador de miles por comas
		$cuits[] = '"' . $pre_cuit . '.' . number_format(intval($center_cuit), 0, "", ".") . '.' . $pos_cuit . '"';//separador de miles por puntos
		$cuits[] = '"' . $pre_cuit . '-' . number_format(intval($center_cuit), 0, "", "-") . '-' . $pos_cuit . '"';//separador de miles por guiones
		$cuits[] = '"' . $pre_cuit . ' ' . number_format(intval($center_cuit), 0, "", " ") . ' ' . $pos_cuit . '"';//separador de miles por espacios
		return $cuits;
	}
	public static function diccionarioDNIs($dni) {
		$dni = str_replace(" ", "", $dni);
		$dni = str_replace(".", "", $dni);
		$dni = str_replace(",", "", $dni);
		$dni = str_replace("-", "", $dni);
		$dnis[] = '"' . $dni . '"'; // sin separador de miles
		$dnis[] = '"' . number_format(intval($dni), 0, "", ",") . '"';//separador de miles por comas
		$dnis[] = '"' . number_format(intval($dni), 0, "", ".") . '"';//separador de miles por puntos
		$dnis[] = '"' . number_format(intval($dni), 0, "", "-") . '"';//separador de miles por guiones
		$dnis[] = '"' . number_format(intval($dni), 0, "", " ") . '"';//separador de miles por espacios
		return $dnis;
	}

	// datacleaning - juicios 26/05
	public static function diccionarioSinonimos($razon_social) {
		//$razon_social = 'COCA COLA FEMSA DE BUENOS AIRES S.A.';
		$razon_social_segmentada = [];
		$sinonimos = [];
		$palabras_agregar = [];
		$array_palabras_con_sinonimos = [];
		$razones_sociales_con_sinonimos = '';
		// Obtengo omitidos y los elimino
		$omitidos = SQLConnection::obtenerOmitidos();
		foreach ($omitidos as $omitido) {

			foreach ($omitido as $valor) {
				if (!empty($valor)) {
					// print_r($valor);print_r(' | ');
					$razon_social = preg_replace("/$valor\Z/", "", $razon_social);
					$razon_social = rtrim($razon_social);
					// print_r($razon_social);
				}
			}
			//dd($razon_social);
		}

		return "\"" . $razon_social . "\"";
		$palabras = explode(' ', $razon_social);

		// Si existen palabras mayores  1 letra...
		foreach ($palabras as $key => $palabra) {
			if (strlen($palabra) > 1) {
				$razon_social_segmentada[] = $palabra;
			}
		}

		// Si existen palabras o sinonimos en el array...
		if (sizeof($razon_social_segmentada) == 1) {
			return "\"" . $razon_social_segmentada[0] . "\"";
		}

		// Busco sinonimos de acuerdo a las palabras segmentadas de la razon social...
		foreach ($sinonimos as $sinonimo) {
			$resp = SQLConnection::obtenerSinonimos($sinonimo);
			if ($resp) {
				$palabras_agregar[] = $resp;
			}
		}

		// Si no existen sinonimos...
		if (!$palabras_agregar) {
			// return "\"".implode(" ",$sinonimos)."\"";
			return false;
		}

		$posicion_reemplazo = null;
		$textos_semejantes = array();
		$nuevos_textos = "";

		//Buscando posicion a reemplazar
		foreach ($palabras_agregar as $cantidad_sinonimo => $lote) {
			foreach ($lote as $palabra) {
				if (!empty($palabra)) {
					foreach ($sinonimos as $key => $segmentado) {
						if ($palabra == $segmentado) {
							$posicion_reemplazo[$cantidad_sinonimo] = $key;
						}
					}
				}
			}
		}

		// Estructurando las semejanzas
		foreach ($palabras_agregar as $cantidad_sinonimo => $lote) {
			foreach ($lote as $key_sin => $palabra) {
				if (!empty($palabra)) {
					foreach ($sinonimos as $key => $segmentado) {
						if (isset($posicion_reemplazo[$cantidad_sinonimo]) && ($posicion_reemplazo[$cantidad_sinonimo] == $key)) {
							$textos_semejantes[$cantidad_sinonimo][$key_sin][$key] = $palabra;
						} else {
							$textos_semejantes[$cantidad_sinonimo][$key_sin][$key] = $segmentado;
						}
					}
				}
			}
		}

		$cantidad_palabras_razon_social = count($sinonimos) - 1;

		// ultima llave general
		$nuevo_textos_general = $textos_semejantes;
		end($nuevo_textos_general);
		$ultima_llave_textos_general = key($nuevo_textos_general);

		// Concatenando
		foreach ($textos_semejantes as $key => $sinom_textos) {
			foreach ($sinom_textos as $key2 => $semejanzas) {
				// ultima llave semejantes
				$nuevo_textos_semejantes = $sinom_textos;
				end($nuevo_textos_semejantes);
				$ultima_llave_textos_semejantes = key($nuevo_textos_semejantes);

				foreach ($semejanzas as $key3 => $valor) {
					// primera llave valor
					$primer_llave_textos_valor = key($semejanzas);
					if ($primer_llave_textos_valor == $key3) {
						$nuevos_textos .= "\"";
					}

					// ultima llave valor
					$nuevo_textos_valor = $semejanzas;
					end($nuevo_textos_valor);
					$ultima_llave_textos_valor = key($nuevo_textos_valor);

					// Si esta recorriendo la cantidad de palabras de la razon social
					if ($cantidad_palabras_razon_social != $key3) {
						$nuevos_textos .= $valor . ' ';
					} else {
						// Agregando mas semejanzas
						if (($ultima_llave_textos_general == $key) && ($ultima_llave_textos_semejantes == $key2) && ($ultima_llave_textos_valor == $key3)) {
							$nuevos_textos .= $valor . "\"";
						} else {
							$nuevos_textos .= $valor . "\"" . ' or ';
						}
					}
				}
			}
		}

		if (strlen($nuevos_textos) >= 8000) {
			$nuevos_textos = self::sinonimTruncate($nuevos_textos, 8000);
		}

		return $nuevos_textos;
	}

	public static function sinonimTruncate($string, $chars_count) {
		$text = substr($string, 0, $chars_count);
		$text = substr($text, 0, strrpos($text, 'or'));
		return $text;
	}

	public static function ResaltarResultadosEdictosHomonimos($sinonimos, $edictos, $razon_social) {
		$sinonimos = str_replace("\"", "", $sinonimos);
		$sinonimos_segmentados = explode(" or ", $sinonimos);

		foreach ($edictos as $key => $edicto) {
			// Resaltando la Razon Social
			$edictos[$key]->contenido_archivo = str_ireplace($razon_social, "<span class='fw600' style='font-size:14px;background-color:yellow;'>" . $razon_social . "</span>", $edicto->contenido_archivo);

			// Resaltando los sinonimos de razon social
			foreach ($sinonimos_segmentados as $sinonimo) {
				$edictos[$key]->contenido_archivo = str_ireplace($sinonimo, "<span class='fw600' style='font-size:14px;background-color:yellow;'>" . $sinonimo . "</span>", $edicto->contenido_archivo);
			}
		}
		return $edictos;
	}

	public static function ResaltarResultadosEdictos($edictos, $razon_social, $sinonimos) {
		foreach ($edictos as $key => $edicto) {
			if (!empty($sinonimos)) {
				foreach ($sinonimos as $sinonimo) {
					$edictos[$key]->texto = str_ireplace($sinonimo, "<span class='fw600' style='font-size:14px;background-color:yellow;'>" . $sinonimo . "</span>", self::sanear_string($edicto->texto));
				}
			}

			if (!empty($razon_social)) {
				$edictos[$key]->texto = str_ireplace($razon_social, "<span class='fw600' style='font-size:14px;background-color:yellow;'>" . $razon_social . "</span>", self::sanear_string($edicto->texto));
			}
		}
		return $edictos;
	}

	// get date microtime yyyy-mm-dd hh:mm:ss.uuuuuuuu
	public static function now() {
		list($usec, $sec) = explode(' ', microtime());
		return date('Y-m-d H:i:s', $sec) . substr(str_replace("0.", ".", $usec), 0, 3);
	}

	// write to html log
	public static function Log($txt, $dir, $type = "txt") {
		$f_log = fopen($dir, "a");
		$now = Misc::now();
		if ($type == "html") {
			$html = "<span style='font-size:12px; color:#666'>[" . $now . "]</span> " . $txt;
			fwrite($f_log, $html . "<br>");
		} else {
			$txt = "[" . $now . "] " . $txt . "\n";
			fwrite($f_log, $txt);
		}
		fclose($f_log);
		return 0;
	}

	// move file
	public static function moverArchivo($file, $destfile) {
		$resp = '';
		try {
			//$destfile = str_replace(self::$directorio_fuente, self::$directorio_destino, $file);
			$destdir = pathinfo($destfile)["dirname"];

			// genero nuevo directorio
			if (!file_exists($destdir)) {
				try {
					$um = umask(0);
					$res = mkdir($destdir, 0777, true);
					umask($um);
				} catch (\Exception $e) {
					throw new \Exception("Error fatal creando el nuevo directorio de destino: " . $destdir);
				}
				if ($res === FALSE) {
					throw new \Exception("No se pudo crear el nuevo directorio de destino: " . $destdir);
				}
			}

			// copio file
			try {
				$res = copy($file, $destfile);
			} catch (\Exception $e) {
				throw new \Exception("Error fatal copiando el archivo: " . $file);
			}
			if ($res === FALSE) {
				throw new \Exception("No se pudo copiar el archivo: " . $file);
			}

			// elimino file
			try {
				$res = unlink($file);
			} catch (\Exception $e) {
				throw new \Exception("Error fatal eliminando el archivo: " . $file);
			}
			if ($res === FALSE) {
				throw new \Exception("No se pudo eliminar el archivo " . $file);
			}

			return 1;

		} catch (\Exception $e) {
			return $res;
		}
	}

	/* 
	  Organiza los input de un formulario de forma ASC 
	  y asigna null a todos los campos vacíos para ser
	  procesados por SP en orden con null respectivos
	*/
	public static function organizarRequest($inputs_ignorados = []){
		// si es un solo valor lo parsea a string y luego array
		$inputs_ignorados = (is_array($inputs_ignorados)) ? $inputs_ignorados : array((String)$inputs_ignorados);
		$inputs_ignorados[] = '_token';
		$inputs = Request::except($inputs_ignorados); 
		// ordenados alfabeticamente ASC
		ksort($inputs);
		// asignar null a todos los campos vacíos
		$inputs = self::convertirStringsVaciosEnNull($inputs);
	
		return $inputs;
	}

	// asignar null a todos los campos string vacíos de un array
	public static function convertirStringsVaciosEnNull($array = []) {
		return array_map(
			function ($valor) {
				return ($valor === '' || $valor === "") ? null : $valor;
			}, $array);
	}

	public static function convertirFormatoFecha($date, $from = 'd/m/Y', $to = 'Y-m-d') {
		if (isset($date) && isset($from) && isset($to)) {
			$aux = DateTime::createFromFormat($from, $date);
			if ($aux !== false) {
				$date = $aux->format($to);
			}
			return $date;
		}
		return null;
	}

	public static function limpiarString($str) {
		//limpia string para búsqueda, solo dejando caracteres alfanuméricos y espacios simples
		$str = trim($str);
		$str = preg_replace('/\s+/', ' ', $str);
		$str = preg_replace('/[^\p{Latin}\d ]/u', '', $str);
		$str = trim($str);
		return strtoupper($str);
	}

	public static function armarDomicilio($domicilio, $codpos, $loc_nombre, $prv_nombre, $pai_nombre) {
		$return = $domicilio;
		if ($codpos) {
			$return .= ',(' . $codpos . ')';
		}
		if ($loc_nombre) {
			$return .= ',' . $loc_nombre;
		}
		if ($prv_nombre) {
			$return .= ',' . $prv_nombre;
		}
		if ($pai_nombre) {
			$return .= ',' . $pai_nombre;
		}
		return $return;
	}

	public static function resultadoCombinaciones($words) {
		$count_words = count($words);
		if ($count_words <= 1) {
			$result = $words;
		} else {
			if ($count_words > 7) {
				$words = array_slice($words, 0, 7);
				$count_words = count($words);
			}
			//
			$result = array();
			for ($i = 0; $i < $count_words; ++$i) {
				$firstword = $words[$i];
				$remainingwords = array();
				for ($j = 0; $j < $count_words; ++$j) {
					if ($i <> $j)
						$remainingwords[] = $words[$j];
				}
				$combos = self::resultadoCombinaciones($remainingwords);
				for ($j = 0; $j < count($combos); ++$j) {
					$result[] = $firstword . ' ' . $combos[$j];
				}
			}
		}
		return $result;
	}

	public static function tipoPersona($cuit, $id_padron = null) {
		//$fisica_juridica = SQLConnection::obtenerTipoPersona($cuit);
		$fisica_juridica = SQLConnection::backendStoreProcedure('obtener_tipo_persona', array($cuit, $id_padron), 'selectOne');
		#$fisica_juridica = SQLConnection::backendStoreProcedure('dbo.obtener_tipo_persona', array($cuit, $id_padron),'SelectOne');    

		if (isset($fisica_juridica->tipo_persona)) {
			if ($fisica_juridica->tipo_persona == 'F' || $fisica_juridica->tipo_persona == 'J') {
				return $fisica_juridica->tipo_persona;
			} else {
				return (substr($cuit, 0, 1) == 3) ? 'J' : 'F';
			}
		} else {
			return (substr($cuit, 0, 1) == 3) ? 'J' : 'F';
		}
	}

	public static function diccionarioSinonimosTEST_11012022($razon_social) {
		$razon_social_segmentada = [];
		$sinonimos = [];
		$palabras_agregar = [];
		$array_palabras_con_sinonimos = [];
		$razones_sociales_con_sinonimos = '';
		$omitidos = SQLConnection::obtenerOmitidos();
		foreach ($omitidos as $omitido) {

			foreach ($omitido as $valor) {
				if (!empty($valor)) {
					$razon_social = preg_replace("/$valor\z/", "", $razon_social);
				}
			}
		}
		$razon_social = array_map('trim', $razon_social);

		foreach ($razon_social as $key => $value) {
			$razon_social[$key] = "\"" . $value . "\"";
		}

		return $razon_social;
	}

	public static function diccionarioSinonimosTEST($razon_social) {
		$razon_social_segmentada = [];
		$sinonimos = [];
		$palabras_agregar = [];
		$array_palabras_con_sinonimos = [];
		$razones_sociales_con_sinonimos = '';
		//$omitidos                       = SQLConnection::obtenerOmitidos();
		$omitidos = SQLConnection::backendStoreProcedure('obtener_omitidos_sinonimos', array());

		// dd($omitidos);
		foreach ($omitidos as $omitido) {

			foreach ($omitido as $valor) {
				//print_r("\n". $valor ." - ");
				if (!empty($valor)) {
					//$valor = str_ireplace(".", "\\.", $valor);
					//print_r($valor);
					// $razon_social = preg_replace("/\^$valor/","", $razon_social);
					// print_r($razon_social);

					// $razon_social = preg_replace(" "."/$valor\$/","", $razon_social);
					// print_r($razon_social);
					$valor1 = $valor . " ";
					$razon_social = preg_replace('/^' . preg_quote($valor1, '/') . '/', '', $razon_social);
					$valor1 = " " . $valor;
					$razon_social = preg_replace('/' . preg_quote($valor1, '/') . '$/', '', $razon_social);
					$valor1 = " " . $valor . " ";
					$razon_social = str_ireplace($valor1, " ", $razon_social);
					//        print_r($razon_social);
				}
			}
		}
		//die();
		$razon_social = array_map('trim', $razon_social);

		foreach ($razon_social as $key => $value) {
			$value = rtrim($value);
			if (substr($value, -2, 1) == " ") // si termina con solo una letra elimina esa letra del final
			{
				$value = substr($value, 0, -1);
			}
			$value = rtrim($value);
			$razon_social[$key] = "\"" . $value . "\"";
		}
		//print_r($razon_social);

		return $razon_social;
	}

	public static function diccionarioSinonimos2020($razon_social) {
		$razon_social_segmentada = [];
		$sinonimos = [];
		$palabras_agregar = [];
		$array_palabras_con_sinonimos = [];
		$razones_sociales_con_sinonimos = '';
		$omitidos = SQLConnection::backendStoreProcedure('obtener_omitidos_sinonimos', array());
		foreach ($omitidos as $omitido) {

			foreach ($omitido as $valor) {
				if (!empty($valor)) {
					//$razon_social = preg_replace("/$valor\z/","", $razon_social);
					$valor1 = $valor . " ";
					$razon_social = preg_replace('/^' . preg_quote($valor1, '/') . '/', '', $razon_social);
					$valor1 = " " . $valor;
					$razon_social = preg_replace('/' . preg_quote($valor1, '/') . '$/', '', $razon_social);
					$valor1 = " " . $valor . " ";
					$razon_social = str_ireplace($valor1, " ", $razon_social);

					$razon_social = rtrim($razon_social);
				}
			}
		}
		$razon_social = rtrim($razon_social);
		if (substr($razon_social, -2, 1) == " ") // si termina con solo una letra elimina esa letra del final
		{
			$razon_social = substr($razon_social, 0, -1);
		}
		$razon_social = rtrim($razon_social);

		return "\"" . $razon_social . "\"";
	}

	public static function ResaltarResultadosEdictosHomonimosPF($edictos, $razon_social) {
		foreach ($edictos as $key => $edicto) {
			foreach ($razon_social as $rs) {
				$edictos[$key]->contenido_archivo = str_ireplace($rs, "<span class='fw600' style='font-size:14px;background-color:yellow;'>" . $rs . "</span>", self::sanear_string($edicto->contenido_archivo));
			}
		}
		return $edictos;
	}

	public static function ResaltarResultadosEdictosHomonimosPJ($edictos, $razon_social, $sinonimos) {
		foreach ($edictos as $key => $edicto) {
			if (isset($razon_social)) {
				$edictos[$key]->contenido_archivo = str_ireplace($razon_social, "<span class='fw600' style='font-size:14px;background-color:yellow;'>" . $razon_social . "</span>", $edicto->contenido_archivo);
			}

			if (isset($sinonimos)) {
				$edictos[$key]->contenido_archivo = str_ireplace($sinonimos, "<span class='fw600' style='font-size:14px;background-color:yellow;'>" . $sinonimos . "</span>", $edicto->contenido_archivo);
			}
		}
		return $edictos;
	}

	//Resalta edictos cuando encuentra nombres posibles relacionados a un mismo CUIT (TEST)
	public static function ResaltarResultadosEdictosHomonimosPJ_TEST($edictos, $razon_social, $sinonimos) {
		//dd($sinonimos);
		foreach ($edictos as $key => $edicto) {
			if (isset($razon_social)) {
				$razon_social = str_replace('"', '', $razon_social);
				$edictos[$key]->contenido_archivo = str_ireplace($razon_social, "<span class='fw600' style='font-size:14px;background-color:yellow;'>" . $razon_social . "</span>", self::sanear_string($edicto->contenido_archivo));
			}
			if (isset($sinonimos)) {
				foreach ($sinonimos as $value) {
					$value = str_replace('"', '', $value);
					$edictos[$key]->contenido_archivo = str_ireplace($value, "<span class='fw600' style='font-size:14px;background-color:yellow;'>" . $value . "</span>", self::sanear_string($edicto->contenido_archivo));
				}
			}

		}
		return $edictos;
	}

	public static function ResaltarResultadosEdictosFrontend($sinonimos, $edictos, $razon_social) {

		if (isset($sinonimos)) {
			foreach ($edictos as $key => $edicto) {
				// Resalta los sinonimos (con palabras omitidos) - ej: SANCOR
				$edictos[$key]->texto = str_ireplace($sinonimos, "<span class='fw600' style='font-size:14px;background-color:yellow;'>" . $sinonimos . "</span>", $edicto->texto);
			}
		}

		// Resalta razon social sin palabras omitidas - ej: SANCOR S.A
		//$edictos[$key]->texto = str_ireplace($razon_social, "<span class='fw600' style='font-size:14px;background-color:yellow;'>".$razon_social."</span>", $edicto->texto);

		return $edictos;
	}


	public static function ResaltarResultadosEdictosHomonimosNombresAnt($edictos, $sinonimos) {
		//dd($sinonimos);
		foreach ($edictos as $key => $edicto) {
			if (isset($sinonimos)) {
				foreach ($sinonimos as $value) {
					$value = str_replace('"', '', $value);
					// $edictos[$key]->contenido_archivo = str_ireplace($value, "<span class='fw600' style='font-size:14px;background-color:yellow;'>" . $value . "</span>", self::sanear_string($edicto->contenido_archivo));
					$edictos[$key]->razon_social = str_ireplace($value, "<span class='fw600' style='font-size:14px;background-color:yellow;'>" . $value . "</span>", self::sanear_string($edicto->razon_social));
				}
			}

		}
		return $edictos;
	}

	public static function sanear_string($string) {

		$string = trim($string);

		$string = str_replace(
			array('á', 'à', 'ä', 'â', 'ª', 'Á', 'À', 'Â', 'Ä'),
			array('a', 'a', 'a', 'a', 'a', 'A', 'A', 'A', 'A'),
			$string
		);

		$string = str_replace(
			array('é', 'è', 'ë', 'ê', 'É', 'È', 'Ê', 'Ë'),
			array('e', 'e', 'e', 'e', 'E', 'E', 'E', 'E'),
			$string
		);

		$string = str_replace(
			array('í', 'ì', 'ï', 'î', 'Í', 'Ì', 'Ï', 'Î'),
			array('i', 'i', 'i', 'i', 'I', 'I', 'I', 'I'),
			$string
		);

		$string = str_replace(
			array('ó', 'ò', 'ö', 'ô', 'Ó', 'Ò', 'Ö', 'Ô'),
			array('o', 'o', 'o', 'o', 'O', 'O', 'O', 'O'),
			$string
		);

		$string = str_replace(
			array('ú', 'ù', 'ü', 'û', 'Ú', 'Ù', 'Û', 'Ü'),
			array('u', 'u', 'u', 'u', 'U', 'U', 'U', 'U'),
			$string
		);

		$string = str_replace(
			array('ñ', 'Ñ', 'ç', 'Ç'),
			array('n', 'N', 'c', 'C', ),
			$string
		);

		/* $string = str_replace(
			 array("¨", "º", "-", "~",
				  "#", "@", "|", "!", "\"",
				  "·", "$", "%", "&", "/",
				  "(", ")", "?", "'", "¡",
				  "¿", "[", "^", "<code>", "]",
				  "+", "}", "{", "¨", "´",
				  ">", "< ", ";", ",", ":",
				  "."),
			 '',
			 $string
		 );*/

		return $string;
	}

	public static function diccionarioRazonesSociales($razon_social) {
		$words = explode(' ', $razon_social);
		$to_search[0][0] = ['ARG', 'ARGENTINA'];
		$to_search[0][1] = [];
		$to_search[1][0] = ['SACIIF'];
		$to_search[1][1] = [' SACII Y F'];
		$to_search[2][0] = ['SRL'];
		$to_search[2][1] = [' S R L', ' SOC RESP LTDA', ' SOCIEDAD DE RESPONSABILIDAD LIMITADA'];
		$to_search[3][0] = ['SA'];
		$to_search[3][1] = [' S A', ' SOCIEDAD ANONIMA'];
		$to_search[4][0] = ['SH'];
		$to_search[4][1] = [' S H', ' S DE H', ' SOCIEDAD DE HECHO'];
		$dictionary = false;

		foreach ($to_search as $array) {
			$dictionary = self::buscarArray($array[0], $words, array_map('ltrim', $array[1]));
			if (is_array($dictionary)) {
				return $dictionary;
			}

			if ($array[1] != []) {
				$dictionary = self::buscarString($array[1], $razon_social, array_map(function ($word) {
					return ' ' . $word; }, $array[0]));
				if (is_array($dictionary)) {
					return $dictionary;
				}
			}
		}
		return false;
	}

	public static function buscarArray($to_search, $words, $to_add = []) {
		$aux = $to_search;
		$dictionary = [];
		foreach ($to_search as $searching) {
			$key = array_search($searching, $words);
			if ($key !== false && $key != 0) {
				$aux = array_merge($aux, $to_add);
				foreach ($aux as $value) {
					$words[$key] = $value;
					$dictionary[] = implode(' ', $words);
				}
				return $dictionary;
			}
		}
		return false;
	}

	public static function buscarString($to_search, $string, $to_add = []) {
		$aux = $to_search;
		$dictionary = [];
		foreach ($to_search as $searching) {
			$key = strpos($string, $searching);
			if ($key !== false && $key != 0) {
				$aux = array_merge($aux, $to_add);
				foreach ($aux as $value) {
					$dictionary[] = preg_replace('/' . $searching . '/', $value, $string, 1);
				}
				return $dictionary;
			}
		}
		return false;
	}

	public static function reemplazarAcentosPorEquivalentes($string = '') {

		$normalizeChars = array(
			'Š' => 'S', 'š' => 's', 'Ð' => 'D', 'Ž' => 'Z', 'ž' => 'z', 'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A',
			'Å' => 'A', 'Æ' => 'A', 'Ç' => 'C', 'È' => 'E', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I',
			'Ï' => 'I', 'Ñ' => 'N', 'Ń' => 'N', 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ö' => 'O', 'Ø' => 'O', 'Ù' => 'U', 'Ú' => 'U',
			'Û' => 'U', 'Ü' => 'U', 'Ý' => 'Y', 'Þ' => 'B', 'ß' => 'Ss', 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' => 'a',
			'å' => 'a', 'æ' => 'a', 'ç' => 'c', 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e', 'ì' => 'i', 'í' => 'i', 'î' => 'i',
			'ï' => 'i', 'ð' => 'o', 'ñ' => 'n', 'ń' => 'n', 'ò' => 'o', 'ó' => 'o', 'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ø' => 'o', 'ù' => 'u',
			'ú' => 'u', 'û' => 'u', 'ü' => 'u', 'ý' => 'y', 'ý' => 'y', 'þ' => 'b', 'ÿ' => 'y', 'ƒ' => 'f',
			'ă' => 'a', 'î' => 'i', 'â' => 'a', 'ș' => 's', 'ț' => 't', 'Ă' => 'A', 'Î' => 'I', 'Â' => 'A', 'Ș' => 'S', 'Ț' => 'T',
		);
		return strtoupper(strtr($string, $normalizeChars));
	}

	public static function resaltarStringEnContenido($string, $contenido) {
		return str_ireplace($string, "<span class='fw600' style='font-size:14px; background-color:yellow;'>" . $string . "</span>", $contenido);
	}

	public static function paginarArray($searchResults, $path, $perPage = 10) {
		//Get current page form url e.g. &page=6
		$currentPage = LengthAwarePaginator::resolveCurrentPage();
		//Create a new Laravel collection from the array data
		$collection = new Collection($searchResults);
		//Slice the collection to get the items to display in current page
		$currentPageSearchResults = $collection->slice(($currentPage - 1) * $perPage, $perPage)->all();
		//Create our paginator and pass it to the view
		$paginatedSearchResults = new LengthAwarePaginator($currentPageSearchResults, count($collection), $perPage);
		$paginatedSearchResults->setPath($path);

		return $paginatedSearchResults;
	}

	public static function agregarCerosAlDNI($dni) {
		if (strlen($dni) < 8) {
			$ceros = 8 - strlen($dni);
			for ($i = 0; $i < $ceros; $i++) {
				$dni = '0' . $dni;
			}
		}
		return $dni;
	}

	public static function esRazonSocialDeSoloCaracteres($razon_social) {
		$words = explode(' ', $razon_social);
		$to_search[0][0] = ['ARG', 'ARGENTINA'];
		$to_search[0][1] = [];
		$to_search[1][0] = ['SACIIF'];
		$to_search[1][1] = [' SACII Y F'];
		$to_search[2][0] = ['SRL'];
		$to_search[2][1] = [' S R L', ' SOCIEDAD DE RESPONSABILIDAD LIMITADA'];
		$to_search[3][0] = ['SA'];
		$to_search[3][1] = [' S A', ' SOCIEDAD ANONIMA'];
		$to_search[4][0] = ['SH'];
		$to_search[4][1] = [' S H', ' S DE H', ' SOCIEDAD DE HECHO'];
		$dictionary = false;

		foreach ($to_search as $array) {
			$dictionary = self::buscarArray($array[0], $words, array_map('ltrim', $array[1]));
			if (is_array($dictionary)) {
				return $dictionary;
			}

			if ($array[1] != []) {
				$dictionary = self::buscarString($array[1], $razon_social, array_map(function ($word) {
					return ' ' . $word; }, $array[0]));
				if (is_array($dictionary)) {
					return $dictionary;
				}
			}
		}
		return false;
	}

	public static function abrirDirectorio($path, $reference = '') {
		/*
		verifica si existe la ruta, 
		si es un directorio lo abre y devuelve el objeto de tipo array, 
		con el cual se trabajará en la posición cero, ejemplo: 

		$opened_root = Misc::abrirDirectorio($root_path);
		if (is_array($opened_root)) {
		  while (($sub_folder_or_file = readdir($opened_root[0])) !== false) {
		  ...
		  }
		  closedir($opened_root[0]);
		}

		(el dir debe ser cerrado manualmente luego de usar este método)
		si no es un directorio devuelve false
		si no tiene permisos para lectura devuelve un string con el error
		la variable REFERENCE puede usarse para aumentar la precisión del error, 
		por ejemplo pasar la linea y nombre de un archivo, datos previos al llamado del método, entre otros.
		*/
		if (isset($path) && file_exists($path)) {
			if (is_dir($path) && (basename($path) != '.') && (basename($path) != '..')) {
				if (($opened_path = opendir($path)) !== false) {
					return [$opened_path];
				}
				return "{$reference}[$path] Error: no se pudo abrir el directorio, revisar si tiene permisos.";
			}
			return false; // no es un directorio, pero esto no es necesariamente un error.
		}
		return "{$reference}[$path] Error: el directorio no existe.";
	}

	public static function abrirArchivo($path, $reference = '') {
		/*
		verifica si existe la ruta, 
		si es un archivo lo abre y devuelve el objeto de tipo array, 
		con el cual se trabajará en la posición cero, ejemplo: 

		$opened_file = Misc::abrirArchivo($path);
		if (is_array($opened_file)){
		  $numero_linea = 0;
		  while (($line = fgets($opened_file[0])) !== false) {
			$numero_linea++;
			...
		  }
		  fclose($opened_file[0]);
		}

		(el archivo debe ser cerrado manualmente luego de usar este método)
		si no es un archivo devuelve false
		si no tiene permisos para lectura devuelve un string con el error
		la variable REFERENCE puede usarse para aumentar la precisión del error, 
		por ejemplo pasar la linea y nombre de un archivo, datos previos al llamado del método, entre otros.
		*/
		if (isset($path) && file_exists($path)) {
			if (is_file($path)) {
				if (($opened_path = fopen($path, "r")) !== false) {
					return [$opened_path];
				}
				return "{$reference}[$path] Error: no se pudo abrir el archivo, revisar si tiene permisos.";
			}
			return false; // no es un archivo, pero esto no es necesariamente un error.
		}
		return "{$reference}[$path] Error: el archivo no existe.";
	}

	public static function ddd($var) {
		echo "<pre>" . print_r($var, true) . "</pre>";
		die();
	}

	//se formatea la fecha para los archivos de cyq de BT, viene el campo junto, se lo separa con guiones
	public static function formatFecha($array_fechas) {
		foreach ($array_fechas as $value) {
			$format_anio = substr($value, 0, 4);
			$format_mes = substr($value, 4, 2);
			$format_dia = substr($value, 6, 2);
			if ($value != '') {
				$res_format[] = $format_anio . '-' . $format_mes . '-' . $format_dia;
			} else {
				$res_format[] = null;
			}
		}
		return $res_format;
	}

	public static function busquedaPalabrasCyQbT($texto) {
		if (strpos($texto, 'QUIEBRA') !== false || strpos($texto, 'quiebra') !== false) {
			return 'QUIEBRA';
		} elseif (strpos($texto, 'CONCURSO') !== false || strpos($texto, 'concurso') !== false) {
			return 'CONCURSO';
		} else {
			return 'NODATA';
		}


	}

	public static function obtenerHtmlPortalTramites($num_acta, $num_boletin) {
		$html = '';
		$url_html_marca_externo = 'https://portaltramites.inpi.gob.ar/Clasico/Docs/ResultadosConsultas/ResultadoSolicitudMarca2.asp?Va=' . $num_acta;
		$url_header = get_headers($url_html_marca_externo);
		if (($url_header[0] == 'HTTP/1.1 302 Found') || ($url_header[0] == 'HTTP/1.1 500 Internal Server Error')) {
			return 'no_html_portal';
		} else {
			$html = trim(file_get_contents($url_html_marca_externo));
			if (!is_dir('/var/www/html/compartido/marcas_html/' . $num_boletin . '/marcas/')) {
				mkdir('/var/www/html/compartido/marcas_html/' . $num_boletin . '/marcas/', 0777, true);
				file_put_contents('/var/www/html/compartido/marcas_html/' . $num_boletin . '/marcas/' . $num_acta . '.html', $html);
				return 'ok';
			} elseif (!file_exists('/var/www/html/compartido/marcas_html/' . $num_boletin . '/marcas/' . $num_acta . '.html')) {
				file_put_contents('/var/www/html/compartido/marcas_html/' . $num_boletin . '/marcas/' . $num_acta . '.html', $html);
				return 'ok';
			}
		}
	}

	public static function limpiarParametro($parametro) {
		$parametro = str_replace('"', '', $parametro);
		$parametro = str_replace("'", '', $parametro);
		return $parametro;
	}

	public static function parseoHtmlMarcas() {
		$html = 'https://portaltramites.inpi.gob.ar/Clasico/Docs/ResultadosConsultas/ResultadoSolicitudMarca2.asp?Va=1732412';
		$html = trim(file_get_contents($url_html_marca_externo));
		return $html;
	}


	public static function generateRandomString($length = 10) {
		$characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
		$charactersLength = strlen($characters);
		$randomString = '';
		for ($i = 0; $i < $length; $i++) {
			$randomString .= $characters[rand(0, $charactersLength - 1)];
		}
		return $randomString;
	}


	public static function periodoVencido($fmt = 'Ym') {
		$m1 = date_create_from_format('Y-m-d', date('Y-m-') . '01');
		$di = date_interval_create_from_date_string('-1 month');
		return date_format(date_add($m1, $di), $fmt);
	}

	public static function fechaMesProximo($fmt = 'd/m/Y') {
		$m1 = date_create_from_format('Y-m-d', date('Y-m-') . '01');
		$di = date_interval_create_from_date_string('1 month');
		return date_format(date_add($m1, $di), $fmt);
	}


	public static function enviarMailLED($view = '', $from = '', $to = '', $bcc = '', $replyto = '', $content = '', $subject = "Fidelitas", $attach = '', $attach_name = '', $cc = '', $logo = '', $title = '', $to_array = []) {
		Mailer::initialize();
		Mailer::from($from);
		// echo("MISC 1280");
		// dd($to);
		
		if (is_array($to) && empty($to_array)) {
			$to_array = $to;
		}

		if (empty($to_array)) {
			$to_array[] = $to;
		}
		Mailer::to($to_array);
		Mailer::cc($cc);
		Mailer::bcc($bcc);
		Mailer::replyto($replyto);

		if ($logo !== '' && $view == '/led/led_email_generico') {
			$content =
				'<table width="100%" border="0" cellspacing="0" cellpadding="3" class="HeaderTable">' .
				'<tr>' .
				'<td valign="top" valign="middle"><img src="' . $logo . '" alt="" border="0"></td>' .
				'</tr>' .
				'<tr>' .
				'<td>' .
				'<br />' .
				$content .
				'<br /></td></tr></table>';
		}

		$content = \View::make($view)->with('content', $content, 'title', $title)->render();
		Mailer::text($content, $subject);
		if ($attach_name != '') {
			Mailer::attachment($attach, $attach_name);
		} else {
			Mailer::attachment($attach);
		}
		return Mailer::send();
	}
	//Llamado CURL.
	public static function CURLCall($url, $params, $type = "POST", $timeout = 30,$apikey_header = NULL) {
		$arr_headers = array(
			"cache-control: no-cache",
			"content-type: application/x-www-form-urlencoded"
		);
		if ( !is_null($apikey_header) ){
			array_push($arr_headers,"X-API-KEY:  $apikey_header");
		}
		$curl = curl_init();
		curl_setopt_array($curl, array(
			CURLOPT_URL => $url,
			CURLOPT_RETURNTRANSFER => true,
			CURLOPT_ENCODING => "",
			CURLOPT_MAXREDIRS => 10,
			CURLOPT_TIMEOUT => $timeout,
			CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
			CURLOPT_CUSTOMREQUEST => $type,
			CURLOPT_POSTFIELDS => $params,
			CURLOPT_HTTPHEADER => $arr_headers,
		));

		$response = curl_exec($curl);
		$err = curl_error($curl);
		curl_close($curl);

		if ($err) {
			return json_encode(array('error' => true));
		} else {
			return $response;
		}
	}

	/*
	  /// devolver un Array con las URL de los documentos (el index del array se corresponde con cada doc_version)
	  public static function docUrls($doc_id) {
		$a_url = [];
		if ($doc_id > 0) {
		  $doc = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento', array($doc_id), 'selectOne');
		  if (!empty($doc)) {
			if($doc->estado_doc != 'N') {
			  for($dv = 0; $dv <= $doc->doc_version; $dv++) {
				$verspath = ($dv > 0) ? str_pad($dv, 3, '0', STR_PAD_LEFT) . '/' : '';
				$rootpath = env('PATH_DOCUMENTOS_IMPERIUM') . '/' . $doc->doc_path . $verspath;
				
				$f_url = NULL;
				if (is_dir($rootpath)) {
				  $fn = NULL;
				  $pattern = $doc->preffix . '*.pdf';
				  $files = glob( $rootpath . $pattern );
				  foreach ($files as $f => $file) {
					$extn = strtolower(pathinfo($file, PATHINFO_EXTENSION));
					if ($extn == 'pdf') {
					  $fn = basename($file);
					}
				  }
				  if ($fn != NULL) {
					$f_url = env('RUTA_DOCUMENTOS_IMPERIUM') . '/' . $doc->doc_path . $verspath . $fn;
				  }
				}

				$a_url[] = $f_url;
		
			  }
			}
		  }
		}

		return $a_url;
	  }


	  // dado un DOC_ID devuelve la URL del documento, incluyendo búsqueda replicada 
	  public static function getDocUrl($doc_id, $doc_version = NULL) {
		$f_url = NULL;
		$fn = NULL;

		if ($doc_id > 0) {

		  // version solicitada
		  $dv = ($doc_version == NULL) ? 0 : $doc_version;

		  
		 
		  
		  $verspath = '';

		  // evaluamos según versiones existentes del documento y estado //
		  $doc = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento', array($doc_id), 'selectOne');
		  $docpath = $doc->doc_path;
		
		  if ($doc->doc_version == 0) {
			// por si tiene replicado
			if($doc->replicated_doc_id > 0) {
			  $replicated = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento', array(NULL, NULL, NULL, NULL, $doc_id), 'selectOne');
			  $doc = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento', array($replicated->doc_id), 'selectOne');
			  $docpath = $doc->doc_path;
			}        
		  }
		  else {
			// documento tiene reemplazos
			if ($dv == 0) {
			  // solicito la versión 0, depende del estado
			  if ($doc->estado_doc == 'V') {
				// si esta verificado entonces la encuentro en la carpeta 0
				$verspath = '000/';
			  }
			}
			else {
			  // solicito una versión de reemplazo, se encuentra en la carpeta de la versión
			  $verspath = str_pad($dv, 3, '0', STR_PAD_LEFT) . '/';
			}
		  }

		  if (!empty($doc)) {

			$rootpath = env('PATH_DOCUMENTOS_IMPERIUM') . '/' . $docpath . $verspath;

			if (is_dir($rootpath)) {
			  $pattern = $doc->preffix . '*.pdf';
			  $files = glob( $rootpath . $pattern );
			  foreach ($files as $f => $file) {
				$extn = strtolower(pathinfo($file, PATHINFO_EXTENSION));
				if ($extn == 'pdf') {
				  $fn = basename($file);
				}
			  }
			  if ($fn != NULL) {
				$f_url = env('RUTA_DOCUMENTOS_IMPERIUM') . '/' . $docpath . $verspath . $fn;
			  }
			}
		  }
		}
		return $f_url;

	  }
	*/

	public static function getDocUrl($doc_id, $doc_version = NULL) {
		$f_url = NULL;
		$fn = NULL;

		if ($doc_id > 0) {

			// version solicitada
			$dv = ($doc_version == NULL) ? 0 : $doc_version;


			/*if ($doc_version == 0) {
				$doc = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento', array($doc_id), 'selectOne');
				if($doc->replicated_doc_id > 0) {
				$replicated = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento', array(NULL, NULL, NULL, NULL, $doc_id), 'selectOne');
				$doc = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento', array($replicated->doc_id), 'selectOne');
				}
			}
			else {
				$doc = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento_Reemplazo', array($doc_id, $doc_version), 'selectOne');
				$verspath = str_pad($doc_version, 3, '0', STR_PAD_LEFT) . '/';
			}*/

			$verspath = '';

			// evaluamos según versiones existentes del documento y estado //
			$doc = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento', array($doc_id), 'selectOne');
			$docpath = $doc->doc_path;

			if ($doc->doc_version == 0) {
				// por si tiene replicado
				if ($doc->replicated_doc_id > 0) {
					$replicated = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento', array(NULL, NULL, NULL, NULL, $doc_id), 'selectOne');
					$doc = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento', array($replicated->doc_id), 'selectOne');
					$docpath = $doc->doc_path;
				}
			} else {
				// documento tiene reemplazos
				if ($dv == 0) {
					// solicito la versión 0, depende del estado
					if ($doc->estado_doc == 'V') {
						// si esta verificado entonces la encuentro en la carpeta 0
						$verspath = '000/';
					}
				} else {
					// solicito una versión de reemplazo, se encuentra en la carpeta de la versión
					$verspath = str_pad($dv, 3, '0', STR_PAD_LEFT) . '/';
				}
			}

			if (!empty($doc)) {

				$rootpath = env('PATH_DOCUMENTOS_IMPERIUM') . '/' . $docpath . $verspath;

				if (is_dir($rootpath)) {
					$pattern = $doc->preffix . '*.pdf';
					$files = glob($rootpath . $pattern);
					foreach ($files as $f => $file) {
						$extn = strtolower(pathinfo($file, PATHINFO_EXTENSION));
						if ($extn == 'pdf') {
							$fn = basename($file);
						}
					}

					if ($fn == NULL) {
						$pattern = $doc->preffix . '*.PDF';
						$files = glob($rootpath . $pattern);
						foreach ($files as $f => $file) {
							$extn = pathinfo($file, PATHINFO_EXTENSION);
							if ($extn == 'PDF') {
								$fn = basename($file);
							}
						}
					}

					if ($fn != NULL) {
						$f_url = env('RUTA_DOCUMENTOS_IMPERIUM') . '/' . $docpath . $verspath . $fn;
					}
				}
			}
		}
		return $f_url;

	}


	//// utiliza el path según la última versión del documento
	public static function getDocUrlLast($doc_id) {
		$f_url = NULL;
		$fn = NULL;


		if ($doc_id > 0) {
			$doc = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento', array($doc_id), 'selectOne');

			if (!empty($doc)) {

				// si tiene una version mayor a la 0, voy a buscar a esa carpeta sino al root
				$verspath = ($doc->doc_version > 0) ? str_pad($doc->doc_version, 3, '0', STR_PAD_LEFT) . '/' : '';

				$rootpath = env('PATH_DOCUMENTOS_IMPERIUM') . '/' . $doc->doc_path . $verspath;

				if (is_dir($rootpath)) {
					$pattern = $doc->preffix . '*.pdf';
					$files = glob($rootpath . $pattern);
					foreach ($files as $f => $file) {
						$extn = strtolower(pathinfo($file, PATHINFO_EXTENSION));
						if ($extn == 'pdf') {
							$fn = basename($file);
						}
					}
					if ($fn != NULL) {
						$f_url = env('RUTA_DOCUMENTOS_IMPERIUM') . '/' . $doc->doc_path . $verspath . $fn;
					}
				}
			}

		}
		return $f_url;

	}

	/// devolver un Array con las URL de los documentos (el index del array se corresponde con cada doc_version)
	public static function docUrls($doc_id) {
		$a_url = [];
		if ($doc_id > 0) {
			$doc = SQLConnection::backendStoreProcedure('Imperium_Datos_Documento', array($doc_id), 'selectOne');
			if (!empty($doc)) {
				if ($doc->estado_doc != 'N') {
					for ($dv = 0; $dv <= $doc->doc_version; $dv++) {
						$verspath = ($dv > 0) ? str_pad($dv, 3, '0', STR_PAD_LEFT) . '/' : '';
						$rootpath = env('PATH_DOCUMENTOS_IMPERIUM') . '/' . $doc->doc_path . $verspath;

						$f_url = NULL;
						if (is_dir($rootpath)) {
							$fn = NULL;
							$pattern = $doc->preffix . '*.pdf';
							$files = glob($rootpath . $pattern);
							foreach ($files as $f => $file) {
								$extn = strtolower(pathinfo($file, PATHINFO_EXTENSION));
								if ($extn == 'pdf') {
									$fn = basename($file);
								}
							}
							if ($fn != NULL) {
								$f_url = env('RUTA_DOCUMENTOS_IMPERIUM') . '/' . $doc->doc_path . $verspath . $fn;
							}
						}

						$a_url[] = $f_url;

					}
				}
			}
		}
		return $a_url;
	}


	//==============================================  CLAUDIO  =======================================================//

	/*
	  FUNCION AUXILIAR PARA EXTRAER CONTENIDO DE UN STORE
	  REQUIERE: 
	  $resultado = 'Llamada normal con sus parametros' 
	$buscar = 'Nombre del indice a extraer en formato String'
	
	RESULTADO:
	sin resultados -> no se encontro indice.
	NULL -> store null.
	  */
	public static function filtro_claudio($resultado, $buscar) {
		if ($resultado !== null) {
			foreach ($resultado as $key) {
				return $key->$buscar;
			}
			return 'sin resultado';
		}
		return 'NULL';
	}


	/*
	FUNCION PARA MOSTRAR TODO EL CONTENIDO OBTENIDO DE UN STORE

	REQUIERE: 
	$resultado = 'Llamada normal con sus parametros'
	*/
	public static function contenido_store($resultado) {
		return var_dump($resultado);
	}

	/* FUNCION QUE DEVUELVE UNA LISTA DE LOS CONTENIDOS DEL JSON  , PARAMETROS: 1-array de json 2-nombre del valor en el objeto(clave) */
	public static function borrar_datos_repetidos($objeto, $clave) {
		$valores_lista = [];
		foreach ($objeto as $elem) {
			if (in_array($elem->{$clave}, $valores_lista) == FALSE) {
				array_push($valores_lista, $elem->{$clave});
			}
		}
		return $valores_lista;
	}
	// FUNCION QUE VALIDA DATA, LLEVA DOS PARAMETROS: 1-La Expression Regular que establece un patron con la data 2- la informacion que va a ser validada
	public static function validar_data($expReg,$data){
		return (preg_match($expReg,$data) == 1);
	}

	// FUNCIÓN QUE VALIDA SI ES ENTERO (caso de id usuario)
	// Requiere un parámetro que puede ser string o int.
	public static function validar_entero($data) {
		return is_int(intval($data));
	}

	public static function tieneCaracterRaroBase($cadena) {
		return (preg_match('/[>#<=!*¿@?}¡{]{1,}/', $cadena) == 1);
	}

	// FUNCION GENERICA ENCARGADA DE VALIDAR LOS DATOS
	// PARAMETROS : 1- dato a validar 2- tipo de validacion 3- indicador de si el dato es necesario o no
	// RESPUESTA : valor booleano
	public static function validacionesGenerica($valor, $tipo, $unrequired = 0) {
		//------
		switch ($tipo) {
			case 'numero':
				$expReg = '/^[0-9]+$/';
				break;
			case 'nombre':
				$expReg = '/^[^0-9]+$/';
				break;
			case 'cuit':
				$expReg = '/^[123]\d\d{8}\d{1}$/';
				break;
			case 'taxid':
				$expReg = '/^[0-9A-Z]+$/';
				break;
			case 'codigo_postal':
				$expReg = '/^\d{4,10}$/';
				break;
			case 'email':
				$expReg = '/^[a-z0-9!#$%&\'*+\/\=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/\=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/';
				break;
			case 'telefono':
				$expReg = '/^[+]?\d{8,}$/';
				break;
			case 'razon_social':
				$expReg = '/^[0-9A-Za-z-\.& ÑñÁáÉeÍíÓóÚú]+$/';
				break;
			case 'web':
				$expReg = '/^(https?:\/\/)?(www\.)[-a-zA-Z0-9@:%._\+~#\=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&\/\/\=]*)|(https?:\/\/)?(www\.)?(?!ww)[-a-zA-Z0-9@:%._\+~#\=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&\/\/\=]*)$/';
				break;
			case 'piso':
				$expReg = '/^[A-Za-z0-9]{1,2}$/';
				break;
			case 'dpto':
				$expReg = '/^[A-Za-z0-9]{1,2}$/';
				break;
			case 'calle':
				return (!self::tieneCaracterRaroBase($valor));
				break;
			case 'localidad':
				$expReg = '/^[0-9A-Z-\. ]+$/';
				break;
			case 'country_code':
				$expReg = '/^[A-Z]{2}$/';
				break;
			case 'identificador':
				$expReg = '/^[A-Z\s]{2,8}$/';
				break;
			case 'fecha':
				$expReg = '/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/';
				break;
			case 'password':
				return (!self::tieneCaracterRaroBase($valor));
				break;
			case 'login':
				$expReg = '/^[A-Za-z0-9_\-\.\@\$\#]+$/';
				break;
			default:
				break;
		}
		//-----
		if ($unrequired) {
			return (preg_match($expReg, $valor) == 1 || empty($valor));
		} else {
			return (preg_match($expReg, $valor) == 1);
		}
	}

	public static function esElMismoNombre($n1, $n2) {
		$n1 = explode(' ', trim(strtoupper($n1)));
		$n2 = explode(' ', trim(strtoupper($n2)));

		if (count($n1) <= count($n2)) {
			$cont = 0;
			foreach ($n1 as $e) {
				foreach ($n2 as $a) {
					if ($e == $a) {
						$cont++;
					}
				}
			}
			return $cont == count($n1);
		}
		return false;
	}

	//===================================================================================================================//

	//--------------------------------------------------------  SISTEMAS DE NOTIFICACION POR MAIL APIS  ---------------------------------------------------------------//
	//Método para el envio de emails errores
	public static function enviarMail_errores_api($content = '') {
		Mailer::from("no-reply@fidelitas.com.ar");
		Mailer::to(env('DESTINATARIO'));
		// echo("MISC 1760");
		// dd(env('DESTINATARIO'));

		//Mailer::bcc(env('COPIA'));
		Mailer::text($content, "API STATUS");
		return Mailer::send();
	}
	//--------------------------------------------------------  FIN SISTEMAS DE NOTIFICACION POR MAIL  ----------------------------------------------------------------//



	//==============================================  DIEGO  =======================================================//




	// FUNCION ENCARGADA DE CALCULAR LA INTEGRIDAD DE LOS ESTADOS DE CARGA, RECHAZO Y VERIFICACION DE DOCUMENTOS
	// PARAMETROS :     1- doc (objeto) 
	//                  2- accion_doc (int) (VERIFICA-RECHAZA)
	//                  3- integ_carga (int)
	//                  4- integ_verif (int)
	//                  5- integ_rech (int)
	//                  5- undo (int ? 1 : 0)
	public static function integridadDocStore($doc, $accion_doc, $integ_carga, $integ_verif, $integ_rech, $undo = 0) {
		$contraparte = $doc->contraparte;
		$cliente = $doc->cliente;
		$gestion = $doc->gestion;
		$informe = $doc->informe;
		return self::recalcularIntegridadGestion($contraparte, $gestion);
		//
		$docs = SQLConnection::backendStoreProcedure('LN_contrapartes_', array('DOCUMENTOS_GESTION_ACTIVA', $contraparte, null, null, null, null, null, null, null, null, null, null, null, null, null));
		//$docs = DB::select('EXEC dbo.LN_contrapartes_ ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?', array('DOCUMENTOS_GESTION_ACTIVA', $contraparte, null, null, null, null, null, null, null, null, null, null, null, null, null));
		$report_data = SQLConnection::backendStoreProcedure('LN_demo_', array('SELECCIONAR_INFORME', $contraparte, $cliente, null, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, $informe, $gestion), 'selectOne');
		// $producto = SQLConnection::backendStoreProcedure('LN_demo_', array('reports', $contraparte, $cliente), 'selectOne');
		$producto = $report_data->producto;
		foreach ($docs as $key => $doc) {
			if ($doc->aplica != '1') {
				unset($docs[$key]);
			}
		}
		$tot_doc = count($docs);
		// SI VIENE DE DESHACER VERIFICACION O RECHAZO ENTRA EN EL PRIMER BLOQUE, DONDE CALCULA TODAS LAS INTEGRIDADES. 
		// SINO ENTRA EN EL SEGUNDO BLOQUE, DONDE SOLO CALCULA LA INTEGRIDAD DE VERIFICACION SI VERIFICA EL DOCUMENTO O INTEGRIDAD DE RECHAZO SI RECHAZA EL DOCUMENTO. SI HAY UN ERROR EN LA INTEGRIDAD DE CARGA LO CORRIGE.
		if ($undo == 1) {
			$integ_carga = 0;
			$integ_rech = 0;
			$integ_verif = 0;
			$docs_in = 0;
			$doc_rec = 0;
			$doc_ver = 0;
			foreach ($docs as $key => $doci) {
				if ($doci->estado_doc == 'I' || $doci->estado_doc == 'V' || $doci->estado_doc == 'R') {
					$docs_in++;
				}
				if ($doci->estado_doc == 'R' && $doci->aplica == '1') {
					$doc_rec++;
				} elseif ($doci->estado_doc == 'V' && $doci->aplica == '1') {
					$doc_ver++;
				}
			}
			//
			if ($tot_doc == 0) {
				$integ_carga = 0;
				$integ_rech = 0;
				$integ_verif = 0;
			} else {
				$porcentaje_docs_carga = number_format(floor((100 * $docs_in) / $tot_doc), 0);
				$integ_carga = $porcentaje_docs_carga;
				$porcentaje_docs_rechazados = number_format(floor((100 * $doc_rec) / $tot_doc), 0);
				$integ_rech = ($porcentaje_docs_rechazados > 100) ? 100 : $porcentaje_docs_rechazados;
				$porcentaje_docs_verificados = number_format(floor((100 * $doc_ver) / $tot_doc), 0);
				$integ_verif = ($porcentaje_docs_verificados > 100) ? 100 : $porcentaje_docs_verificados;
			}
			$estado_doc_ok = 0;
			//
			if ($accion_doc == 3) {
				$estado_doc_ok = (isset($porcentaje_docs_verificados) && $porcentaje_docs_verificados == 100 && intval($integ_carga) == 100) ? 1 : 0;
			}
			$temp = SQLConnection::backendStoreProcedure('LN_demo_', array('UPDATE', $contraparte, $cliente, $producto, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, $informe, $gestion, null, null, null, null, $integ_carga, $integ_verif, $integ_rech, $estado_doc_ok), 'selectOne');

		} else {
			$docs_in = 0;
			if (intval($integ_carga) == 0 || intval($integ_carga) > 100) {
				foreach ($docs as $key => $doci) {
					if ($doci->estado_doc == 'I' || $doci->estado_doc == 'V') {
						$docs_in++;
					}
				}
				if ($tot_doc == 0) {
					$integ_carga = 0;
				} else {
					$porcentaje_docs_carga = number_format(floor(((100 * ($docs_in)) / $tot_doc)), 0);
					$integ_carga = $porcentaje_docs_carga;
				}

			}
			//
			if ($accion_doc == 2) {
				// PORCENTAJE RECHAZADA
				$doc_rec = 0;
				if (count($docs) > 0) {
					foreach ($docs as $clave => $doci) {
						if ($doci->estado_doc == 'R' && $doci->aplica == '1') {
							$doc_rec++;
						} else if ($doci->estado_doc == 'I' || $doci->estado_doc == 'V') {
							$docs_in++;
						}
					}
				}
				//
				if ($tot_doc == 0) {
					$integ_carga = 0;
					$porcentaje_docs_rechazados = 0;
				} else {
					$porcentaje_docs_carga = number_format(floor(((100 * ($docs_in)) / $tot_doc)), 0);
					$integ_carga = $porcentaje_docs_carga;
					$porcentaje_docs_rechazados = number_format(floor(((100 * ($doc_rec + 1)) / $tot_doc)), 0);
					$porcentaje_docs_rechazados = ($porcentaje_docs_rechazados > 100) ? 100 : $porcentaje_docs_rechazados;
				}

				$estado_doc_ok = ($porcentaje_docs_rechazados != 0) ? 0 : 1;
				$integridad_rech = SQLConnection::backendStoreProcedure('LN_demo_', array('UPDATE', $contraparte, $cliente, $producto, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, $informe, $gestion, null, null, null, null, $integ_carga, $integ_verif, $porcentaje_docs_rechazados), 'selectOne');
			} elseif ($accion_doc == 1) {
				// PORCENTAJE VERIFICADA
				$doc_ver = 0;
				//
				if (count($docs) > 0) {
					foreach ($docs as $key => $doci) {
						if ($doci->estado_doc == 'V' && $doci->aplica == '1') {
							$doc_ver++;
						}
					}
				}
				if ($tot_doc == 0) {
					$porcentaje_docs_verificados = 0;
				} else {
					$porcentaje_docs_verificados = 100 * ($doc_ver);
					$porcentaje_docs_verificados = $porcentaje_docs_verificados / $tot_doc;
					$porcentaje_docs_verificados = floor($porcentaje_docs_verificados);
					$porcentaje_docs_verificados = number_format($porcentaje_docs_verificados, 0);
				}
				// $porcentaje_docs_verificados =  number_format(floor(((100*($doc_ver+1))/$tot_doc)),0);
				if ($porcentaje_docs_verificados == 100 && intval($integ_carga) < 100) {
					$docs_in = 0;
					foreach ($docs as $key => $doci) {
						if ($doci->estado_doc == 'I' || $doci->estado_doc == 'V' || $doci->estado_doc == 'R') {
							$docs_in++;
						}
					}
					if ($tot_doc == 0) {
						$integ_carga = 0;
					} else {
						$porcentaje_docs_carga = number_format(floor(((100 * ($docs_in)) / $tot_doc)), 0);
						$integ_carga = $porcentaje_docs_carga;
					}
				}
				$porcentaje_docs_verificados = ($porcentaje_docs_verificados > 100) ? 100 : $porcentaje_docs_verificados;
				$estado_doc_ok = ($porcentaje_docs_verificados == 100 && intval($integ_carga) == 100) ? 1 : 0;
				$integridad_ver = SQLConnection::backendStoreProcedure('LN_demo_', array('UPDATE', $contraparte, $cliente, $producto, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, $informe, $gestion, null, null, null, null, $integ_carga, $porcentaje_docs_verificados, $integ_rech, $estado_doc_ok), 'selectOne');
			}
		}
	}

	// FUNCION QUE AGREGA DOMICILIOS CONOCIDOS A LISTA DE DOMICILIOS.
	public static function addDomicilio($taxid, $new_direccion, $new_altura = null, $piso = null, $depto = null, $new_localidad = null, $new_provincia = null, $cod_postal = null, $facon = 0, $google = 0, $geolat = null, $geolong = null, $new_pai_nombre = null) {
		//
		if ($google == 1) {
			$direccion = json_decode($new_direccion);
			// DEFINE LAS VARIABLES CON LOS DATOS TRAIDOS DE GOOGLE MAPS
			foreach ($direccion as $dir) {
				if ($dir->types[0] == 'route') {
					$new_direccion = Misc::reemplazarAcentosPorEquivalentes($dir->short_name);
				} elseif ($dir->types[0] == 'street_number') {
					$new_altura = $dir->long_name;
				} elseif ($dir->types[0] == 'administrative_area_level_1') {
					if ($dir->short_name == 'CABA') {
						// SI ES DE CABA DEFINE LOCALIDAD Y PROVINCIA COMO TAL, SI NO SOLO PROIVNCIA.
						$new_localidad = $dir->short_name;
						$new_provincia = $dir->short_name;
					} else {
						$new_provincia = $dir->long_name;
					}
				} elseif ($dir->types[0] == 'postal_code') {
					if (count_chars($dir->long_name) > 4) {
						// OBTIENE SOLO LOS NÚMEROS DEL CÓDIGO POSTAL, FORMATO VIEJO
						preg_match_all('!\d+!', $dir->long_name, $numeros);
						$cod_postal = $numeros[0][0];
					} else {
						$cod_postal = $dir->long_name;
					}
				} elseif ($dir->types[0] == 'administrative_area_level_2' && $new_localidad == null) {
					// SI NO SE DEFINIÓ ANTES LOCALIDAD SE DEFINE ACÁ
					$new_localidad = $dir->short_name;
				} elseif ($dir->types[0] == 'country' && $new_pai_nombre == null) {
					$new_pai_nombre = $dir->long_name;
				}

			}
		}


		$domicilios = SQLConnection::obtenerDomicilios($taxid); // STORE PARA DOMICILIOS
		// $dir_exist = 0;
		$dir_updt = 0;
		$new_domicilio = strtoupper($new_direccion . ' ' . $new_altura);

		foreach ($domicilios as $domi) {
			if (preg_match(('/' . $domi->domicilio . '/'), $new_domicilio)) {
				// COMPARA SI EXISTE LA DIRECCIÓN EN LA LISTA
				// $dir_exist ++;
				if (($domi->geo_long == null || $domi->geo_lat == null) && $google == 1) {
					// SI FALTAN DATOS GEO SE DEFINEN VARIABLES PARA ACTUALIZAR
					$dir_updt++;
					$idDomicilio = $domi->id_domicilio;
				}
			}
			// if ($domi->tipo_domicilio == 'M'){
			//     $direccion = $domi->domicilio;
			// }
		}
		//
		if ($facon == 1) {
			// SI LA DIRECCIÓN BUSCADA NO EXISTE EN LA LISTA LA INSERTA
			$flds = SQLConnection::backendStoreProcedure('facon_domicilios', array('INSERTAR', $taxid, $new_direccion, $new_altura, $piso, $depto, $cod_postal, $new_localidad, $new_provincia, $new_domicilio, $geolat, $geolong, Session::get('usuario')->user_id, null, $new_pai_nombre), 'select');
			return 'insert ok';
		} else {
			return 'sin guardar';
		}
		// elseif ($dir_updt != 0) {
		//     // SI EXISTE LA DIRECCIÓN BUSCADA EN LA LISTA, Y NO TIENE DATOS GEO, SE ACTUALIZA
		//     $flds = SQLConnection::backendStoreProcedure('facon_domicilios', array('ACTUALIZAR', $taxid, $new_direccion, $new_altura, $piso, $depto, $cod_postal, $new_localidad, $new_provincia, $new_domicilio,$geolat,$geolong,Session::get('usuario')->user_id,$idDomicilio), 'select');
		//     return $flds;
		// }
	}

	/**
	 * Funcion que devuelve los estados
	 * de los informes y sus nombres 
	 * @param string|null codigo del estado
	 * @return array|null
	 */
	public static function NombreEstadosInforme($estado = NULL) {
		$nombre_estados = [
			'N' => 'Anulado',
			'K' => 'Aprobado',
			'P' => 'En gestión',
			'E' => 'En proceso',
			'W' => 'En espera',
			'A' => 'No calificado',
			'I' => 'Ingresado',
			'X' => 'Carga Comercial',
			'T' => 'Respondido',
			'M' => 'A Completar',
			'F' => 'Finalizado',
			'R' => 'Observado',
			'C' => 'Rechazado'
		];
		//
		if (is_null($estado)) {
			return $nombre_estados;
		} else {
			return $nombre_estados[$estado] ?? NULL;
		}
	}

	/**
	 * FUNCION QUE DEVUELVE SI EL INFORME DE INQUIRO EXISTE O NO, Y EN CASO DE SI SU RUTA
	 * @access public
	 * @static
	 * @param string|int id de cliente
	 * @param string|int id de contraparte
	 * @param string|int id de gestion
	 * @return object objeto que tiene la url del informe y si existe
	 * */
	public static function obtenerInforme($cliente, $contraparte, $gestion) {
		$informe_path = env('PATH_DOCUMENTOS') . '/dossier/' . $contraparte . '.pdf';
		$informe_url = env('RUTA_DOCUMENTOS') . '/dossier/' . $contraparte . '.pdf';
		//
		$informe_path_alternativo = env('PATH_DOSSIER') . '/' . $cliente . '/' . $contraparte . '/' . $gestion . '/' . $gestion . '.pdf';
		$informe_url__alternativo = env('RUTA_DOSSIER') . '/' . $cliente . '/' . $contraparte . '/' . $gestion . '/' . $gestion . '.pdf';
		//
		if (file_exists($informe_path)) {
			return (object) ['informe_existe' => true, 'informe_url' => $informe_url];
		} elseif (file_exists($informe_path_alternativo)) {
			return (object) ['informe_existe' => true, 'informe_url' => $informe_url__alternativo];
		} else {
			return (object) ['informe_existe' => false, 'informe_url' => NULL];
		}
	}

	/**
	 * FUNCION QUE DEVUELVE LAS EVIDENCIAS DEL INFORME DE INQUIRO
	 * @access public
	 * @static
	 * */
	public static function obtenerEvidenciasInformeOrg($cliente, $contraparte, $gestion) {
		$path_evidencias = env('PATH_DOCUMENTOS_IV') . DIRECTORY_SEPARATOR . $cliente . DIRECTORY_SEPARATOR . $contraparte . DIRECTORY_SEPARATOR . $gestion . DIRECTORY_SEPARATOR . 'evidencias' . DIRECTORY_SEPARATOR . '*';
		$archivos_evidencias = glob($path_evidencias);
		$name = NULL;
		$file = NULL;
		//
		$evidencias = [];
		//
		if (!empty($archivos_evidencias)) {
			foreach ($archivos_evidencias as $archivo) {
				$name = basename($archivo);
				$file = str_replace(env('PATH_DOCUMENTOS_IV'), env('RUTA_DOCUMENTOS_IV'), $archivo);
				if ($name == 'antecedentes_policiales.png') {
					// antecedentes policiales
					$evidencias['Antecedentes Policiales'] = ['tipo' => 'img', 'file' => $file];
				} elseif ($name == 'inpec.png') {
					// INPEC
					$evidencias['INPEC'] = ['tipo' => 'img', 'file' => $file];
				} elseif ($name == 'juicios.pdf') {
					// JUICIOS
					$evidencias['Juicios'] = ['tipo' => 'pdf', 'file' => $file];
				} elseif ($name == 'proc.pdf') {
					// Procuraduria
					$evidencias['Procuraduria'] = ['tipo' => 'pdf', 'file' => $file];
				} elseif ($name == 'ced_ciu.pdf') {
					// Cedula de ciudadania
					$evidencias['Cedula de ciudadania'] = ['tipo' => 'pdf', 'file' => $file];
				} elseif ($name == 'consentimiento.pdf') {
					// Consentimiento
					$evidencias['Consentimiento'] = ['tipo' => 'pdf', 'file' => $file];
				}
			}
		}
		//
		return $evidencias;
	}

	/**
	 * FUNCION QUE DEVUELVE LAS EVIDENCIAS DEL INFORME DE INQUIRO
	 * @access public
	 * @static
	 * */
	public static function obtenerEvidenciasInforme($cliente, $contraparte, $gestion) {
		$docs = SQLConnection::backendStoreProcedure('LN_contrapartes_', array('DOCUMENTOS_GESTION_ACTIVA', $contraparte, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
		$evidencias = [];
		//
		foreach ($docs as $doc) {
			if ($doc->es_evidencia && $doc->es_dni) {
				$files_dni = [];
				$path_dni_1 = env('PATH_DOCUMENTOS_IV') . DIRECTORY_SEPARATOR . $cliente . DIRECTORY_SEPARATOR . $contraparte . DIRECTORY_SEPARATOR . $gestion . DIRECTORY_SEPARATOR . 'evidencias' . DIRECTORY_SEPARATOR . '1_dni.png';
				$path_dni_2 = env('PATH_DOCUMENTOS_IV') . DIRECTORY_SEPARATOR . $cliente . DIRECTORY_SEPARATOR . $contraparte . DIRECTORY_SEPARATOR . $gestion . DIRECTORY_SEPARATOR . 'evidencias' . DIRECTORY_SEPARATOR . '2_dni.png';
				if (file_exists($path_dni_1)) {
					$files_dni[] = str_replace(env('PATH_DOCUMENTOS_IV'), env('RUTA_DOCUMENTOS_IV'), $path_dni_1);
				}
				if (file_exists($path_dni_2)) {
					$files_dni[] = str_replace(env('PATH_DOCUMENTOS_IV'), env('RUTA_DOCUMENTOS_IV'), $path_dni_2);
				}
				//
				if (!empty($files_dni)) {
					$evidencias[$doc->nombre_tipo_doc] = ['tipo' => 'img', 'empty' => false, 'file' => $files_dni];
				} else {
					$evidencias[$doc->nombre_tipo_doc] = ['tipo' => 'img', 'empty' => true];
				}
			} elseif ($doc->es_evidencia) {
				$path_evidencia = env('PATH_DOCUMENTOS_IV') . DIRECTORY_SEPARATOR . $cliente . DIRECTORY_SEPARATOR . $contraparte . DIRECTORY_SEPARATOR . $gestion . DIRECTORY_SEPARATOR . 'evidencias' . DIRECTORY_SEPARATOR . $doc->doc_id . '.pdf';
				//
				if (file_exists($path_evidencia)) {
					$file = str_replace(env('PATH_DOCUMENTOS_IV'), env('RUTA_DOCUMENTOS_IV'), $path_evidencia);
					$evidencias[$doc->nombre_tipo_doc] = ['tipo' => 'pdf', 'empty' => false, 'file' => $file];
				} else {
					$evidencias[$doc->nombre_tipo_doc] = ['tipo' => 'pdf', 'empty' => true];
				}
			}
		}
		//
		return $evidencias;
	}

	/**
	 * Funcion que devuelve los
	 * archivos cargados para un
	 * documento
	 * @access public
	 * @param string|int|null doc_id del caso
	 * @param object|null objeto que tiene los datos del documento
	 * @return array
	 */
	/* public static function docFiles($doc_id=NULL,object $doc=NULL){
	  if ( !$doc_id && !$doc ){
		return [];
	  } else {
		if ( !$doc ){
		  $doc = SQLConnection::backendStoreProcedure('LN_docs_', array('select', $doc_id, null, null, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, null, NULL), 'selectOne');
		}
		//
		if ( $doc->es_evidencia ){

		}
	  }
	} */

	/**
	 * Funcion que calcula el TAT 
	 * en minutos y bloques de tiempo
	 * @param string|int la contraparte del caso
	 * @param string|int la gestion del caso
	 * @return array
	 */
	public static function calcularTATORG($contraparte, $gestion) {
		$contrap = SQLConnection::backendStoreProcedure('LN_contrapartes_', array('select', $contraparte, null, null, null, null, null, null, null, null, null, null, null, null, Session::get('usuario')->user_id), 'selectOne');
		$tatProd = SQLConnection::backendStoreProcedure('LN_TATime_', array('LISTBYID', $contraparte, $gestion, NULL, NULL));
		//
		$intervalos_trabajo = [];
		$cant_tat = count($tatProd);
		$i = 0;
		$ini_ciclo = false;
		$fecha_ini = null;
		$fecha_fin = null;
		$interval = null;
		//
		$bloque = 0;
		//
		while ($i < $cant_tat) {
			if (!$ini_ciclo && $tatProd[$i]->accion == 'START_IV') {
				$ini_ciclo = true;
				$fecha_ini = new DateTime($tatProd[$i]->created);
				//
				$date = $fecha_ini->format("H");
			}
			//
			if ($ini_ciclo && ($tatProd[$i]->accion == 'OBS_IV' || $tatProd[$i]->accion == 'CLOSE_PUB_IV_REPORT' || $tatProd[$i]->accion == 'REJECT_IV')) {
				$ini_ciclo = false;
				$fecha_fin = new DateTime($tatProd[$i]->created);
				//
				$date2 = $fecha_fin->format("H");
				if ($date >= 9 && $date2 <= 13) {
					$bloque = $bloque + 0.5;
				} elseif ($date >= 14 && $date2 <= 18) {
					$bloque = $bloque + 0.5;
				}
				//
				$interval = $fecha_ini->diff($fecha_fin);
				$intervalos_trabajo[] = $interval;
				//
				$fecha_ini = null;
				$fecha_fin = null;
				$interval = null;
			}
			//
			$i++;
		}
		// calculamos los minutos finales
		$resultado = new DateTime();
		$resultado->setTimestamp(0);
		$fecha_calculo_inicial = clone $resultado;
		//
		foreach ($intervalos_trabajo as $intervalo) {
			$resultado->add($intervalo);
		}
		//    
		$tatMin = $resultado->diff($fecha_calculo_inicial);
		$diasAMinutos = (($tatMin->d) * 24) * 60;
		$horasAMintos = (($tatMin->h) * 60);
		$minutosTotal = $diasAMinutos + $horasAMintos + $tatMin->i;
		//
		$resultadoTAT = array('minutos_totales' => $minutosTotal, 'bloque_jornada' => $bloque);
		return $resultadoTAT;
	}

	/**
	 * Funcion que calcula el TAT 
	 * en minutos y bloques de tiempo
	 * @param string|int la contraparte del caso
	 * @param string|int la gestion del caso
	 * @return void
	 */
	public static function calcularTAT($contraparte, $gestion) {
		$tatProd = SQLConnection::backendStoreProcedure('LN_TATime_', array('LISTBYID', $contraparte, $gestion, NULL, NULL));
		//
		$minutosTAT = 0;
		$bloquesTAT = 0.0;
		//
		$cant_tat = count($tatProd);
		// $i = 0;
		$ini_ciclo = false;
		$fecha_ini = null;
		$fecha_fin = null;
		//
		//while ( $i < $cant_tat ){
		for ($i = 0; $i < $cant_tat; $i++) {
			if (!$ini_ciclo && $tatProd[$i]->accion == 'START_IV') {
				// inicio ciclo productivo
				$ini_ciclo = true;
				$fecha_ini = new DateTime($tatProd[$i]->created);
			}
			//
			if ($ini_ciclo && ($tatProd[$i]->accion == 'OBS_IV' || $tatProd[$i]->accion == 'CLOSE_PUB_IV_REPORT' || $tatProd[$i]->accion == 'REJECT_IV' || $tatProd[$i]->accion == 'CANCEL_IV' || $tatProd[$i]->accion == 'GESTION_IV')) {
				// fin ciclo productivo
				$ini_ciclo = false;
				$fecha_fin = new DateTime($tatProd[$i]->created);
				//
				self::intervaloTAT($fecha_ini, $fecha_fin, $minutosTAT, $bloquesTAT);
				//
				$fecha_ini = null;
				$fecha_fin = null;
			}
			//
			// $i++;
		}
		//
		//$resultadoTAT = array('minutos_totales' => $minutosTAT,'bloque_jornada' => $bloquesTAT);
		SQLConnection::backendStoreProcedure('LN_TATime_', array('UPDBYCONTRA', $contraparte, $gestion, $minutosTAT, $bloquesTAT));
		//return $resultadoTAT;       
	}

	/**
	 * Funcion que calcula los
	 * tiempos TAT en un intervalo
	 * produccion de informe
	 * @access private
	 * @static
	 * @param DateTime fecha de inicio de periodo
	 * @param DateTime fecha de finalizacion de periodo
	 * @param int minutos totales
	 * @param float bloques totales
	 * @return void
	 */
	private static function intervaloTAT(DateTime $fecha_ini, DateTime $fecha_fin, int &$minutosTAT, float &$bloquesTAT) {
		$fecha_cal = clone $fecha_ini;
		$interval = $fecha_cal->diff($fecha_fin);
		$dia = new DateInterval('P1D');
		$dia_semana = NULL;
		//
		// $bloques_por_periodo = 0.0;
		$minutos_por_periodo = 0;
		$minutos_prod = 0;
		// calcula diferencia de dias
		while ($interval->d != 0) {
			$dia_semana = $fecha_cal->format('w'); // se calcula que no sea fin de semana
			if ($dia_semana && $dia_semana != '6' && !self::esFeriado($fecha_cal)) {
				// se le suma un dia
				$minutos_por_periodo += 1440;
				$minutos_prod += 480;
				// $bloques_por_periodo += 1.0; 
			}
			//
			$fecha_cal->add($dia);
			$interval = $fecha_cal->diff($fecha_fin);
		}
		// si son dias laborales se calculan las horas
		$dia_semana = $fecha_cal->format('w'); // se calcula que no sea fin de semana
		if ($dia_semana && $dia_semana != '6' && !self::esFeriado($fecha_cal)) {
			// calcula diferencia de horas
			$hora = new DateInterval('PT1H');
			$hora_dia = NULL;
			//
			while ($interval->h != 0) {
				$hora_dia = $fecha_cal->format('H');
				if (($hora_dia >= 9 && $hora_dia < 13) || ($hora_dia >= 14 && $hora_dia < 18)) {
					$minutos_prod += 60;
				}
				$minutos_por_periodo += 60;
				/* if ( $hora_dia == 9 || $hora_dia == 14 ){
																																		  $bloques_por_periodo += 0.5;
																																		} */
				//}
				//
				$fecha_cal->add($hora);
				$interval = $fecha_cal->diff($fecha_fin);
			}
			// si son horarios laborales se calculan los minutos
			$hora_dia = $fecha_cal->format('H');
			$cond_hora_dia = (($hora_dia >= 9 && $hora_dia < 13) || ($hora_dia >= 14 && $hora_dia < 18));
			//
			$minuto = new DateInterval('PT1M');
			// calcula diferencia de minutos
			while ($interval->i != 0) {
				$minutos_por_periodo += 1;
				if ($cond_hora_dia) {
					$minutos_prod += 1;
				}
				$fecha_cal->add($minuto);
				$interval = $fecha_cal->diff($fecha_fin);
			}
			// se le suma una jornada si la diferencia es solo de minutos
			/* if ( !$bloques_por_periodo ){
																										$bloques_por_periodo += 0.5;
																									  } */
			//}
		}
		// se le suma al total de tiempos
		$minutosTAT += $minutos_prod;
		$bloquesTAT += ($minutos_por_periodo / (1440));
	}

	/**
	 * Funcion que hace el calculo
	 * de TAT de la tarea
	 * @access public
	 * @static
	 * @param string|int el id de la contraparte
	 * @return void
	 */
	public static function calcularTATTarea($contraparte, $tarea) {
		$tatProd = SQLConnection::backendStoreProcedure('LN_TATime_', array('LISTTASKTIME', $contraparte, NULL, NULL, NULL, $tarea));
		//
		$minutos = 0;
		$cant_tat = count($tatProd);
		//
		$ini_ciclo = false;
		$fecha_ini = null;
		$fecha_fin = null;
		//
		for ($i = 0; $i < $cant_tat; $i++) {
			if (!$ini_ciclo && ($tatProd[$i]->accion == 'INICIAR_TAREA' || $tatProd[$i]->accion == 'CONTINUAR_TAREA')) {
				// inici ciclo 
				$ini_ciclo = true;
				$fecha_ini = new DateTime($tatProd[$i]->created);
			} elseif ($ini_ciclo && ($tatProd[$i]->accion == 'PAUSAR_TAREA' || $tatProd[$i]->accion == 'FIN_TAREA' || $tatProd[$i]->accion == 'ANULAR_TAREA' || $tatProd[$i]->accion == 'ESPERA_TAREA')) {
				// fin ciclo
				$ini_ciclo = false;
				$fecha_fin = new DateTime($tatProd[$i]->created);
				// pasaje por referencia de minutos
				self::intervaloTATTarea($fecha_ini, $fecha_fin, $minutos);
				//
				$fecha_ini = null;
				$fecha_fin = null;
			}
		}
		// para que no se grabe 0 si es menos que un minuto
		/* if ($minutos == 0) {
			$minutos++;
		} */
		//
		SQLConnection::backendStoreProcedure('LN_TATime_', array('UPDBYTAREA', $contraparte, NULL, $minutos, NULL, $tarea));
	}

	/**
	 * Funcion que calcula los
	 * tiempos TAT en un intervalo
	 * produccion de informe
	 * @access private
	 * @static
	 * @param DateTime fecha de inicio de periodo
	 * @param DateTime fecha de finalizacion de periodo
	 * @param int minutos totales
	 * @return void
	 */
	private static function intervaloTATTarea(DateTime $fecha_ini, DateTime $fecha_fin, int &$minutosTAT) {
		$fecha_cal = clone $fecha_ini;
		$interval = $fecha_cal->diff($fecha_fin);
		$dia = new DateInterval('P1D');
		$dia_semana = NULL;
		$segundos_TAT = 0;
		// calcula diferencia de dias
		while ($interval->d != 0) {
			$dia_semana = $fecha_cal->format('w'); // se calcula que no sea fin de semana
			if ($dia_semana && $dia_semana != '6' && !self::esFeriado($fecha_cal)) {
				// se le suma un dia
				$minutosTAT += 480;
			}
			//
			$fecha_cal->add($dia);
			$interval = $fecha_cal->diff($fecha_fin);
		}
		// si son dias laborales se calculan las horas
		$dia_semana = $fecha_cal->format('w'); // se calcula que no sea fin de semana
		if ($dia_semana && $dia_semana != '6' && !self::esFeriado($fecha_cal)) {
			// calcula diferencia de horas
			$hora = new DateInterval('PT1H');
			$hora_dia = NULL;
			//
			while ($interval->h != 0) {
				// $hora_dia = $fecha_cal->format('H');
				//if (($hora_dia >= 9 && $hora_dia < 13) || ($hora_dia >= 14 && $hora_dia < 18)) {
				$minutosTAT += 60;
				// }
				//
				$fecha_cal->add($hora);
				$interval = $fecha_cal->diff($fecha_fin);
			}
			// si son horarios laborales se calculan los minutos
			// $hora_dia = $fecha_cal->format('H');
			//$cond_hora_dia = (($hora_dia >= 9 && $hora_dia < 13) || ($hora_dia >= 14 && $hora_dia < 18));
			//
			$minuto = new DateInterval('PT1M');
			// calcula diferencia de minutos
			while ($interval->i != 0) {
				//if ($cond_hora_dia) {
				$minutosTAT += 1;
				// }
				$fecha_cal->add($minuto);
				$interval = $fecha_cal->diff($fecha_fin);
			}
			$segundo = new DateInterval('PT1S');
			while ( $interval->s != 0 ){
				$segundos_TAT += 1;
				//
				$fecha_cal->add($segundo);
				$interval = $fecha_cal->diff($fecha_fin);
			}
			//
			if ( $segundos_TAT > 0 ){
				$minutosTAT += round(($segundos_TAT/60),2);
			}
		}
	}

	public static function esFeriado(DateTime $fecha): bool {
		$feriados = SQLConnection::backendStoreProcedure('LN_feriados', array('FERIADOS_INFORME', 'AR', NULL, NULL));
		$cant_feriados = count($feriados);
		$es_feriado = false;
		//-------------------------  
		$i = 0;
		while (!$es_feriado && $i < $cant_feriados) {
			$obj_dia_feriado = new DateTime($feriados[$i]->fecha_feriado);
			if ($fecha == $obj_dia_feriado) {
				$es_feriado = true;
			}
			$i++;
		}
		//
		return $es_feriado;
	}

	// ============================================== //
	// ================ OBTENER TEAM ================ //
	// ============================================== //

	/**
	 * Función que devuelve
	 * el team default de la
	 * familia, en caso que no haya
	 * team default devuelve NULL
	 * @access public
	 * @static
	 * @param string|int id de familia
	 * @return int|null el id de team default o NULL
	 */
	public static function obtenerTeamDefaultFamilia($familia) {
		/* $teams_familia = SQLConnection::backendStoreProcedure('LN_Teams_',array('LSTFAMILYTEAMS',Session::get('usuario')->user_id,null,null,null,null,null,null,null,null,null,null,$familia),'select');
		
			$team_default = ( isset($teams_familia[0]->id_team) ) ? $teams_familia[0]->id_team : NULL;
			if ( !empty($teams_familia) ){
				foreach( $teams_familia as $team ){
					if ( $team->isDefault == '1' && $team->activo == '1' ){
						$team_default = $team->id_team;
						break;
					}
				}
		} */
		$team_default = SQLConnection::backendStoreProcedure('LN_Teams_', array('DEFAULTTEAMFAMILIA', Session::get('usuario')->user_id, null, null, null, null, null, null, null, null, null, null, $familia), 'selectOne');
		return $team_default;
	}

	// ================================================================================== //
	// ============= CALCULO DE FECHA DE INICIO Y COMPROMEIDA DE UN INFORME ============= //
	// ================================================================================== //

	/**
	 * Funcion que devuelve las fechas del informe en base a la duracion
	 * de su modelo
	 * @access public
	 * @param string|null duracion del informe
	 * @return array
	 *
	 */
	public static function establecerFechasInforme($duracion_informe, $incio = NULL) {
		$fecha_inicio = self::obtenerFechaInicioInforme($incio); // calculamos la fecha de incio    
		$fecha_comprometida = self::obtenerFechaComprometidaInforme($duracion_informe, $fecha_inicio); // calculamos la fecha comprometida del informe

		$fecha_comprometida = self::omitirFeriados($fecha_inicio, $fecha_comprometida); // se omiten los feriados    

		return [
			'fecha_inicio' => ($fecha_inicio->format('Y-m-d H:i:s')),
			'fecha_comprometida' => ($fecha_comprometida->format('Y-m-d H:i:s'))
		];
	}

	// ================================================================================== //
	// ============= CALCULO DE FECHA DE INICIO Y COMPROMEIDA DE UN INFORME ============= //
	// ================================================================================== //

	/**
	 * Funcion que devuelve las fechas del informe en base a la duracion
	 * de su modelo
	 * @access public
	 * @param string|null duracion del informe
	 * @return array
	 *
	 */
	public static function establecerFechasInformebkp($duracion_informe, $incio = NULL) {
		$fecha_inicio = self::obtenerFechaInicioInforme($incio); // calculamos la fecha de incio    
		$fecha_comprometida = self::obtenerFechaComprometidaInforme($duracion_informe, $fecha_inicio); // calculamos la fecha comprometida del informe

		$fecha_comprometida = self::omitirFeriados($fecha_inicio, $fecha_comprometida); // se omiten los feriados    

		return [
			'fecha_inicio' => ($fecha_inicio->format('Y-m-d H:i:s')),
			'fecha_comprometida' => ($fecha_comprometida->format('Y-m-d H:i:s'))
		];
	}

	// public static function establecerFechasInformeOrg($duracion_informe){
	//   $fecha = new DateTime();
	//   $hora = explode(':',$fecha->format('H:i'));
	//   if(intval($hora[0]) >= 14){
	//     $fecha->modify('+1 day');
	//   }
	//   if($fecha->format('N') == 6){
	//     $fecha>modify('+2 day');
	//   }
	//   dd($fecha);

	//   // $numeroDiaSemana = $fecha->format('N');
	//   // $fechaInicio;  
	//   // for ($i=0; $i < $duracion_informe; $i++) { 
	//   //   # code...
	//   //   if($numeroDiaSemana = $fecha->format('N');){

	//   //   }
	//   //   //$fecha->modify('+1 day');
	//   //   //echo $fecha->format('Y-m-d');
	//   // }   

	// }

	/**
	 * Funcion que establece la fecha de inicio del informe
	 * @access private
	 * @return DateTime objeto del tiempo de la fecha de inicio
	 */
	private static function obtenerFechaInicioInforme($inicio) {
		$fecha = !is_null($inicio) ? new DateTime($inicio) : new DateTime();
		$intervalo_dia = new DateInterval('P1D');  // intervalo de un dia
		$horario_corte = 14;
		$hora = intval($fecha->format('H'));

		//
		if ($hora >= $horario_corte) {
			// Si el informe entra despues del horario de corte 
			// se pasa para que comienze el dia siguiente
			// a las 9
			$fecha->add($intervalo_dia);
			$fecha->setTime(9, 0);
		} else {
			// Si el informe entra antes del horario de corte 
			if ($hora < 9) {
				// y antes de las 9 (antes del comienzo de la jornada laboral) 
				// comienza a las 9 del mismo dia
				$fecha->setTime(9, 0);
			} else {
				// Si el informe entra despues de las 9 (despues del comienzo de la jornada laboral) 
				// comienza al horario de corte del mismo dia
				$fecha->setTime($horario_corte, 0);
			}

		}
		// se valida que no caiga un sabado ni domingo
		$dia_semana = $fecha->format('w');
		if ($dia_semana == '6') {
			// sabado
			$fecha->add(new DateInterval('P2D'));
		} elseif ($dia_semana == '0') {
			// domingo
			$fecha->add($intervalo_dia);
		}
		//
		return $fecha;
	}

	/**
	 * Funcion que establece la fecha de comprometida del informe
	 * @access private
	 * @param string|null duracion del informe
	 * @param array arreglo de fechas feriados proximos
	 * @return DateTime objeto del tiempo de la fecha de inicio
	 */
	private static function obtenerFechaComprometidaInforme($duracion, $fecha_inicio) {
		$fecha = clone $fecha_inicio; // clono el objeto del fecha de inicio para obtener uno nuevo
		$fecha->setTime(23, 59, 59); // setea la hora comprometida al final del dia
		$intervalo_dia = new DateInterval('P1D'); // intervalo de un dia
		// $hora = intval($fecha_inicio->format('H')); // hora de la fecha comprometida
		$hora = intval((new DateTime())->format('H'));
		$dia_semana = NULL;
		//
		if ($duracion && is_numeric($duracion) && intval($duracion) > 0) {
			// sumamos dia a dia para evaluar si cae algun fin de semana
			$fecha->sub($intervalo_dia);
			for ($i = 0; $i < $duracion; $i++) {
				$fecha->add($intervalo_dia);
				$dia_semana = $fecha->format('w');
				if ($dia_semana == '6') {
					// sabado
					$fecha->add(new DateInterval('P2D'));
				} elseif ($dia_semana == '0') {
					// domingo
					$fecha->add($intervalo_dia);
				}
			}
			// le restamos un dia (para que el dia de inicio este integrado en el calculo de duracion)
			// if ( $hora < 14 ){
			// $fecha->sub($intervalo_dia);
			// }
		} else {
			// caso de duracion invalida
			$fecha->add($intervalo_dia);
		}
		// se valida que no caiga un sabado ni domingo
		/* $dia_semana = $fecha->format('w');
					if ( $dia_semana == '6' ){
						// sabado
						$fecha->add(new \DateInterval('P2D'));
					} elseif ( $dia_semana == '0' ){
						// domingo
						$fecha->add($intervalo_dia);
					} */
		//
		return $fecha;
	}

	/**
	 * Funcion que valida que las fechas 
	 * no hayan caido en tiempo de feriado.
	 * Si caen en feriado se modifican hasta
	 * la fecha hábil mas cercana
	 * @access private
	 * @param DateTime fecha de inicio informe
	 * @param DateTime fecha comprometida informe
	 * @return void modifica el contenido de los objetos sin tener que devolverlos
	 */
	private static function omitirFeriados($fecha_inicio, $fecha_comprometida) {
		//--Modificado 12/05/2023--
		$intervalo_dia = new DateInterval('P1D'); // intervalo de un dia

		// $feriados = SQLConnection::backendStoreProcedure('IVferiados',array('LIST_FERIADOS')); // obtenemos los feriados nacionales
		$feriados = SQLConnection::backendStoreProcedure('LN_feriados', array('FERIADOS_INFORME', 'AR', NULL, NULL));
		//-------------------------   
		$fecha_comprometida_analisis = clone $fecha_comprometida;
		$fecha_comprometida_analisis->setTime(0, 0, 0);
		$fecha_inicio_analisis = clone $fecha_inicio;
		$fecha_inicio_analisis->setTime(0, 0, 0);
		$entra = 0;

		foreach ($feriados as $dia_feriado) {

			$obj_dia_feriado = new DateTime($dia_feriado->fecha_feriado);
			if ($obj_dia_feriado && $obj_dia_feriado->format('Y-m-d H:i:s') == $fecha_inicio_analisis->format('Y-m-d H:i:s')) {

				/* 
																																																	 si fecha de inicio es feriado , tambien se modifica
																																																		 la fecha comprometida para respetar la duracion
																																																 */
				$fecha_inicio->add($intervalo_dia);
				$fecha_comprometida_analisis->add($intervalo_dia);
			} elseif ($obj_dia_feriado && $obj_dia_feriado->format('Y-m-d') == $fecha_comprometida_analisis->format('Y-m-d')) {
				$fecha_comprometida_analisis->add($intervalo_dia);
			} elseif ($obj_dia_feriado && ($obj_dia_feriado->format('Y-m-d') < $fecha_comprometida_analisis->format('Y-m-d')) && ($obj_dia_feriado->format('Y-m-d') > $fecha_inicio_analisis->format('Y-m-d'))) {

				$fecha_comprometida_analisis->add($intervalo_dia);

			}
		}
		$fecha_inicio = self::calcularFinDeSemana($fecha_inicio);
		$fecha_comprometida_analisis = self::calcularFinDeSemana($fecha_comprometida_analisis);

		return $fecha_comprometida_analisis;
	}


	/**
	 * Funcion que calcula
	 * @access private
	 * @param DateTime fecha de inicio informe
	 * @param DateTime fecha comprometida informe
	 * @return void modifica el contenido de los objetos sin tener que devolverlos
	 */
	private static function calcularFinDeSemana($fecha) {
		$dia_semana = $fecha->format('w');
		$intervalo_dia = new DateInterval('P1D'); // intervalo de un dia

		if ($dia_semana == '6') {
			// sabado
			$fecha->add(new DateInterval('P2D'));
		} elseif ($dia_semana == '0') {
			// domingo
			$fecha->add($intervalo_dia);
		}

		return $fecha;
	}

	/**
	 * Metodo que recalcula la
	 * integridad del documento
	 * devuelve true si es docs_ok o false si no
	 * @access public
	 * @param string|int id de contraparte
	 * @param string|int id de gestion
	 * @return bool|null|array
	 */
	public static function recalcularIntegridadGestion($contraparte, $gestion, $response = false) {
		/* $count_docs = DB::selectOne("SELECT gestion,
			(SELECT count(*) AS Verif FROM ln_docs WHERE gestion=$gestion && aplica=1 && estado_doc='V') AS integ_verif,
			(SELECT count(*) AS rechazados FROM ln_docs WHERE gestion=$gestion && aplica=1 && estado_doc='R') AS integ_rech,
			(SELECT count(*) AS totales FROM ln_docs WHERE gestion=$gestion && aplica=1 && estado_doc != 'X') AS totales,
			(SELECT count(*) AS sin_verif FROM ln_docs WHERE gestion=$gestion && aplica=1 && estado_doc='I') AS sin_verificar ,
			(SELECT count(*) AS pendiente_carga FROM ln_docs WHERE gestion=$gestion && aplica=1 && estado_doc='N') AS sin_cargar
			FROM ln_docs WHERE gestion=$gestion
			GROUP BY gestion
		"); */
		/* $count_docs = DB::select("SELECT COUNT(*),estado_doc
		FROM LN_docs
		WHERE LN_docs.contraparte = $contraparte
		&& LN_docs.gestion=$gestion
		&& LN_docs.estado_doc != 'X'
		&& (LN_docs.aplica = 1 || 
				(LN_docs.aplica = 0 && 
				not exists (select * from LN_docs b 
							where b.contraparte = ln_docs.contraparte 
								&& b.tipo_doc = ln_docs.tipo_doc 
								&& ISNULL(b.inicio_ejercicio, '2001-01-01') = ISNULL(ln_docs.inicio_ejercicio, '2001-01-01')
								&& b.gestion = ln_docs.gestion 
								&& b.estado_doc != 'X'
								&& b.aplica = 1))
			)
		GROUP BY estado_doc
	"); */
		$docs = SQLConnection::backendStoreProcedure('LN_contrapartes_', array('DOCUMENTOS_GESTION_ACTIVA', $contraparte, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
		$report_data = SQLConnection::backendStoreProcedure('LN_demo_', array('SELECCIONAR_INFORME', $contraparte, NULL, null, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, $gestion), 'selectOne');
		//
		if (!empty($docs) && !is_null($report_data)) {
			$suma_cargados = 0;
			$suma_verificados = 0;
			$suma_rechazados = 0;
			$total = 0;
			//
			foreach ($docs as $doc) {
				if ($doc->estado_doc == 'V') {
					$suma_cargados++;
					$suma_verificados++;
				} elseif ($doc->estado_doc == 'R') {
					$suma_cargados++;
					$suma_rechazados++;
				} elseif ($doc->estado_doc == 'I') {
					$suma_cargados++;
				}
				if ($doc->aplica == '1') {
					$total++;
				}
			}
			//
			$integ_verif = 0;
			$integ_carga = 0;
			$integ_rech = 0;
			//
			$docs_ok = $report_data->docs_ok; // el que esta cargado
			//
			if ($total > 0) {
				// $suma_cargados = $count_docs->totales - $count_docs->sin_cargar;
				// $suma_verificados = $count_docs->integ_verif;
				// $suma_rechazados = $count_docs->integ_rech;
				//
				$integ_verif = floor(($suma_verificados * 100) / $total);
				$integ_carga = floor(($suma_cargados * 100) / $total);
				$integ_rech = floor(($suma_rechazados * 100) / $total);
				//
				if ($docs_ok != 1 && $suma_verificados == $total) {
					// if ( $suma_verificados == $total ){
					$docs_ok = 1;
				}
			}
			// dd($suma_verificados,$total,$docs_ok);
			/* if ( $count_docs->totales > 0 ){
			$suma_cargados = $count_docs->totales - $count_docs->sin_cargar;
			$suma_verificados = $count_docs->integ_verif;
			$suma_rechazados = $count_docs->integ_rech;
			//
			$integ_verif = ($suma_verificados*100)/$count_docs->totales;
			$integ_carga = ($suma_cargados*100)/$count_docs->totales;
			$integ_rech = ($suma_rechazados*100)/$count_docs->totales;
			//
			// $integ_verif = number_format($integ_verif,2);
			// $integ_carga = number_format($integ_carga,2);
			// $integ_rech = number_format($integ_rech,2);
			//
			if ( $docs_ok != 1 && $suma_verificados == $count_docs->totales ){
				$docs_ok = 1;
			}
			} */
			//
			// dd($integ_verif,$integ_rech,$integ_carga,$suma_verificados,$total);
			SQLConnection::backendStoreProcedure('LN_demo_', array('ACTUALIZAR_INTEGRIDADES', $contraparte, NULL, null, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, $gestion, null, null, null, null, $integ_carga, $integ_verif, $integ_rech, $docs_ok));
			//
			if ($response) {
				return ['integ_carga' => $integ_carga, 'integ_verif' => $integ_verif, 'integ_rech' => $integ_rech, 'docs_ok' => $docs_ok];
			}
			//
			return ($docs_ok == 1);
		}
		//
		if ($response) {
			return NULL;
		}
		return false;
	}

	public static function obtenerUsuariosCliente() {
		$cliente = Request::input('cliente');
		$usuarios = SQLConnection::backendStoreProcedure('LN_demo_', array('usuarios_solicitantes', null, $datos_informe->cliente), 'select');
	}

	/**
	 * Extiende la fecha comprometida de una tarea en base a la extension del link.
	 *
	 * @param string $tarea El identificador de la tarea.
	 * @param string $expira La fecha de expiracion en formato 'd/m/Y'.
	 * @param string $nombre_tipo_tarea El nombre del tipo de tarea.
	 * @param string $limite_carga_inicial El limite de carga inicial de la tarea.
	 * @param object $qcontrap Objeto que contiene información de la contraparte.
	 * @param int $id El identificador de la contraparte.
	 * @return string|null
	 * Mensaje que indica el resultado de la operacion: 'EXTENSION_FECHA_COMPLETO' o 'ERROR_PARAMETROS'.
	 */
	public static function extensionFechaComprometidaTarea($tarea, $expira, $nombre_tipo_tarea, $limite_carga_inicial, $qcontrap, $id, $proximo_contacto) {
		// Verifica si la variable $tarea esta definida y no esta vacia
		if (isset($tarea) && !empty($tarea)) {
			// Obtiene los datos de la tarea
			$datos_tarea = self::datosTarea($tarea);

			// Verifica si la fecha comprometida de la tarea no esta vacia
			if (!empty($datos_tarea) && isset($datos_tarea->fecha_comprometida_tarea) && !empty($datos_tarea->fecha_comprometida_tarea)) {

				if (!self::validateDate($expira, 'd/m/Y')) {
					$expira = str_replace('-', '/', $expira);
				}

				// Crea un objeto DateTime a partir de la fecha de expiracion en formato 'd/m/Y'
				$fecha = DateTime::createFromFormat('d/m/Y', $expira);
				$fecha_expiracion = $fecha->format('Y-m-d H:i:s');
				$fecha = new DateTime($fecha_expiracion);

				// Suma dos días a la fecha comprometida de la tarea
				$fecha->modify('+2 days');
				$fechaModificadaTarea = $fecha->format('Y-m-d H:i:s');

				// Obtiene el día de la semana (0 para domingo, 6 para sabado)
				$diaDeLaSemana = $fecha->format('w');

				// Si es fin de semana, ajusta la fecha comprometida
				if ($diaDeLaSemana == 6) {
					// Suma 2 dias si es Sabado
					$fecha->modify('+2 days');
					$fechaModificadaTarea = $fecha->format('Y-m-d H:i:s');
				} elseif ($diaDeLaSemana == 0) {
					// Suma 1 día si es Domingo
					$fecha->modify('+1 day');
					$fechaModificadaTarea = $fecha->format('Y-m-d H:i:s');
				}

				if (!self::validateDateContact($proximo_contacto, 'Y-m-d H:i:s')) {
					$proximo_contacto = DateTime::createFromFormat('d-m-Y', $proximo_contacto);
					$proximo_contacto = $proximo_contacto->format('Y-m-d H:i:s');
				}

				$temp = SQLConnection::backendStoreProcedure('LN_contrapartes_', array('actualizar_carga_inicial', $datos_tarea->contraparte, NULL, NULL, NULL, NULL, NULL, NULL, NULL, $limite_carga_inicial, NULL, NULL, NULL, NULL, null, 0, null, 'CC', NULL, NULL, 'AR', NULL, 'spa', null, null, null, null, 'F,C,L', 0, $proximo_contacto, null, $fechaModificadaTarea), 'selectOne');

				// Actualizar la fecha comprometida de la tarea en la base de datos
				//SQLConnection::backendStoreProcedure('LN_Blue_UPDAGB',array('UPD_TAREA2',$datos_tarea[0]->contraparte,$tarea,Session::get('usuario')->user_id,NULL,NULL,$datos_tarea[0]->idTipoTarea,$datos_tarea[0]->tarea_prioridad,$datos_tarea[0]->codigo_estado_tarea,$datos_tarea[0]->ingresado_por,NULL,$datos_tarea[0]->userIDAsigandoTarea,$datos_tarea[0]->cliente,NULL,NULL,$fechaModificadaTarea,NULL,NULL,NULL,$datos_tarea[0]->ready_to_start_date));               

				// Actualizar la fecha comprometida de la tarea en la base de datos
				/* SQLConnection::backendStoreProcedure('LN_Blue_UPDAGB', array(
					'UPD_FECHA_COMPROMETIDA_TAREA', 
					NULL, 
					$tarea, 
					Session::get('usuario')->user_id, 
					NULL, 
					NULL, 
					NULL, 
					NULL, 
					NULL, 
					NULL, 
					NULL, 
					NULL, 
					NULL, 
					NULL, 
					NULL, 
					$fechaModificadaTarea
				)); */

				// Registra el cambio de fecha en la trazabilidad
				SQLConnection::logTrazabilidad('Se cambió la fecha comprometida de la tarea ' . $nombre_tipo_tarea . ' : ' . $fechaModificadaTarea, 'CAMBIAR_FECHA_COMPROMETIDA_TAREA', Session::get('webdata')['id_menu_plataforma'], Session::get('usuario')->user_id, $qcontrap->servicio_contratado, $qcontrap->cliente, $id, null, null, null, null, null, $tarea, null);

				// Devuelve un mensaje indicando que la extension de la fecha fue completa
				return 'EXTENSION_FECHA_COMPLETO';
			}
		} else {
			// Retorna un mensaje de error si los parámetros no son validos
			return 'ERROR_PARAMETROS';
		}
	}

	/**
	 * Extiende la fecha comprometida de un informe en base a la extencion del link.
	 *
	 * @param object $datos_informe Objeto que contiene los datos del informe, incluyendo la fecha comprometida actual.
	 * @param string $expira La fecha de expiración en formato 'd/m/Y'.
	 * @param string $informe El identificador del informe.
	 * @param string $servicio_contratado El nombre del servicio contratado.
	 * @param string $cliente El nombre del cliente.
	 * @param string $contraparte El id de la contraparte.
	 * @param string $duracion_informe Es la cantidad de dias que dura el informe.
	 * @return string Mensaje que indica el resultado de la operacion: 'EXTENSION_FECHA_COMPLETO' o 'ERROR_PARAMETROS'.
	 */
	public static function extensionFechaComprometidaInforme($datos_informe, $expira, $informe, $servicio_contratado, $cliente, $contraparte, $duracion_informe) {
		// Verificar si los parametros están definidos y no están vacios
		if (!empty($datos_informe) && isset($datos_informe->fecha_comprometida_informe)) {
			// Crear objeto DateTime a partir de la fecha de expiracion

			if (self::validateDate($expira, 'd/m/Y')) {
				$expira = str_replace('/', '-', $expira);
			}

			$fecha_expiracion_informe = DateTime::createFromFormat('d-m-Y', $expira);
			$fecha = new DateTime($fecha_expiracion_informe->format('Y-m-d H:i:s'));
			// Sumo la cantidad de dias de duracion del informe a la fecha
			$fecha->modify('+' . $duracion_informe . ' days');
			// Verificar si es fin de semana
			$diaDeLaSemana = $fecha->format('w');

			if ($diaDeLaSemana == 6) {
				// Sumar 2 dias si es sabado
				$fecha->modify('+2 days');
			} elseif ($diaDeLaSemana == 0) {
				// Sumar 1 dia si es domingo
				$fecha->modify('+1 day');
			}

			// Obtener la nueva fecha comprometida como string
			$fechaComprometidaInforme = $fecha->format('Y-m-d H:i:s');

			// Actualizar la fecha comprometida del informe en la base de datos
			SQLConnection::backendStoreProcedure('LN_Blue_UPDAGB', [
				'UPD_informe',
				$datos_informe->contraparte,
				$informe,
				Session::get('usuario')->user_id,
				NULL,
				NULL,
				$datos_informe->id_tipo_informe,
				$datos_informe->informe_prioridad,
				$datos_informe->codigo_estado_informe,
				NULL,
				NULL,
				$datos_informe->userIDAsigandoInforme,
				$datos_informe->cliente,
				NULL,
				NULL,
				$fechaComprometidaInforme
			]);

			// Registrar la trazabilidad del cambio de fecha comprometida en la base de datos
			SQLConnection::logTrazabilidad(
				'Se cambió la fecha comprometida del informe: ' . $fechaComprometidaInforme,
				'CAMBIAR_FECHA_COMPROMETIDA_INFORME',
				Session::get('webdata')['id_menu_plataforma'],
				Session::get('usuario')->user_id,
				$servicio_contratado,
				$cliente,
				$contraparte,
				null,
				null,
				null,
				null,
				null,
				$informe,
				null
			);

			// Devolver codigo de éxito
			return 'EXTENSION_FECHA_COMPLETO';
		} else {

			// Devolver codigo de error
			return 'ERROR_PARAMETROS';
		}
	}

	/**
	 * FUNCION GENÉRICA QUE DEVUELVE LOS DATOS DE UNA TAREA PASADA POR PARÁMETRO
	 * 
	 * @param string id de la tarea 
	 */
	public static function datosTarea($tarea = null) {
		if (!is_null($tarea) && is_numeric($tarea)) {
			$datos_tarea = SQLConnection::backendStoreProcedure("LN_datos_tarea", array($tarea))[0] ?? null;
			// dd($datos_tarea);
			return $datos_tarea;
		} else {
			return null;
		}

	}

	public static function validateDate($date, $format = 'd/m/Y') {

		$d = DateTime::createFromFormat($format, $date);

		return $d && $d->format($format) === $date;
	}

	public static function validateDateContact($date, $format = 'Y-m-d H:i:s') {

		$d = DateTime::createFromFormat($format, $date);

		return $d && $d->format($format) === $date;
	}


	/**
	 * Función que valida devuelve
	 * los procesos de una fuente
	 * @access private
	 * //
	 * @param string
	 * @param int
	 * @param string (50)
	 * @param string 
	 */
	public static function validacion_proceso_fuente_mensual($id_fuente, $cod_fuente, $fecha) {
		return SQLConnection::backendStoreProcedure('fuentes_procesadas_info', array('control_mensual', NULL, NULL, $id_fuente, $cod_fuente, $fecha));
	}

	/**
	 * Función que valida devuelve
	 * los procesos de una fuente
	 * @access private
	 * //
	 * @param string
	 * @param int
	 * @param string (50)
	 * @param string 
	 */
	public static function validacion_proceso_fuente_semanal($id_fuente, $cod_fuente, $fecha) {
		return SQLConnection::backendStoreProcedure('fuentes_procesadas_info', array('control_semanal', NULL, NULL, $id_fuente, $cod_fuente, $fecha));
	}

	/**
	 * Función que valida devuelve
	 * los procesos de una fuente
	 * @access private
	 * //
	 * @param string
	 * @param int
	 * @param string (50)
	 * @param string 
	 */
	public static function validacion_proceso_fuente_diario($id_fuente, $cod_fuente, $fecha) {
		return SQLConnection::backendStoreProcedure('fuentes_procesadas_info', array('control_diario', NULL, NULL, $id_fuente, $cod_fuente, $fecha));
	}

	
	/* Lo cambiamos por este control el 05/10/2020 */
    /* public static function obtenerConsumos($productos,$id_producto){
		//v
	} */

	private static function ControlConsumos($cliente, $usuario, $prod){
		$ver_consumos = SQLConnection::backendStoreProcedure('obtener_control_consumos',array($cliente, $usuario, $prod),'selectOne');
		return $ver_consumos;
	}

	/* 
		Esta funcion escribe los logs de los procesos de fuentes
	*/
	public static function logFuentes($fechaProceso, $fuente, $observaciones, $fuenteId, $id_cendeu_procesado = null){
		
		/* 
			ALTER PROCEDURE [dbo].[backend_abm_fuentes_procesadas]
        	@accion char(1), 
        	@id_cendeu_procesado int = null, 
        	@fecha_informacion date  = null, 
        	@fuente varchar(500)  = null, 
        	@visible int  = null,
        	@observaciones varchar(max)  = null, 
        	@user_id int  = null, 
        	@IP varchar(100)    = null,
        	@id_fuente int=NULL 
		*/

		$userId = NULL; 
		$ip = $_SERVER['REMOTE_ADDR'];

		SQLConnection::backendStoreProcedure('backend_abm_fuentes_procesadas',array('A', $id_cendeu_procesado, $fechaProceso, $fuente, 1, $observaciones, $userId, $ip, $fuenteId));


	}

	/* 
        Funcion que obtiene la fecha del dia anterior a hoy
    */
    public static function obtenerDiaHabilAnterior($fecha = 'today'){
        $date = new DateTime($fecha);
        
        do {
            $date->modify('-1 day');
        } while (in_array($date->format('N'), [6, 7])); // 6 = Sabado, 7 = Domingo

        return $date->format('Y-m-d');
    }

	/* 
        Funcion que obtiene la fecha del hoy
    */
	public static function obtenerDiaDeHoy($fecha = 'today'){
        $date = new DateTime($fecha);              

        return $date->format('Y-m-d');
    }

	public static function escribirLogBatch($message, $level = 'INFO') {
		// se freno la función (porque no se graba log), en caso de cambiar de opinión
		// crear la carpeta de log antes de habilitar
		return;
		// Nombre del archivo de log (uno por día)
		$logFile = '/var/www/html/compartido/logProcesosBatch/log_' . date('Y-m-d') . '.txt';
	
		$logMessage = '[' . date('Y-m-d H:i:s') . '] ' . $level . ': ' . $message . PHP_EOL;
			
		file_put_contents($logFile, $logMessage, FILE_APPEND);
	}

	public static function formatearClienteId($clienteId): string {
        return $clienteId
        ? str_pad($clienteId, 12, '0', STR_PAD_LEFT)
        : 'all';
    }

    public static function generarRutaCarpeta($rangoFecha, $clienteId, $productoId, $baseDir): ?string {
		try {
			$clienteIdPadded = self::formatearClienteId($clienteId);
			$productoNombre = $productoId ? "{$productoId}" : "all";

			if (strlen($rangoFecha) > 7) { // Diario
				$fechaObj = Carbon::createFromFormat('Y-m-d', $rangoFecha);
				$añoMes = $fechaObj->format('Ym');
				$dia = $fechaObj->format('d');
				return "$baseDir/$añoMes/$dia/$clienteIdPadded/$productoNombre";
			} else { // Mensual
				$fechaObj = Carbon::createFromFormat('Y-m', $rangoFecha);
				$añoMes = $fechaObj->format('Ym');
				return "$baseDir/$añoMes/mensual/$clienteIdPadded/$productoNombre";
			}
		} catch (\Exception $e) {
			error_log("Error al generar ruta para fecha $rangoFecha: " . $e->getMessage());
			return null;
        }
    }

	public static function generarNombreArchivo($productoId, $clienteId, $rangoFecha): string {
		//$pNombre = $productoId ? "producto-{$productoId}" : "all";
        //$cNombre = $clienteId ? "cliente-{$clienteId}" : "all";
		$fechaNombre = str_replace('-', '', $rangoFecha);
        return "{$fechaNombre}";
    }

}

