]> git.llucax.com Git - mecon/meconlib.git/blob - lib/MECON/Tiempo/Banda.php
Se modifica Intervalo::seSuperpone() para que no tome como superpuestos a
[mecon/meconlib.git] / lib / MECON / Tiempo / Banda.php
1 <?php /* vim: set binary expandtab tabstop=4 shiftwidth=4 textwidth=80:
2 -------------------------------------------------------------------------------
3                              Ministerio de Economía
4                                     meconlib
5 -------------------------------------------------------------------------------
6 This file is part of meconlib.
7  
8 meconlib is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2 of the License, or (at your option)
11 any later version.
12  
13 meconlib is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16  
17 You should have received a copy of the GNU General Public License; if not,
18 write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 Boston, MA  02111-1307  USA
20 -------------------------------------------------------------------------------
21 Creado: lun abr 22 16:05:33 ART 2002
22 Autor:  Gonzalo Merayo <gmeray@mecon.gov.ar>
23 -------------------------------------------------------------------------------
24 $Id$
25 -----------------------------------------------------------------------------*/
26
27 require_once 'DB.php'; // FIXME - esto debe volar!!!
28 require_once 'MECON/Tiempo/Intervalo.php';
29
30 /**
31  * Representa un conjunto de entradas y salidas para formar una banda horaria
32  *
33  * @package HE
34  * @abstract
35  * @version $Rev$
36  * @author  Gonzalo Merayo <gmeray@mecon.gov.ar>
37  */
38 class MECON_Tiempo_Banda {
39
40     var $intervalos;
41     var $db;
42
43     /**
44      * Constructor.
45      * @param $db Conexión opcional a una base de datos.
46      */
47     function MECON_Tiempo_Banda($db = null)
48     {
49         $this->db = $db;
50         $this->intervalos = array();
51     }
52
53     /**
54      * Funcion que se encarga de cargar los intervalos de tiempo de un agente.
55      * Devuelve true en caso de detectar una inconsistecia de reloj o false en caso contrario
56      * 
57      * @param $agente Documento del agente
58      * @param $accesos Array o Date Variable que puede ser un array con todos los accesos
59      *        de un agente o un objeto Date que indica la fecha de la banda a procesar
60      * @param $db Conexión opcional a una base de datos.
61      */
62     function cargar($agente, $accesos, $db = null)
63     {
64         if ($db) {
65             $this->db = $db;
66         }
67
68         $funcion = $this->db->getOne(
69                 "SELECT E.funcion
70                 FROM novedades.estado as E, novedades.web003 as S
71                 WHERE
72                 E.nrodoc = $agente AND
73                 S.nrodoc = $agente AND
74                 S.codep  = E.dependencia"
75                 );
76
77         if (is_a($accesos,'date')) {
78             $fecha =& $accesos;
79             $fecha = $fecha->format("%Y%m%d");
80             $query = "SELECT TA.tipo_acceso, A.hora 
81                 FROM Acceso A, Agente_Credencial AC, Tipo_Acceso TA
82                 WHERE AC.credencial = A.credencial
83                 AND A.fecha = '$fecha'
84                 AND AC.agente = $agente
85                 AND TA.puerta = A.puerta
86                 AND AC.desde <= '$fecha'
87                 AND (  AC.hasta >= '$fecha'
88                         OR   AC.hasta IS NULL)
89                 ORDER BY A.hora";
90             $result = $this->db->query($query);
91             if(DB::isError($result))
92                 trigger_error($result->getMessage(), E_USER_ERROR);
93
94             $inconsistencia = false;
95             if($funcion != 'SE')
96             {//Version tough
97                 $int = null;
98                 while( $r = $result->fetchRow() )
99                 {
100                     if($r[0] == 'E')
101                     {
102                         if($int != null)
103                             $inconsistencia = true;
104                         $int = new Mecon_Tiempo_Intervalo(new Mecon_Tiempo_Hora( $r[1] ),
105                                 new Mecon_Tiempo_Hora( $r[1] ));
106                     }
107                     if($r[0] == 'S')
108                     {
109                         if($int != null)
110                         {
111                             $int->setFin( new Mecon_Tiempo_Hora( $r[1] ) );
112                             $this->agregarIntervalo( $int );
113                             $int = null;
114                         }
115                         else
116                             $inconsistencia = true;
117                     }
118                 }
119                 if($int != null)
120                     $inconsistencia = true;
121             }
122             else
123             {
124                 if($result->numRows() > 0)
125                 {//Version Light o Serenos
126                     $int = new Mecon_Tiempo_Intervalo(new Mecon_Tiempo_Hora('00:00'),
127                             new Mecon_Tiempo_Hora('00:00'));
128                     while( $r = $result->fetchRow() )
129                     {
130                         if($r[0] == 'E')
131                         {
132                             // if($int != null)
133                             //$inconsistencia = true;
134                             $int = new Mecon_Tiempo_Intervalo(new Mecon_Tiempo_Hora( $r[1] ),
135                                     new Mecon_Tiempo_Hora( $r[1] ));
136                         }
137                         if($r[0] == 'S')
138                         {
139                             if($int != null)
140                             {
141                                 $int->setFin( new Mecon_Tiempo_Hora( $r[1] ) );
142                                 $this->agregarIntervalo( $int );
143                                 $int = null;
144                             }
145                             //else
146                             //  $inconsistencia = true;
147                         }
148                     }
149                     if($int != null)
150                     {
151                         $int->setFin( new Hora('24:00') );
152                         $this->agregarIntervalo( $int );
153                         $int = null;
154                     }
155                 }
156             }
157         }
158         else
159         {
160             $inconsistencia = false;
161             if($funcion != 'SE')
162             {//Version tough
163                 $int = null;
164                 if(!is_null($accesos))
165                 {
166                     foreach( $accesos as $r )
167                     {
168                         if($r[0] == 'E')
169                         {
170                             if($int != null)
171                                 $inconsistencia = true;
172                             $int = new Mecon_Tiempo_Intervalo(new Mecon_Tiempo_Hora( $r[1] ),
173                                     new Mecon_Tiempo_Hora( $r[1] ));
174                         }
175                         if($r[0] == 'S')
176                         {
177                             if($int != null)
178                             {
179                                 $int->setFin( new Mecon_Tiempo_Hora( $r[1] ) );
180                                 $this->agregarIntervalo( $int );
181                                 $int = null;
182                             }
183                             else
184                                 $inconsistencia = true;
185                         }
186                     }
187                 }
188                 if($int != null)
189                     $inconsistencia = true;
190             }
191             else
192             {
193                 //Version Light o Serenos
194                 $int = new Mecon_Tiempo_Intervalo(new Mecon_Tiempo_Hora('00:00'),
195                         new Mecon_Tiempo_Hora('00:00'));
196
197                 if(!is_null($accesos))
198                 {
199                     foreach( $accesos as $r )
200                     {
201                         if($r[0] == 'E')
202                         {
203                             // if($int != null)
204                             //$inconsistencia = true;
205                             $int = new Mecon_Tiempo_Intervalo(new Mecon_Tiempo_Hora( $r[1] ),
206                                     new Mecon_Tiempo_Hora( $r[1] ));
207                         }
208                         if($r[0] == 'S')
209                         {
210                             if($int != null)
211                             {
212                                 $int->setFin( new Mecon_Tiempo_Hora( $r[1] ) );
213                                 $this->agregarIntervalo( $int );
214                                 $int = null;
215                             }
216                             //else
217                             //  $inconsistencia = true;
218                         }
219                     }
220                 }
221                 if($int != null)
222                 {
223                     $int->setFin( new Hora('24:00') );
224                     $this->agregarIntervalo( $int );
225                     $int = null;
226                 }
227             }
228         } 
229         return $inconsistencia;
230     }
231
232     /**
233      * Completa las salidas del medio del dia.
234      *
235      */
236     function CompletarSalidas()
237     {
238         if(count($this->intervalos) > 0) {
239             $p = reset($this->intervalos);
240             $u = end($this->intervalos);
241             $p->setFin($u->fin);
242             $this->intervalos = array($p);
243         }
244     }
245
246
247     /**
248      * Agrega un intervalo a la banda
249      * Chequeando superposiciones y en orden
250      *
251      * @param Intervalo $intervalo Intervalo a agregar.
252      */
253     function agregarIntervalo($intervalo)
254     {
255         if ($intervalo->invertido()) {
256             $intervalo->_chequear();
257             $this->agregarIntervalo(new MECON_Tiempo_Intervalo(new MECON_Tiempo_Hora('00:00'), new MECON_Tiempo_Hora ('24:00')));
258             $this->sacarIntervalo($intervalo);
259             return true;
260         }
261         $n_intervalos = array();
262         $insertado = false;
263         // recorre el vector de intervalos
264         foreach( $this->intervalos as $i ) {
265             // si se superpone con alguno, fusionar con ese
266             if($i->seSuperpone($intervalo) || $i->esAdyacente($intervalo)) {
267                 $intervalo->fusionar($i);
268             } else {
269                 if($i->inicio->greater($intervalo->inicio) && ! $insertado) {
270                     array_push($n_intervalos, $intervalo);
271                     $insertado = true;
272                 }
273                 array_push($n_intervalos, $i);
274             }
275         }
276         if(! $insertado )
277             array_push($n_intervalos,$intervalo);
278         $this->intervalos = $n_intervalos;
279         return true;
280     }
281
282     /**
283      * Saca.
284      */
285     function sacarBanda($banda)
286     {
287         foreach($banda->intervalos as $i)
288             $this->sacarIntervalo($i);
289     }
290
291     /**
292      * Saca un intervalo de una banda horaria.
293      */
294     function sacarIntervalo($intervalo)
295     {
296         // Si el intervalo está vacío, no hace nada.
297         $dur = $intervalo->getDuracion();
298         if ($dur->isEmpty()) {
299             return true;
300         }
301         $n_intervalos = array();
302         // recorre el vector de intervalos
303         foreach( $this->intervalos as $i ) {
304             if($i->seSuperpone($intervalo)) {
305                 $a = $i->cortar($intervalo);
306                 $d = $a->getDuracion();
307                 if($d->toSeconds() > 0) {
308                     $n_intervalos[] = $a;
309                 }
310                 $d = $i->getDuracion();
311                 if($d->toSeconds() > 0) {
312                     $n_intervalos[] = $i;
313                 }
314             } else {
315                 $n_intervalos[] = $i;
316             }
317         }
318         $this->intervalos = $n_intervalos;
319         return true;
320
321     }
322
323     /**
324      * Saca.
325      */
326     function sacarTiempo($t)
327     {
328         $n_int = array();
329         while(count($this->intervalos) > 0) {
330             $int = array_shift($this->intervalos);
331             if($t->toSeconds() > 0) {
332                 $d = $int->getDuracion();
333                 if($d->greater($t)) {
334 #con cortar alcanza
335                     $ini = new MECON_Tiempo_Hora();
336                     $ini->copy($int->inicio);
337                     $ini->add($t);
338                     /*TODO guardar este tiempo como rechazado*/
339                     $int->cortar($ini);
340                     $t->setFromSeconds(0);
341                 } else {
342 #con cortar no alcanza y hay que sacar...
343                     $t->subtract($int->getDuracion());
344                     /*TODO guardar int como rechazado*/
345                 }
346             }
347             $n_int[] = $int;
348         }
349         $this->intervalos = $n_int;
350     }
351
352     /**
353      * Chequea si el intervalo pedido esta cubierto por la banda, si faltan
354      *  horas en la banta se retorna el tiempo que falta
355      *
356      * @return Date_Span el periodo faltante
357      */
358     function chequearIntervalo($intervalo)
359     {
360         $t = new MECON_Tiempo_Hora();
361         foreach ($this->intervalos as $i)
362             $t->add($i->superponer($intervalo));
363         $d = $intervalo->getDuracion();
364         $d->subtract($t);
365         return $d;
366     }
367
368     /**
369      * Chequea si la banda(parametro) esta cubierto por la banda(this),
370      * si faltan horas en la banda(this) para llegar a banda(parametro)
371      * se retorna el tiempo que falta
372      *
373      * @return Date_Span el periodo faltante
374      */
375     function chequearBanda($banda)
376     {
377         $f = new MECON_Tiempo_Hora();
378         foreach ($banda->intervalos as $i)
379             $f->add($this->chequearIntervalo($i));
380         return $f;
381     }
382
383
384     /**
385      * Devuelve una representacion del objeto como un string.
386      *
387      * @return string Representacion del objeto.
388      */
389     function toString()
390     {
391         $s = '';
392         $t = count($this->intervalos);
393         for ($n = 0; $n < ($t - 1); $n++) {
394             $s .= "intervalo $n: [" . $this->intervalos[$n]->toString() . '] | ';
395         }
396         $n = $t - 1;
397         if ($n != -1) {
398             $s .= "intervalo $n: [" . $this->intervalos[$n]->toString() . ']';
399         }
400         return $s;
401     }
402
403     function getIntervalos()
404     {
405         return $this->intervalos;
406     }
407
408     /**
409      * Corta una banda, devolviendo la banda previa al punto de corte.
410      *
411      * La banda actual queda con los intervalos posteriores al punto de corte
412      * y se devuelve la banda con los intervalos anteriores.
413      * El punto de corte puede ser tanto una hora como un intervalo.
414      *
415      * @param mixed $c Donde cortar.
416      *
417      * @return object Banda Bnada anterior al punto de corte.
418      */
419     function cortar($c)
420     {
421         $b = $this->__clone();
422         $b->intervalos = array();
423         $intervalos = array();
424         foreach ($this->intervalos as $i) {
425             $a = $i->cortar($c);
426             $da = $a->getDuracion();
427             if (!$da->isEmpty()) {
428                 $b->agregarIntervalo($a);
429             }
430             $di = $i->getDuracion();
431             if (!$di->isEmpty()) {
432                 $intervalos[] = $i;
433             }
434         }
435         $this->intervalos = $intervalos;
436         return $b;
437     }
438
439     /**
440      * Devuelve el timpo total que contiene la banda.
441      *
442      * @return object Date_Span Tiempo total.
443      */
444     function total()
445     {
446         $t = new Date_Span;
447         foreach ($this->intervalos as $i) {
448             $t->add($i->getDuracion());
449         }
450         return $t;
451     }
452
453     /**
454      * Alias de Banda::total() para compatibilidad con Intervalo.
455      *
456      * @return object Date_Span Tiempo total.
457      */
458     function getDuracion()
459     {
460         return $this->total();
461     }
462
463     /**
464      * Chequea si el período pasado como argumento se superpone con la banda.
465      * @param $periodo Puede ser un MECON_Tiempo_Intervalo o MECON_Tiempo_Banda.
466      * @return true si se superpone, false si no.
467      */
468     function seSuperpone($periodo)
469     {
470         $intervalos = array($periodo);
471         if (is_a($periodo, 'mecon_tiempo_banda')) {
472             $intervalos = $periodo->intervalos;
473         }
474         foreach ($intervalos as $i) {
475             if ($i->seSuperpone($this->intervalos)) {
476                 return true;
477             }
478         }
479         return false;
480     }
481
482     /**
483      * Resetea la banda.
484      */
485     function flush()
486     {
487         $this->intervalos = array();
488     }
489
490     function copy($b)
491     {
492         $this->flush();
493         foreach ($b->intervalos as $i) {
494             $this->intervalos[] = $i->__clone();
495         }
496     }
497
498     function __clone()
499     {
500         $class = get_class($this);
501         $b = new $class;
502         $b->copy($this);
503         return $b;
504     }
505
506 }
507
508 ?>