-- $Id: acs-sc-msg-types-create.sql,v 1.1.1.1 2002/07/09 17:34:58 rmello Exp $

begin

   acs_object_type.create_type (
        supertype => 'acs_object',
        object_type => 'acs_sc_msg_type',
	pretty_name => 'ACS SC Message Type',
        pretty_plural => 'ACS SC Message Types',
        table_name => 'acs_sc_msg_types',
        id_column => 'msg_type_id'
    );

end;
/
show errors

create table acs_sc_msg_types (
    msg_type_id		     integer
			     constraint acs_sc_msg_type_id_fk
			     references acs_objects(object_id)
			     on delete cascade
			     constraint acs_sc_msg_type_pk
			     primary key,
    msg_type_name	     varchar2(100)
			     constraint acs_sc_msg_type_name_un
			     unique
);


create table acs_sc_msg_type_elements (
    msg_type_id		     integer
			     constraint acs_sc_msg_type_el_mtype_id_fk
			     references acs_sc_msg_types(msg_type_id)
			     on delete cascade,
    element_name	     varchar2(100),
    element_msg_type_id	     integer
			     constraint acs_sc_msg_type_el_emti_id_fk
			     references acs_sc_msg_types(msg_type_id),
    element_msg_type_isset_p char(1) constraint acs_msg_type_el_set_p_ck
			     check (element_msg_type_isset_p in ('t', 'f')),
    element_pos		     integer
);

create or replace package acs_sc_msg_type
as

    function new (
        msg_type_name	 in acs_sc_msg_types.msg_type_name%TYPE,
	msg_type_spec	 in varchar2
     ) return acs_sc_msg_types.msg_type_id%TYPE;

    procedure delete (
        msg_type_id	 in acs_sc_msg_types.msg_type_id%TYPE default null,
	msg_type_name	 in acs_sc_msg_types.msg_type_name%TYPE default null
    );

    function get_id (
        msg_type_name	 in acs_sc_msg_types.msg_type_name%TYPE
    ) return acs_sc_msg_types.msg_type_id%TYPE;


    function get_name (
	msg_type_id	 in acs_sc_msg_types.msg_type_id%TYPE
    ) return acs_sc_msg_types.msg_type_name%TYPE;

    -- ask nd about name
    function parse_spec (
	msg_type_name	 in acs_sc_msg_types.msg_type_name%TYPE,
	msg_type_spec	 in varchar2
    ) return integer;

    function new_element (
	msg_type_name	 in acs_sc_msg_types.msg_type_name%TYPE,
	element_name	 in acs_sc_msg_type_elements.element_name%TYPE,
	element_msg_type_name		in acs_sc_msg_types.msg_type_name%TYPE,
	element_msg_type_isset_p	in acs_sc_msg_type_elements.element_msg_type_isset_p%TYPE,
	element_pos			in acs_sc_msg_type_elements.element_pos%TYPE
     ) return acs_sc_msg_types.msg_type_id%TYPE;

end acs_sc_msg_type;
/
show errors


create or replace package body acs_sc_msg_type
as

     function new (
        msg_type_name	in acs_sc_msg_types.msg_type_name%TYPE,
	msg_type_spec	in varchar2
     ) return acs_sc_msg_types.msg_type_id%TYPE
     is
	v_msg_type_id   integer;
	v_spec_parse_level integer;
     begin
        v_msg_type_id := acs_object.new(
		      object_type => 'acs_sc_msg_type'
		      );		    

        insert into acs_sc_msg_types (
	       msg_type_id,
	       msg_type_name
	       ) values (
	       v_msg_type_id,
	       msg_type_name
	       );

	v_spec_parse_level := acs_sc_msg_type.parse_spec(
			      msg_type_name,
			      msg_type_spec);

	return v_msg_type_id;

     end new;

     procedure delete (
         msg_type_id	 in acs_sc_msg_types.msg_type_id%TYPE default null,
	 msg_type_name	 in acs_sc_msg_types.msg_type_name%TYPE default null
     )
     is 
        v_msg_type_id	acs_sc_msg_types.msg_type_id%TYPE;
     begin

	if msg_type_name is not NULL
	then
	   v_msg_type_id := acs_sc_msg_type.get_id(msg_type_name);

	elsif msg_type_id is not NULL
	then
	   v_msg_type_id := msg_type_id;
	
	else
	   raise_application_error(-20000, 'no args supplied to sc_msg_type.delete');

	end if;

	delete from acs_sc_msg_types 
	       where msg_type_id = v_msg_type_id;

     end delete;

    function get_id (
        msg_type_name in acs_sc_msg_types.msg_type_name%TYPE
    ) return acs_sc_msg_types.msg_type_id%TYPE

    is 
       v_msg_type_id	acs_sc_msg_types.msg_type_id%TYPE;
    begin

	select msg_type_id into v_msg_type_id
	from acs_sc_msg_types 
	where msg_type_name = get_id.msg_type_name;

	return v_msg_type_id;

    end get_id;


    function get_name (
	msg_type_id   in acs_sc_msg_types.msg_type_id%TYPE
    ) return acs_sc_msg_types.msg_type_name%TYPE
    is	     
       v_msg_type_name	acs_sc_msg_types.msg_type_name%TYPE;
    begin
    
	select msg_type_name into v_msg_type_name
	from acs_sc_msg_types
	where msg_type_id = get_name.msg_type_id;

	return v_msg_type_name;
    end get_name;



    -- string processing in pl/sql is so much fun
    -- i'm sure there is a better way to go about this
    function parse_spec (
	msg_type_name in acs_sc_msg_types.msg_type_name%TYPE,
	msg_type_spec in varchar2
    ) return integer
    is
	v_element_pos	   integer;
	v_str_s_idx        integer; -- spec str pointers
	v_str_e_idx	   integer; 
	v_elem_idx	   integer; -- element str pointer
	v_str_len	   integer;
	v_element          varchar(200);
	v_element_type	   varchar(200);
	v_element_name	   varchar(200);
	v_element_msg_type_name     varchar(200);
	v_element_msg_type_isset_p  char(1);
	v_junk_msg_type_id integer; 
    begin

	-- oracle treats empty strings as nulls
	if msg_type_spec is null
	then		 
	   return 0;
	end if;
		

	v_element_pos := 1;
	v_str_e_idx := 1;

	while TRUE
	loop
	    -- string start check
	    if v_element_pos = 1
	    then
		v_str_s_idx := 1;
	    else	    
		v_str_s_idx := instr(msg_type_spec, ',', v_str_e_idx);	    
		
		if v_str_s_idx > 0 then
		   v_str_s_idx := v_str_s_idx + 1;
		end if;

	    end if;

	    v_str_e_idx := instr(msg_type_spec, ',', v_str_s_idx+1)-1;	

	    -- end of string check
	    if v_str_s_idx > 0 and v_str_e_idx <= 0
	    then
		v_str_e_idx := length(msg_type_spec);
	    end if;

	    -- dbms_output.put_line(v_str_s_idx || ' '|| v_str_e_idx || ' ' || v_element_pos);
	    -- dbms_output.new_line();

	    if v_str_s_idx > 0 
	    then

		v_element := substr(msg_type_spec, 
			            v_str_s_idx,
				    v_str_e_idx+1 - v_str_s_idx);

		v_elem_idx := instr(v_element, ':');

		if v_elem_idx > 0 
 		then
		    v_element_name := trim( substr(v_element, 1, v_elem_idx-1));
		    v_element_type := trim( substr(v_element, v_elem_idx+1));
		    
		    if (instr(v_element_type, '[',1,1) = length(v_element_type)-1) and
		       (instr(v_element_type, ']',1,1) = length(v_element_type))
		    then
			v_element_msg_type_isset_p := 't';
			v_element_msg_type_name := trim(substr(
							v_element_type,
							1,
							length(v_element_type)-2));

			if v_element_msg_type_name = '' 
			then
			    raise_application_error (-20001, 
						    'Wrong Format: Message Type Specification');
		        end if;
		    else
			v_element_msg_type_isset_p := 'f';
			v_element_msg_type_name := v_element_type;

		    end if;

		    v_junk_msg_type_id := acs_sc_msg_type.new_element (
			     msg_type_name =>parse_spec.msg_type_name,
			     element_name  => v_element_name,
			     element_msg_type_name    => v_element_msg_type_name,
			     element_msg_type_isset_p => v_element_msg_type_isset_p,
			     element_pos   => v_element_pos
			     );

		else
		    raise_application_error(-20001,'Wrong Format: Message Type Specification');
		end if;
	    else 
		 -- yippee we're done
		 exit;
	    end if;
	    
	    v_element_pos := v_element_pos + 1;
		
	end loop;
		
	return v_element_pos - 1;
    end parse_spec;

    function new_element (
	msg_type_name	 in acs_sc_msg_types.msg_type_name%TYPE,
	element_name	 in acs_sc_msg_type_elements.element_name%TYPE,
	element_msg_type_name		in acs_sc_msg_types.msg_type_name%TYPE,
	element_msg_type_isset_p	in acs_sc_msg_type_elements.element_msg_type_isset_p%TYPE,
	element_pos			in acs_sc_msg_type_elements.element_pos%TYPE
     ) return acs_sc_msg_types.msg_type_id%TYPE
     is
	v_msg_type_id		integer;
	v_element_msg_type_id	integer;
     begin
	
	v_msg_type_id := acs_sc_msg_type.get_id(msg_type_name);
	
	if v_msg_type_id is null 
	then
	    raise_application_error (-20001, 'Unknown Message Type: ' || msg_type_name);	
	end if;

	v_element_msg_type_id := acs_sc_msg_type.get_id(element_msg_type_name);

	if v_element_msg_type_id is null 
	then
	    raise_application_error (-20001, 'Unknown Message Type: ' || element_msg_type_name);	
	end if;	

	insert into acs_sc_msg_type_elements (
	       msg_type_id,
	       element_name,
	       element_msg_type_id,
	       element_msg_type_isset_p,
	       element_pos
	) values (
	       v_msg_type_id,
	       element_name,	 	
	       v_element_msg_type_id,
	       element_msg_type_isset_p,
	       element_pos
	);
	       
	return v_msg_type_id;

     end new_element;
     
end acs_sc_msg_type;
/
show errors


--
-- Primitive Message Types
--
declare
    v_msg_type_id	acs_sc_msg_types.msg_type_id%TYPE;
begin
    v_msg_type_id := acs_sc_msg_type.new('integer','');
    v_msg_type_id := acs_sc_msg_type.new('string','');
    v_msg_type_id := acs_sc_msg_type.new('boolean','');
    v_msg_type_id := acs_sc_msg_type.new('timestamp','');
    v_msg_type_id := acs_sc_msg_type.new('uri','');
    v_msg_type_id := acs_sc_msg_type.new('version','');
    v_msg_type_id := acs_sc_msg_type.new('float','');
    v_msg_type_id := acs_sc_msg_type.new('bytearray','');
end;
/
show errors

