CREATE TABLE t_solicitante
(
  id_solicitante serial NOT NULL,
  dni_tipo numeric(3),
  dni_nro character varying(8),
  apellido character varying(150),
  nombre character varying(150),
  fecha_nac date,
  id_sexo numeric(3),
  domicilio character varying,
  id_localidad integer,
  fecha_hora_aud timestamp without time zone DEFAULT now(),
  id_usuario integer,
  
  CONSTRAINT key_sol PRIMARY KEY (id_solicitante)
)
WITH OIDS;

CREATE TABLE t_feriados
(
  id_feriado serial NOT NULL,
  fecha_feriado date,
  descripcion character varying(150),
  fecha_hora_aud timestamp without time zone DEFAULT now(),
  usuario_aud character varying(20),
  CONSTRAINT t_feriados_pkey PRIMARY KEY (id_feriado)
)
WITHOUT OIDS;

CREATE TABLE t_turnos
(
  id_turno integer NOT NULL DEFAULT nextval('t_turnos_id_turno_seq1'::regclass),
  fecha_turno date,
  hora_turno time without time zone,
  num_turno integer,
  estado integer,
  pg_usuario character varying DEFAULT "current_user"(),
  fecha_hora timestamp without time zone DEFAULT now(),
  id_usuario integer,
  id_turneable integer,
  id_tipo_turno integer,
  CONSTRAINT t_turnos_pkey PRIMARY KEY (id_turno)
)
WITHOUT OIDS;

CREATE TABLE t_turnos_parametros
(
  id_parametros serial NOT NULL,
  fecha_desde date,
  fecha_hasta date,
  hora_desde time without time zone,
  hora_hasta time without time zone,
  puestos integer,
  tiempo_atencion integer,
  intervalo integer,
  apartirde integer,
  cant_turnos integer,
  fin_de_semana integer,
  id_tipo_turno integer,
  id_usuario integer,
  pg_usuario character varying DEFAULT "current_user"(),
  fecha_hora timestamp without time zone DEFAULT now(),
  CONSTRAINT tturnos_parametros_pkey PRIMARY KEY (id_parametros),
  CONSTRAINT fk_idusuario FOREIGN KEY (id_usuario)
      REFERENCES sistema.t_usuarios (idusuario) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITHOUT OIDS;

CREATE TYPE d_turno AS
   (idturno integer,
    fecha date,
    hora time without time zone,
    numero integer,
    estado integer,
    fechahora timestamp without time zone,
    idusuario integer,
    idturneable integer,
    idtipoturno integer);

    
CREATE OR REPLACE FUNCTION f_turnos_asignar(p_id_turno integer, p_idturneable integer, p_idusuario integer, p_tabla character varying)
  RETURNS integer AS
$BODY$
declare
	estado integer;
	c integer;
	
begin
	/* Asigna el turno p_id_turno al Turneable p_idturneable */

	
	execute 'select estado from '||p_tabla ||' where id_turno='||p_id_turno ||' for update' into estado;
	if estado=0 OR estado=1 then
		execute 'update '||p_tabla ||' set estado=2, id_turneable='|| p_idturneable ||',id_usuario='||p_idusuario||',pg_usuario=CURRENT_USER, fecha_hora=now() where id_turno=' ||p_id_turno;
		GET DIAGNOSTICS c= ROW_COUNT;
		if (c>0) then
			return 1;
		else
			return 0;
		end if;
	else
		return 0;
	end if;
end;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
  
CREATE OR REPLACE FUNCTION f_turnos_dame_parametros(p_turno_tipo integer, p_cuando date, tabla_parametros character varying)
  RETURNS SETOF t_turnos_parametros AS
$BODY$declare
-- Obtengo los parametros para un turno_tipo y una fecha determinada
 resultado t_turnos_parametros%ROWTYPE;
begin
 for resultado in 
execute 'select *     from '||tabla_parametros||' p 
    where p.id_tipo_turno='||p_turno_tipo||'  and p.fecha_desde <= '''||p_cuando||''' and (p.fecha_hasta >='''||p_cuando||''' or p.fecha_hasta is null)'
 loop
	return next resultado; 
 end loop;
end;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
  
CREATE OR REPLACE FUNCTION f_turnos_guardarparametros(p_tipo_turno integer, p_fecha_dsd date, p_fecha_hst date, p_hora_dsd time without time zone, p_hora_hst time without time zone, p_intervalo smallint, p_t_atencion integer, p_apartirde integer, p_fin_de_semana integer, p_puestos integer, p_id_usuario smallint, tabla_parametros character varying, tabla_turnos character varying)
  RETURNS integer AS
$BODY$
declare
	r_t_turnosparam t_turnos_parametros%rowtype;
	wid_turnos_param bigint;
	i integer ;
begin	
	set datestyle = 'sql,dmy';
	-- nuevo ID
	execute 'select nextval(\''||tabla_parametros||'_idparametros_seq\')'  into wid_turnos_param ;
	if(wid_turnos_param>0) then

		-- inserto los parametros
		--insert into tturnos_parametros (idparametros, fecha_desde, fecha_hasta, hora_desde, hora_hasta, puestos, tiempo_atencion, fechahora, fin_de_semana, idusuario, pgusuario) 
		--values (wid_turnos_param,desde, hasta, hora_dsd, hora_hst, cant_puestos, periodicidad,  now(),op_fin_d_semana,id_usuario, current_user);

		execute 'insert into '||tabla_parametros ||'(id_parametros, fecha_desde, fecha_hasta, hora_desde, hora_hasta,intervalo,apartirde, fecha_hora, fin_de_semana,id_tipo_turno,puestos,tiempo_atencion, id_usuario, pg_usuario) 
		values ('||wid_turnos_param||',\''||p_fecha_dsd||'\',\''||p_fecha_hst||'\',\''||p_hora_dsd||'\',\''||p_hora_hst||'\','|| p_intervalo||','|| p_apartirde||',now(),'||p_fin_de_semana||','||p_tipo_turno||','||p_puestos||','||p_t_atencion||','||p_id_usuario||', current_user)';


		execute 'select * from '|| tabla_parametros ||' where id_parametros = '|| wid_turnos_param into r_t_turnosparam ;

		-- exploto los paramatros
		perform f_turnosexplotar(r_t_turnosparam, tabla_turnos);
	return 1;
	else
		RAISE EXCEPTION 'No se pede generar nuevo idparametro';
	return 0;
	end if;
	
end;$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
  
CREATE OR REPLACE FUNCTION f_turnos_hay(p_turno_tipo integer, p_tabla character varying)
  RETURNS integer AS
$BODY$
declare
	idturno integer;
	c integer;
	resultado t_turnos_parametros%ROWTYPE;
begin
	/* Reserva el primer turno disponible a partir de "p_lapso" dias a partir de la fecha actual */
	perform f_turnos_refresh(p_tabla);
        execute 'select * from f_turnos_dame_parametros('||p_turno_tipo||',now()::date,'||p_tabla||')' into resultado;
	if(resultado.id_parametros is not null) then
		execute 'select id_turno from '|| p_tabla ||' where id_turno=(select f_turnos_siguiente('||p_turno_tipo||','||resultado.apartirde ||',\''|| p_tabla||'\')) ' into idturno;
		if(idturno>0) then
			return idturno;
			else
				return 0;
			end if;
	else
		return 0;
	end if;
	

end;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
  
CREATE OR REPLACE FUNCTION f_turnos_ofid(id integer)
  RETURNS SETOF d_turno AS
$BODY$
/* New function body */

DECLARE
r public.d_turno;

BEGIN
  
      select id_turno as idturno ,
  fecha_turno as fecha,
  hora_turno as hora,
  num_turno as numero,
  estado as estado,
  fecha_hora as fechahora,
  id_usuario as idusuario,
  id_turneable as idturneable,
  id_tipo_turno as idtipoturno  from public.t_turnos t where t.id_turno=$1  into r ;
      return next r;
end
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
  
CREATE OR REPLACE FUNCTION f_turnos_refresh(p_tabla character varying)
  RETURNS integer AS
$BODY$
declare
	i integer;
	c integer;
begin
	/*
	Pone en 1 el campo disponible de la tabla tturnos_credito de los registros que lo tienen en 1 y pasaron 5 minutos
	 dedesde la hora registrada en el campo fechahora

		RETORNA
			1 si se modifico algun registro
			0 si no se modifico algun registro
	*/
	execute 'update ' || p_tabla || ' 
	set estado=0,fecha_hora=now(), id_usuario=NULL
	where id_turno in(
		select id_turno from '|| p_tabla ||' tc where estado=1 and 
	(select (5-(select extract(epoch from ((select now()) - tc.fecha_hora::timestamp)) / 60)))<0
	)';
	--select * from tturnos_credito
	GET DIAGNOSTICS c= ROW_COUNT;
	if (c>0) then
		return 1;
	else
		return 0;
	end if;

end;$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
  
CREATE OR REPLACE FUNCTION f_turnos_reservar(p_turno_tipo integer, p_tabla character varying, p_tabla_parametros character varying, p_id_usuario integer)
  RETURNS integer AS
$BODY$
declare
	idturno integer;
	c integer;
	resultado t_turnos_parametros%ROWTYPE;
begin
	/* Reserva el primer turno disponible a partir de "p_lapso" dias a partir de la fecha actual */
	perform f_turnos_refresh(p_tabla);
        execute 'select * from f_turnos_dame_parametros('||p_turno_tipo||', now()::date,'''|| p_tabla_parametros ||''')' into resultado;
	if(resultado.id_parametros is not null) then
		execute 'select id_turno from '|| p_tabla ||' where id_turno=(select f_turnos_siguiente('||p_turno_tipo||','||resultado.apartirde ||','''|| p_tabla||''')) for update' into idturno;
		if(idturno>0) then
			execute 'update '||p_tabla||' set estado=1, id_usuario='||p_id_usuario||', fecha_hora=now() where id_turno='||idturno;
			GET DIAGNOSTICS c= ROW_COUNT;
			if (c>0) then
				return idturno;
			else
				return 0;
			end if;
		else
			return 0;
		end if;
	else
	  return 0;
	end if;

end;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
  
CREATE OR REPLACE FUNCTION f_turnos_siguiente(p_turno_tipo integer, p_lapso integer, p_tabla character varying)
  RETURNS integer AS
$BODY$
declare
	idturno integer;
begin
	/*
	Devuelve el id del primer turno disponible a partir de "p_lapso" dias a partir de la fecha actual
	*/
	execute 'select id_turno 
	from '|| p_tabla||'
	where (fecha_turno || \' \' || hora_turno)::timestamp =(
		select min((fecha_turno || \' \' || hora_turno)::timestamp) from '|| p_tabla||' where estado=0
			and fecha_turno>=(now()::date+('||p_lapso||'|| \' day\')::interval) and id_tipo_turno='||p_turno_tipo||'
	) and id_tipo_turno='||p_turno_tipo||' and id_turneable is null
	limit 1 for update ' into idturno ;
	return idturno;
end;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
  
CREATE OR REPLACE FUNCTION f_turnos_turneable_tieneturno(p_id_turneable integer, t_turneable character varying, t_tabla character varying)
  RETURNS SETOF d_turno AS
$BODY$
/* New function body */
DECLARE
r d_turno;
BEGIN

	 FOR r IN  execute 'select  tt.*
	from '||t_turneable||' ts	
	inner join '||t_tabla||' tt ON (tt.id_turneable=ts.id)
	where id=p_id_turneable'  LOOP
        
	return NEXT r;
      
	END LOOP;


	
END
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;

  
CREATE OR REPLACE FUNCTION f_turnosexplotar(t_parametro t_turnos_parametros, tabla_turnos character varying)
  RETURNS void AS
$BODY$
declare
	cturnos integer;
	cdias integer;
	dia_d_semana integer;
	v_incluyedia	boolean;
	fecha 		date;	
	hora 		time;
	divs 		integer;
	en_horario 	integer;
	new_id 		int4;
	c_esferiado	integer;
	num_turno	integer;
begin

set datestyle = 'sql,dmy';
cdias := (t_parametro.fecha_hasta - t_parametro.fecha_desde) + 1;
fecha := t_parametro.fecha_desde;

-- borra los libres
	
execute 'delete from '||tabla_turnos||' where id_turneable is null and 
	fecha_turno >=\''|| t_parametro.fecha_desde ||'\' and fecha_turno <=\''|| t_parametro.fecha_hasta ||'\' and
	hora_turno >= \''||t_parametro.hora_desde||'\' and hora_turno <= \''||t_parametro.hora_hasta ||'\' and
	id_tipo_turno='||t_parametro.id_tipo_turno||'';

for i in 1..cdias loop	
	--es feriado el dia o fin de semana?
	select  into dia_d_semana extract(dow from fecha);
	raise notice 'dia d semana: %', dia_d_semana;
	-- Controla que no sea feriado 
	c_esferiado	:= 0;

	select count(*) into c_esferiado from t_feriados where t_feriados.fecha_feriado = fecha;
	-- op_fin_d_semana, 
	-- Sab =6    Dom = 0
	-- valores:	0: Lunes a Viernes	Sab6no	Dom0no
	-- 		1: Lunes a Sabados 	6si 	0no
	--		2: sabados y domingos		6si 	0si
	v_incluyedia := true ;
	if t_parametro.fin_de_semana = 0 	and	(dia_d_semana = 0 or dia_d_semana = 6)		then	v_incluyedia := false; end if;
	if t_parametro.fin_de_semana = 1 	and	(dia_d_semana = 0)				then	v_incluyedia := false; end if;
	if t_parametro.fin_de_semana = 2 	and	(dia_d_semana = 0 or dia_d_semana = 6)		then	v_incluyedia := true; end if;
	if (c_esferiado = 0) and v_incluyedia then
		hora := t_parametro.hora_desde;
		num_turno:=0;
--si pongo <= da turnos hasta hora_hasta 'osea que tengo turno despues de hora hasta'
		while hora < t_parametro.hora_hasta loop
			-- cant de turnos disponibles en esa hora
								
			
			  execute 'select 	count(*)  from '|| tabla_turnos ||' tt
				where 		tt.hora_turno = \''|| hora ||'\'
					and 	tt.fecha_turno = \''||fecha ||'\'
					and tt.id_tipo_turno='||t_parametro.id_tipo_turno into cturnos  ;
			
			
			
			if cturnos < t_parametro.puestos then  
				cturnos := t_parametro.puestos - cturnos - 1;

				for nturno in 0..cturnos loop
					num_turno:=num_turno+1;
						--puedo usar como num de box a nturno
					execute 'insert into '||tabla_turnos||'(fecha_turno, hora_turno, num_turno,estado, fecha_hora, id_tipo_turno,id_usuario) 
					values 	(\''||fecha||'\',\''|| hora ||'\','|| num_turno ||', 0, now(),'|| t_parametro.id_tipo_turno ||','|| t_parametro.id_usuario ||')';
				end loop;	
			end if;
			--hora := hora + ('00:' || t_parametro.tiempo_atencion || ':00')::interval;
			hora := hora + (t_parametro.tiempo_atencion || ' min')::interval;
		end loop;
	end if;
	fecha := fecha + 1;
end loop;

return ;

end;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;