--
--
-- package/jabber/sql/oracle/jabber-create.sql
-- @author Luis Mosteiro Fernandez
--
--

create table jb_services (
			  service	 varchar2(255) primary key,
			  pretty_name    varchar2(255),
				-- active_check_p to control whether service is avaiable (t) or not (f)
			  active_check_p char check(active_check_p in ('t','f'))
			 );


insert into jb_services (service , pretty_name , active_check_p) values ('jabber' , 'Jabber' , 't');
insert into jb_services (service , pretty_name , active_check_p) values ('aim' , 'AIM' , 't');
insert into jb_services (service , pretty_name , active_check_p) values ('yahoo' , 'Yahoo' , 't');
insert into jb_services (service , pretty_name , active_check_p) values ('msn' , 'MSN' , 't')';
insert into jb_services (service , pretty_name , active_check_p) values ('icq' , 'ICQ' , 't');



-- Screen
-- Definition as an object
-- Screen saves every screenname, it can be taken as a buddylist
-- users within the OACS System can have several screens, because they can be member in different im-systems
-- moreover the screens of external users are stored in this table
-- implementation as object, because it is imaginable to put a permission
-- on the screenname so not everyone can add this screen to his buddylist

begin
acs_object_type.create_type (
supertype      => 'acs_object',
object_type    => 'jb_screen',
pretty_name    => 'Screen',
pretty_plural  => 'Screens',
table_name     => 'JB_SCREENS',
id_column      => 'SCREEN_ID'
);
end;
/
show errors;


declare
	attr_id acs_attributes.attribute_id%TYPE;
begin
	attr_id := acs_attribute.create_attribute (
	object_type	=> 'jb_screen',
	attribute_name	=> 'user_id',
	pretty_name	=> 'User ID',
	pretty_plural	=> 'User IDs',
	datatype	=> 'integer'
	);

	attr_id := acs_attribute.create_attribute (
	object_type     => 'jb_screen',
	attribute_name  => 'im_screen_name',
	pretty_name     => 'IM Screen Name',
	pretty_plural   => 'IM Screen Names',
	datatype        => 'string'
	);

	attr_id := acs_attribute.create_attribute (
	object_type     => 'jb_screen',
	attribute_name  => 'service',
	pretty_name     => 'Service',
	pretty_plural   => 'Services',
	datatype        => 'string'
	);

	attr_id := acs_attribute.create_attribute (
	object_type     => 'jb_screen',
	attribute_name  => 'status',
	pretty_name     => 'Status',
	pretty_plural   => 'Status',
	datatype        => 'string'
	);

	attr_id := acs_attribute.create_attribute (
	object_type     => 'jb_screen',
	attribute_name  => 'away_msg',
	pretty_name     => 'Away_Message',
	pretty_plural   => 'Away_Messages',
	datatype        => 'string'
	);

	attr_id := acs_attribute.create_attribute (
	object_type     => 'jb_screen',
	attribute_name  => 'resourc',
	pretty_name     => 'Resource',
	pretty_plural   => 'Resources',
	datatype        => 'string'
	);

	attr_id := acs_attribute.create_attribute (
	object_type     => 'jb_screen',
	attribute_name  => 'refcount',
	pretty_name     => 'Reference_Count',
	pretty_plural   => 'Reference_Counts',
	datatype        => 'integer'
	);
end;
/
show errors;

create table jb_screens (
			screen_id       integer primary key references acs_objects(object_id),
				-- user_id is null, if the user is not member of the OACS
			user_id	 	integer references users(user_id), 
			im_screen_name  varchar2(255),  
			service         varchar2(255) references jb_services(service) ,
			status          varchar2(255),
			away_msg        varchar2(4000),
			resourc         varchar2(255),
			refcount        integer,
			unique (im_screen_name , service)
			);

create or replace package jb_screen
as

function new (
	screen_id		in jb_screens.screen_id%TYPE default null,
	user_id			in jb_screens.user_id%TYPE default null,
	im_screen_name		in jb_screens.im_screen_name%TYPE default null,
	service			in jb_screens.service%TYPE default null,
	status			in jb_screens.status%TYPE default null,
	away_msg		in jb_screens.away_msg%TYPE default null,
	resourc			in jb_screens.resourc%TYPE default null,
	refcount		in jb_screens.refcount%TYPE default null,
	object_type		in acs_object_types.object_type%TYPE default 'jb_screen',
	creation_date		in acs_objects.creation_date%TYPE default sysdate,
	creation_user		in acs_objects.creation_user%TYPE default null,
	creation_ip		in acs_objects.creation_ip%TYPE default null,
	context_id		in acs_objects.context_id%TYPE default null
) return jb_screens.screen_id%TYPE;

procedure delete (
	screen_id	in jb_screens.screen_id%TYPE
);
end jb_screen;
/
show errors





create or replace package body jb_screen
as

function new (
	screen_id		in jb_screens.screen_id%TYPE default null,
	user_id			in jb_screens.user_id%TYPE default null,
	im_screen_name		in jb_screens.im_screen_name%TYPE default null,
	service			in jb_screens.service%TYPE default null,
	status			in jb_screens.status%TYPE default null,
	away_msg		in jb_screens.away_msg%TYPE default null,
	resourc			in jb_screens.resourc%TYPE default null,
	refcount		in jb_screens.refcount%TYPE default null,
	object_type		in acs_object_types.object_type%TYPE default 'jb_screen',
	creation_date		in acs_objects.creation_date%TYPE default sysdate,
	creation_user		in acs_objects.creation_user%TYPE default null,
	creation_ip		in acs_objects.creation_ip%TYPE default null,
	context_id		in acs_objects.context_id%TYPE default null
) return jb_screens.screen_id%TYPE
is
	v_screen_id integer;
begin
	v_screen_id := acs_object.new (
	object_id	=> screen_id,
	object_type	=> object_type,
	creation_date	=> creation_date,
	creation_user	=> creation_user,
	creation_ip	=> creation_ip,
	context_id	=> context_id
	);


insert into jb_screens
	(screen_id, user_id, im_screen_name, service, status, away_msg, resourc, refcount)
values
	(v_screen_id, user_id, im_screen_name, service, status, away_msg, resourc, refcount);


return v_screen_id;
end new;

procedure delete (
	screen_id	in jb_screens.screen_id%TYPE
)
is
begin
	delete from jb_screens
	where screen_id = jb_screen.delete.screen_id;

	acs_object.delete(screen_id);
end delete;

end jb_screen;
/
show errors;


-- jb_user_jabber_information
-- this table stores jabber login information for each user

create table jb_user_jabber_information (
			user_id 	 integer primary key references users(user_id),
			jabber_regstate  char(2),
			jabber_passwd	 varchar2(16),	
			autologin	 char(2) check (autologin in ('t','f'))
			);

-- jb_subscription_request


create table jb_subscription_requests (
			-- screen is a full Jabber-ID
			screen            varchar2(255) primary key,
			asked             date
			);
-- jb_message_log
-- log table for messages

create sequence jb_message_log_seq start with 1;

create table jb_message_log (
			message_id   integer primary key,
			user_id      integer references users(user_id),
			message      VARCHAR2(4000),
			send         date,
			conn_state   varchar(2),
				-- receive jabber_id 
			receive_jid  varchar2(1000)  
			); 

-- jb_xml_to_send

create table jb_xml_to_send ( 
			xml     blob,
			stored  date
			);




-- jb_friends
-- this table stores information for all user friends (whether external or internal friends)

create table jb_friends (
			user_id		    integer references users(user_id),
			friend_screen_id    integer references jb_screens(screen_id),
			friend_first_name   varchar2(255),
			friend_last_name    varchar2(255),
			primary key(user_id , friend_screen_id)
			);


-- Conference Room
-- implementation as object to use the permissioning system


begin
acs_object_type.create_type (
supertype      => 'acs_object',
object_type    => 'jb_conference_room',
pretty_name    => 'Conference Room',
pretty_plural  => 'Conference Rooms',
table_name     => 'JB_CONFERENCE_ROOMS',
id_column      => 'room_id'
);
end;
/
show errors;



declare
attr_id acs_attributes.attribute_id%TYPE;
begin
	attr_id := acs_attribute.create_attribute (
	object_type     => 'jb_conference_room',
	attribute_name  => 'creator_jabber_id',
	pretty_name     => 'Creator Jabber ID',
	pretty_plural   => 'Creator Jabber IDs',
	datatype        => 'string'
	);
	
	attr_id := acs_attribute.create_attribute (
	object_type	=> 'jb_conference_room',
	attribute_name  => 'name',
	pretty_name     => 'Name',
	pretty_plural	=> 'Names',
	datatype	=> 'string'
	);
	
	attr_id := acs_attribute.create_attribute (
	object_type	=> 'jb_conference_room',
	attribute_name	=> 'description',
	pretty_name	=> 'Description',
	pretty_plural	=> 'Descriptions',
	datatype	=> 'string'
	);
end;
/	
show errors;

create table jb_conference_rooms ( 
			room_id                 integer primary key references acs_objects(object_id),
			creator_jabber_id       varchar2(255),
				-- jabber_id of the creator
				-- only users having a jabber_id can create a conference room
				-- jabber_ids look like: screen_name_of_the_service@service_name.jabber_server
				-- therefore it has to be varchar
			name                    varchar(100) unique,  
			description             varchar(1000),
                        type                    varchar2(15)
			);


create or replace package jb_conference_room
as

function new (
	room_id			in jb_conference_rooms.room_id%TYPE default null,
	creator_jabber_id	in jb_conference_rooms.creator_jabber_id%TYPE default null,
	name			in jb_conference_rooms.name%TYPE default null,
	description		in jb_conference_rooms.description%TYPE default null,
	object_type		in acs_object_types.object_type%TYPE default 'jb_conference_room',
	creation_date		in acs_objects.creation_date%TYPE default sysdate,
	creation_user		in acs_objects.creation_user%TYPE default null,
	creation_ip		in acs_objects.creation_ip%TYPE default null,
	context_id		in acs_objects.context_id%TYPE default null
) return jb_conference_rooms.room_id%TYPE;

procedure delete (
	room_id	in jb_conference_rooms.room_id%TYPE
);
end jb_conference_room;
/
show errors


create or replace package body jb_conference_room
as

function new (
	room_id			in jb_conference_rooms.room_id%TYPE default null,
	creator_jabber_id	in jb_conference_rooms.creator_jabber_id%TYPE default null,
	name			in jb_conference_rooms.name%TYPE default null,
	description		in jb_conference_rooms.description%TYPE default null,
	object_type		in acs_object_types.object_type%TYPE default 'conference_room',
	creation_date		in acs_objects.creation_date%TYPE default sysdate,
	creation_user		in acs_objects.creation_user%TYPE default null,
	creation_ip		in acs_objects.creation_ip%TYPE default null,
	context_id		in acs_objects.context_id%TYPE default null
) return jb_conference_rooms.room_id%TYPE
is
v_room_id integer;
begin
v_room_id := acs_object.new (
	object_id	=> room_id,
	object_type	=> object_type,
	creation_date	=> creation_date,
	creation_user	=> creation_user,
	creation_ip	=> creation_ip,
	context_id	=> context_id
	);


insert into jb_conference_rooms
	(room_id, creator_jabber_id, name, description)
values
	(v_room_id, creator_jabber_id, name, description);


return v_room_id;
end new;

procedure delete (
	room_id	in jb_conference_rooms.room_id%TYPE
)
is
begin
	delete from jb_conference_rooms
	where room_id = jb_conference_room.delete.room_id;

acs_object.delete(room_id);
end delete;

end jb_conference_room;
/
show errors;






-- Conference Room Thread
-- no implementation as object
-- user permission controlled for entire room, not for a single thread 




create sequence jb_conference_room_threads_seq start with 1;

create table jb_conference_room_threads (
	thread_id         integer primary key,
	room_id	          integer not null references jb_conference_rooms(room_id),
	start_time	  date,	
	end_time          date,
	subject           varchar2(200),
	description       varchar2(1000),
	creator_jabber_id varchar2(255),
	creator_user_id   integer references users(user_id)                                                      
	);


-- Maps Rooms to the threads where the dicussion Started, for storing the structure of a discussion on an major topic, that maybe
-- displayed later .



create  table jb_room_start_from_thread (
                                                  thread_id     not null references jb_conference_room_threads(thread_id),
                                                  room_id       not null references jb_conference_rooms(room_id),
                                                  primary key(thread_id , room_id)
                                                  );



-- maps a Room to a Party so oher users/groups can posibly browes the discussions.

create table jb_room_party_map (
                                party_id      not null references parties(party_id),
                                room_id       not null references  jb_conference_rooms(room_id),
                                primary key (party_id , room_id) 
	                       );

-- stores the group_id's that have access to the conference system
-- conference_only_p indicates if this group was created for conferencing ('t') and we (jabber admin) may be allowed to change it,
-- or if this groups originated some where else in the package.


create table jb_conference_groups (
                                  group_id primary key references groups(group_id),
				  conference_only_p  char(1) default 't' check (conference_only_p in ('t' , 'f') ),
                                  default_room_id unique references jb_conference_rooms(room_id)
                                  );  


create table jb_groups_blocked_conference(
	                                    group_id primary key references groups(group_id)
				             );


-- IMPORTANT
-- creation of a dummy conference room and conference room thread, so the C-module can work!
-- C-module has an own sequence for the threads, but it needs to have a start point, so the database has to provide this start point




create table jb_conference_protocols (
	jabber_id   varchar2(100),
	user_id	    integer references users(user_id),
	message     varchar2(1000),
	stored      date,
	room_id     integer references jb_conference_rooms(room_id),
	thread_id   integer references jb_conference_room_threads(thread_id)   
	) ;

create index jb_conference_protocols_id on jb_conference_protocols(room_id, thread_id);





-- Now come some PL/SQL procedures and functions, which are used by the c-modules

-- validate whether user is registered

create or replace procedure jb_reg_validation(screen_in IN varchar2 , regstate IN varchar2)  is
          v_user_id jb_screens.user_id%TYPE;     
    BEGIN 
     v_user_id := v_user_id;     
 
    END;
  

/
 
show errors
 
-- Update the online state of a user
create or replace procedure jb_update_status (status_in IN varchar2 , resourc_in IN varchar2 , screen_in IN varchar2 , service_in IN varchar2) 
IS
service_long varchar2(255);
BEGIN

   IF service_in = 'a' THEN
	service_long := 'aim' ;
   END IF;
   IF service_in = 'j' THEN
	service_long := 'jabber' ;
   END IF;
   IF service_in = 'm' THEN
	service_long := 'msn' ;
   END IF;
   IF service_in = 'r' THEN
	service_long := 'irc' ;
   END IF;
   IF service_in = 'i' THEN
	service_long := 'icq' ;
   END IF;
   IF service_in = 'y' THEN
	service_long := 'yahoo' ;
   END IF;

	
   update jb_screens SET status = status_in , resourc= resourc_in WHERE LOWER(im_screen_name)=LOWER(screen_in) and service = service_long;
 
   commit;

END;

/

show errors


-- Clear the online states of every one on Login or Logout

create or replace procedure jb_clear_status 
IS
Begin
update jb_screens SET status='offline' , resourc='offline';
commit;
End;
/
show errors
 



--checks if jid_in is in the table of the subscription requests , we store them in ther because we may have to wait 
--for a while till some one (jid_in) answers the request, it returns 0 in case there is nothing known about jid_in
--or n > 0  in case there is something known about jid_in 
     
create or replace function jb_subscription_check (jid_in IN varchar2)
return integer
AS r_exists integer;
BEGIN
 r_exists := 0;
 select count(screen) into r_exists from jb_subscription_requests where lower(screen) = lower(jid_in) ;

 return r_exists;
END;

/

show errors




--inserts a new subscription request

create or replace procedure jb_subscription_insert(jid_in IN varchar2)
IS
BEGIN
    insert into jb_subscription_requests (screen , asked ) values ( jid_in , sysdate);
    commit;
END;

/
show errors

--removes a certain subscription request

create or replace procedure jb_subscription_del (jid_in IN varchar2)
IS
BEGIN
          delete from jb_subscription_requests where lower(screen) = lower(jid_in);
          commit;
END;

/
show errors




--Find the user_id to a given jid, when someone invites us through  sending a jabber invite from his jabber client:

create or replace function jb_get_user_id (screen_in IN varchar2) return integer AS r_user_id integer;  

BEGIN

        Select persons.person_id INTO r_user_id
        FROM persons,  jb_screens
        WHERE persons.person_id = jb_screens.user_id
        AND jb_screens.service = 'jabber'
        AND jb_screens.im_screen_name = screen_in;

        return r_user_id;

END;

/

show errors





--Get the jid from a given user_id 

create or replace function jb_get_jid (user_id_in IN integer) return VARCHAR2 AS r_jid varchar2(150);
BEGIN
  
 Select sn.im_screen_name INTO r_jid 
 FROM jb_screens sn 
 WHERE sn.user_id = user_id_in 
 AND sn.service = 'jabber';

 return r_jid;

END;
/
show errors




--if a room is destroyed or the topic changes, the  discussion on the last topic (thread) ends ,insert this time as thread end time:
 

create or replace procedure jb_conference_thread_finish(thread_id_in IN integer)
IS
BEGIN
     update jb_conference_room_threads set end_time = sysdate where thread_id = thread_id_in;
     commit;
END;
/
show errors





--When a room starts or the  topic changes a new Thread is created :


create or replace procedure jb_conference_thread_new (thread_id_in IN integer ,  room_id_in IN integer , subject_in IN varchar2 , creator_jid_in IN varchar2 , creator_user_id_in IN integer)
IS

BEGIN

 IF creator_user_id_in = 0 THEN

   insert into jb_conference_room_threads (thread_id , room_id , start_time , subject , creator_jabber_id )
   values (thread_id_in , room_id_in , sysdate , subject_in , creator_jid_in );

 ELSE
  
   insert into jb_conference_room_threads (thread_id , room_id , start_time , subject , creator_jabber_id , creator_user_id )
   values (thread_id_in , room_id_in , sysdate , subject_in , creator_jid_in , creator_user_id_in);

 END IF;

 commit;  

END;

/
show errors



--When a message is received from a conference room it is stored in the db:

 
create or replace procedure jb_conference_message(jid_in IN varchar2 , message_in IN varchar2 , room_id_in IN integer , thread_id_in IN integer , user_id_in IN integer)
IS
BEGIN

  IF user_id_in = 0 THEN
    
       insert into jb_conference_protocols (jabber_id , message , stored , room_id , thread_id )
       values (jid_in , message_in , sysdate , room_id_in , thread_id_in );

  ELSE 

      insert into jb_conference_protocols (jabber_id , user_id , message , stored , room_id , thread_id)
      values  (jid_in , user_id_in , message_in , sysdate , room_id_in , thread_id_in );

  END IF;

 COMMIT;

END;
/
show errors;






-- When a room is created (it is maybe recreated every Monday at 8:00 ) see if we already have a room_id for that room.

create or replace function jb_conference_room_check(room_name_in IN varchar2 ) return integer AS r_room_id integer;
BEGIN
      r_room_id := -1;

      select room_id  INTO r_room_id from jb_conference_rooms where lower(name)=lower(room_name_in);

     return r_room_id;

END;
/
show errors





-- When a room is fully new created , create a new Table entry. We do not use the room_id given by the c-module due to the fact that 
-- conference_room is implemented as object


create or replace procedure jb_conference_rooms_new ( user_id_in IN integer , creator_jid_in IN varchar2 , name_in IN varchar2 , description_in IN varchar2) 
IS

BEGIN
  
  
  IF user_id_in = 0 THEN


	declare
	id integer;
	begin
	id := jb_conference_room.new (
		creator_jabber_id => creator_jid_in ,
		name => name_in ,
		description => description_in ,
		object_type => 'jb_conference_room'
		);
	end;


  ELSE

	declare
	id integer;
	begin
	id := jb_conference_room.new (
		creator_jabber_id => creator_jid_in ,
		name => name_in ,
		description => description_in ,
		object_type => 'jb_conference_room' ,
		creation_user => user_id_in
		);
	end;

		
     
  END IF;


 COMMIT;

END;

/
show errors



-- Get the next room_id. This procedure is used in the database to get a new room_id, but it takes the ACS3.x datamodel as basis
-- In the OACS4.x datamodel conference_room is implemented as object, so we do not have a sequence, but we do not want the c-module
-- generate an error, so we give him an integer back, but we do not use this room_id (look above)

create or replace function jb_conference_next_room_id return integer AS r_room_id integer;
BEGIN
  SELECT count(*) INTO r_room_id FROM jb_services;
 
  return r_room_id;
END;
/
show errors 



-- Get the next thread_id

create or replace function jb_conference_next_thread_id return integer AS r_thread_id integer;
BEGIN
  
  SELECT  jb_conference_room_threads_seq.nextval INTO r_thread_id from dual;
  
  return r_thread_id;

END;

/
show errors 

@jabber-notification-create.sql