------------------------------------------------------------------------------- $Id$ -----------------------------------------------------------------------------*/ require_once 'DB.php'; // FIXME - esto debe volar!!! require_once 'MLIB/Tiempo/Intervalo.php'; /** * Representa un conjunto de entradas y salidas para formar una banda horaria * * @package HE * @abstract * @version $Rev$ * @author Gonzalo Merayo */ class MLIB_Tiempo_Banda { var $intervalos; var $db; /** * Constructor. * @param $db Conexión opcional a una base de datos. */ function MLIB_Tiempo_Banda($db = null) { $this->db = $db; $this->intervalos = array(); } /** * Funcion que se encarga de cargar los intervalos de tiempo de un agente. * Devuelve true en caso de detectar una inconsistecia de reloj o false en caso contrario * * @param $agente Documento del agente * @param $accesos Array o Date Variable que puede ser un array con todos los accesos * de un agente o un objeto Date que indica la fecha de la banda a procesar * @param $db Conexión opcional a una base de datos. */ function cargar($agente, $accesos, $db = null) { if ($db) { $this->db = $db; } $funcion = $this->db->getOne( "SELECT E.funcion FROM novedades.estado as E, novedades.web003 as S WHERE E.nrodoc = $agente AND S.nrodoc = $agente AND S.codep = E.dependencia" ); if (is_a($accesos,'date')) { $fecha =& $accesos; $fecha = $fecha->format("%Y%m%d"); $query = "SELECT TA.tipo_acceso, A.hora FROM bandas.Acceso A, bandas.Agente_Credencial AC, bandas.Tipo_Acceso TA WHERE AC.credencial = A.credencial AND A.fecha = '$fecha' AND AC.agente = $agente AND TA.puerta = A.puerta AND AC.desde <= '$fecha' AND ( AC.hasta >= '$fecha' OR AC.hasta IS NULL) ORDER BY A.hora"; $result = $this->db->query($query); if(DB::isError($result)) trigger_error($result->getMessage(), E_USER_ERROR); $inconsistencia = false; if($funcion != 'SE') {//Version tough $int = null; while( $r = $result->fetchRow() ) { if($r[0] == 'E') { if($int != null) $inconsistencia = true; $int = new MLIB_Tiempo_Intervalo(new MLIB_Tiempo_Hora( $r[1] ), new MLIB_Tiempo_Hora( $r[1] )); } if($r[0] == 'S') { if($int != null) { $int->setFin( new MLIB_Tiempo_Hora( $r[1] ) ); $this->agregarIntervalo( $int ); $int = null; } else $inconsistencia = true; } } if($int != null) $inconsistencia = true; } else { if($result->numRows() > 0) {//Version Light o Serenos $int = new MLIB_Tiempo_Intervalo(new MLIB_Tiempo_Hora('00:00'), new MLIB_Tiempo_Hora('00:00')); while( $r = $result->fetchRow() ) { if($r[0] == 'E') { // if($int != null) //$inconsistencia = true; $int = new MLIB_Tiempo_Intervalo(new MLIB_Tiempo_Hora( $r[1] ), new MLIB_Tiempo_Hora( $r[1] )); } if($r[0] == 'S') { if($int != null) { $int->setFin( new MLIB_Tiempo_Hora( $r[1] ) ); $this->agregarIntervalo( $int ); $int = null; } //else // $inconsistencia = true; } } if($int != null) { $int->setFin( new Hora('24:00') ); $this->agregarIntervalo( $int ); $int = null; } } } } else { $inconsistencia = false; if($funcion != 'SE') {//Version tough $int = null; if(!is_null($accesos)) { foreach( $accesos as $r ) { if($r[0] == 'E') { if($int != null) $inconsistencia = true; $int = new MLIB_Tiempo_Intervalo(new MLIB_Tiempo_Hora( $r[1] ), new MLIB_Tiempo_Hora( $r[1] )); } if($r[0] == 'S') { if($int != null) { $int->setFin( new MLIB_Tiempo_Hora( $r[1] ) ); $this->agregarIntervalo( $int ); $int = null; } else $inconsistencia = true; } } } if($int != null) $inconsistencia = true; } else { //Version Light o Serenos $int = new MLIB_Tiempo_Intervalo(new MLIB_Tiempo_Hora('00:00'), new MLIB_Tiempo_Hora('00:00')); if(!is_null($accesos)) { foreach( $accesos as $r ) { if($r[0] == 'E') { // if($int != null) //$inconsistencia = true; $int = new MLIB_Tiempo_Intervalo(new MLIB_Tiempo_Hora( $r[1] ), new MLIB_Tiempo_Hora( $r[1] )); } if($r[0] == 'S') { if($int != null) { $int->setFin( new MLIB_Tiempo_Hora( $r[1] ) ); $this->agregarIntervalo( $int ); $int = null; } //else // $inconsistencia = true; } } } if($int != null) { $int->setFin( new Hora('24:00') ); $this->agregarIntervalo( $int ); $int = null; } } } return $inconsistencia; } /** * Completa las salidas del medio del dia. * */ function CompletarSalidas() { if(count($this->intervalos) > 0) { $p = reset($this->intervalos); $u = end($this->intervalos); $p->setFin($u->fin); $this->intervalos = array($p); } } /** * Agrega un intervalo a la banda * Chequeando superposiciones y en orden * * @param Intervalo $intervalo Intervalo a agregar. */ function agregarIntervalo($intervalo) { if ($intervalo->invertido()) { $intervalo->_chequear(); $this->agregarIntervalo(new MLIB_Tiempo_Intervalo(new MLIB_Tiempo_Hora('00:00'), new MLIB_Tiempo_Hora ('24:00'))); $this->sacarIntervalo($intervalo); return true; } $n_intervalos = array(); $insertado = false; // recorre el vector de intervalos foreach( $this->intervalos as $i ) { // si se superpone con alguno, fusionar con ese if($i->seSuperpone($intervalo) || $i->esAdyacente($intervalo)) { $intervalo->fusionar($i); } else { if($i->inicio->greater($intervalo->inicio) && ! $insertado) { array_push($n_intervalos, $intervalo); $insertado = true; } array_push($n_intervalos, $i); } } if(! $insertado ) array_push($n_intervalos,$intervalo); $this->intervalos = $n_intervalos; return true; } /** * Saca. */ function sacarBanda($banda) { foreach($banda->intervalos as $i) $this->sacarIntervalo($i); } /** * Saca un intervalo de una banda horaria. */ function sacarIntervalo($intervalo) { // Si el intervalo está vacío, no hace nada. $dur = $intervalo->getDuracion(); if ($dur->isEmpty()) { return true; } $n_intervalos = array(); // recorre el vector de intervalos foreach( $this->intervalos as $i ) { if($i->seSuperpone($intervalo)) { $a = $i->cortar($intervalo); $d = $a->getDuracion(); if($d->toSeconds() > 0) { $n_intervalos[] = $a; } $d = $i->getDuracion(); if($d->toSeconds() > 0) { $n_intervalos[] = $i; } } else { $n_intervalos[] = $i; } } $this->intervalos = $n_intervalos; return true; } /** * Saca. */ function sacarTiempo($t) { $n_int = array(); while(count($this->intervalos) > 0) { $int = array_shift($this->intervalos); if($t->toSeconds() > 0) { $d = $int->getDuracion(); if($d->greater($t)) { #con cortar alcanza $ini = new MLIB_Tiempo_Hora(); $ini->copy($int->inicio); $ini->add($t); /*TODO guardar este tiempo como rechazado*/ $int->cortar($ini); $t->setFromSeconds(0); } else { #con cortar no alcanza y hay que sacar... $t->subtract($int->getDuracion()); /*TODO guardar int como rechazado*/ } } $n_int[] = $int; } $this->intervalos = $n_int; } /** * Chequea si el intervalo pedido esta cubierto por la banda, si faltan * horas en la banta se retorna el tiempo que falta * * @return Date_Span el periodo faltante */ function chequearIntervalo($intervalo) { $t = new MLIB_Tiempo_Hora(); foreach ($this->intervalos as $i) $t->add($i->superponer($intervalo)); $d = $intervalo->getDuracion(); $d->subtract($t); return $d; } /** * Chequea si la banda(parametro) esta cubierto por la banda(this), * si faltan horas en la banda(this) para llegar a banda(parametro) * se retorna el tiempo que falta * * @return Date_Span el periodo faltante */ function chequearBanda($banda) { $f = new MLIB_Tiempo_Hora(); foreach ($banda->intervalos as $i) $f->add($this->chequearIntervalo($i)); return $f; } /** * Devuelve una representacion del objeto como un string. * * @return string Representacion del objeto. */ function toString() { $s = ''; $t = count($this->intervalos); for ($n = 0; $n < ($t - 1); $n++) { $s .= "intervalo $n: [" . $this->intervalos[$n]->toString() . '] | '; } $n = $t - 1; if ($n != -1) { $s .= "intervalo $n: [" . $this->intervalos[$n]->toString() . ']'; } return $s; } function getIntervalos() { return $this->intervalos; } /** * Corta una banda, devolviendo la banda previa al punto de corte. * * La banda actual queda con los intervalos posteriores al punto de corte * y se devuelve la banda con los intervalos anteriores. * El punto de corte puede ser tanto una hora como un intervalo. * * @param mixed $c Donde cortar. * * @return object Banda Bnada anterior al punto de corte. */ function cortar($c) { $b = $this->__clone(); $b->intervalos = array(); $intervalos = array(); foreach ($this->intervalos as $i) { $a = $i->cortar($c); $da = $a->getDuracion(); if (!$da->isEmpty()) { $b->agregarIntervalo($a); } $di = $i->getDuracion(); if (!$di->isEmpty()) { $intervalos[] = $i; } } $this->intervalos = $intervalos; return $b; } /** * Devuelve el timpo total que contiene la banda. * * @return object Date_Span Tiempo total. */ function total() { $t = new Date_Span; foreach ($this->intervalos as $i) { $t->add($i->getDuracion()); } return $t; } /** * Alias de Banda::total() para compatibilidad con Intervalo. * * @return object Date_Span Tiempo total. */ function getDuracion() { return $this->total(); } /** * Chequea si el período pasado como argumento se superpone con la banda. * @param $periodo Puede ser un MLIB_Tiempo_Intervalo o MLIB_Tiempo_Banda. * @return true si se superpone, false si no. */ function seSuperpone($periodo) { $intervalos = array($periodo); if (is_a($periodo, 'MLIB_tiempo_banda')) { $intervalos = $periodo->intervalos; } foreach ($intervalos as $i) { if ($i->seSuperpone($this->intervalos)) { return true; } } return false; } /** * Resetea la banda. */ function flush() { $this->intervalos = array(); } function copy($b) { $this->flush(); foreach ($b->intervalos as $i) { $this->intervalos[] = $i->__clone(); } } function __clone() { $class = get_class($this); $b = new $class; $b->copy($this); return $b; } } ?>