--
-- __workflow__simple_p/2
--
create or replace function __workflow__simple_p(
  character varying,
  integer
) returns bool as $$

declare
  simple_p__workflow_key           alias for $1;  
  v_session_id                     alias for $2;
  -- previous_place_list              t_place_table; 
  -- target_place_list                t_place_table; 
  -- guard_list                       t_guard_table; 
  guard_list_1                     varchar;
  guard_list_2                     varchar;
  target_place_list_1              varchar;
  target_place_list_2              varchar;
  previous_place_list_i            varchar;
  v_row_count                      integer default 0;       
  v_count                          integer;       
  v_count2                         integer;       
  v_place_key                      wf_places.place_key%TYPE;
  v_end_place                      wf_places.place_key%TYPE;
  v_transition_key                 wf_transitions.transition_key%TYPE;
  v_rownum                         integer;
  v_target                         record;
begin

        /* Let us do some simple checks first */

        /* Places with more than one arc out */
        select count(*) into v_count
        from   wf_places p
        where  p.workflow_key = simple_p__workflow_key
        and    1 < (select count(*) 
                    from   wf_arcs a
                    where  a.workflow_key = p.workflow_key
                    and    a.place_key = p.place_key
                    and    direction = 'in');
        raise notice 'query 1';
        if v_count > 0 then
            return 'f';
        end if;

        /* Transitions with more than one arc in */
        select count(*) into v_count
        from   wf_transitions t
        where  t.workflow_key = simple_p__workflow_key
        and    1 < (select count(*)
                    from   wf_arcs a
                    where  a.workflow_key = t.workflow_key
                    and    a.transition_key = t.transition_key
                    and    direction = 'in');

        raise notice 'query 2';
        if v_count > 0 then
            return 'f';
        end if;

        /* Transitions with more than two arcs out */
        select count(*) into v_count
        from   wf_transitions t
        where  t.workflow_key = simple_p__workflow_key
        and    2 < (select count(*)
                    from   wf_arcs a
                    where  a.workflow_key = t.workflow_key
                    and    a.transition_key = t.transition_key
                    and    direction = 'out');

        raise notice 'query 3';
        if v_count > 0 then
            return 'f';
        end if;

        /* Now we do the more complicated checks.
         * We keep a list of visited places because I could not think
         * of a nicer way that was not susceptable to infinite loops.
         */


        v_place_key := 'start';
        v_end_place := 'end';

        loop
            exit when v_place_key = v_end_place;

            -- previous_place_list(v_row_count) := v_place_key;
            insert into previous_place_list 
            (session_id,rcnt,ky) 
            values 
            (v_session_id,v_row_count,v_place_key);
        raise notice 'query 4';

            select distinct transition_key into v_transition_key
            from   wf_arcs
            where  workflow_key = simple_p__workflow_key
            and    place_key = v_place_key
            and    direction = 'in';
        raise notice 'query 5';

            select count(*) into v_count
            from wf_arcs
            where workflow_key = simple_p__workflow_key
            and   transition_key = v_transition_key
            and   direction = 'out';
        raise notice 'query 6';

            if v_count = 1 then
                select distinct place_key into v_place_key
                from wf_arcs
                where workflow_key = simple_p__workflow_key
                and   transition_key = v_transition_key
                and   direction = 'out';
        raise notice 'query 7';

            else if v_count = 0 then
                /* deadend! */
                return 'f';

            else
                /* better be two based on our earlier test */

                v_rownum := 1;
                for v_target in 
                select place_key,guard_callback
                from   wf_arcs
                where  workflow_key = simple_p__workflow_key
                and    transition_key = v_transition_key
                and    direction = 'out'
                LOOP
                    -- target_place_list(v_target.rownum) := v_target.place_key;
        raise notice 'query 8';
                    insert into target_place_list 
                    (session_id,rcnt,ky) 
                    values 
                    (v_session_id,v_rownum,v_target.place_key);
        raise notice 'query 9';

                    -- guard_list(v_target.rownum) := v_target.guard_callback; 
                    insert into guard_list 
                    (session_id,rcnt,ky) 
                    values 
                    (v_session_id,v_rownum,v_target.guard_callback);
                    v_rownum := v_rownum + 1;
        raise notice 'query 10';
                end loop;
    
                /* Check that the guard functions are the negation of each other 
                 * by looking for the magic entry "#" (exactly once)
                 */
                select ky into guard_list_1 from guard_list 
                where session_id = v_session_id and rcnt = 1;
        raise notice 'query 11';

                select ky into guard_list_2 from guard_list 
                where session_id = v_session_id and rcnt = 2;
        raise notice 'query 12';

                if ((guard_list_1 != '#' and guard_list_2 != '#') or
                    (guard_list_1 = '#' and guard_list_2 = '#')) then
                    return 'f';
                end if;
    
                /* Check that exactly one of the targets is in the previous list */

                v_count2 := 0;
                select ky into target_place_list_1 from target_place_list 
                where session_id = v_session_id and rcnt = 1;
        raise notice 'query 13';

                select ky into target_place_list_2 from target_place_list 
                where session_id = v_session_id and rcnt = 2;                
        raise notice 'query 14';

                for i in 0..v_row_count LOOP
                    select ky into previous_place_list_i 
                    from previous_place_list where session_id = v_session_id 
                    and rcnt = i;
                    if target_place_list_1 = previous_place_list_i then
                        v_count2 := v_count2 + 1;
                        v_place_key := target_place_list_2;
                    end if;
                    if target_place_list_2 = previous_place_list_i then
                        v_count2 := v_count2 + 1;
                        v_place_key := target_place_list_1;
                    end if;
                end loop;
        raise notice 'query 15';

                if v_count2 != 1 then
                    return 'f';
                end if;

            end if; end if;

            v_row_count := v_row_count + 1;

        end loop;

        /* if we got here, it must be okay */
        return 't';

     
end;$$ language plpgsql;