--          This file is part of SmartEiffel The GNU Eiffel Compiler.
--       Copyright (C) 1994-2002 LORIA - INRIA - U.H.P. Nancy 1 - FRANCE
--          Dominique COLNET and Suzanne COLLIN - SmartEiffel@loria.fr
--                       http://SmartEiffel.loria.fr
-- SmartEiffel is  free  software;  you can  redistribute it and/or modify it
-- under the terms of the GNU General Public License as published by the Free
-- Software  Foundation;  either  version  2, or (at your option)  any  later
-- version. SmartEiffel is distributed in the hope that it will be useful,but
-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-- or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU General Public License
-- for  more  details.  You  should  have  received a copy of the GNU General
-- Public  License  along  with  SmartEiffel;  see the file COPYING.  If not,
-- write to the  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-- Boston, MA 02111-1307, USA.
--
class AGENT_POOL
   --
   -- Singleton object in charge of agents.
   -- This singleton is shared via the GLOBALS.`agent_pool' once function.
   --

inherit GLOBALS

feature {E_AGENT}

   register(e_agent: E_AGENT): INTEGER is
	 -- Registration of an "agent ..." creation call. The registered one 
	 -- gets it's id as the `Result' of this function.
      do
	 if list = Void then
	    create list.with_capacity(12)
	 end
	 list.add_last(e_agent)
	 Result := list.upper + 1
	 -- Note that it may not be a really good idea to use the array
	 -- index as an id because this may imply many C recompilations.
      end

feature {SMART_EIFFEL}

   falling_down is
      local
         i: INTEGER
      do
	 if list /= Void then
	    from
	       i := list.upper
	    until
	       i < list.lower
	    loop
	       list.item(i).falling_down
	       i := i - 1
	    end
	 end
      end

   c_header_pass1 is
      require
         cpp.on_h
      do
         if list /= Void then
	    cpp.put_string(once "[
               typedef union _se_agent se_agent;
               typedef struct _se_agent0 se_agent0;

                                 ]")
	 end
      ensure
         cpp.on_h
      end

   c_define_missing_agent_launcher is
      local
	 i: INTEGER; agent_args: AGENT_ARGS
      do
	 from
	    i := 1
	 until
	    i > missing_call_set.count
	 loop
	    agent_args := missing_call_set.item(i)
	    agent_args.c_define_missing_agent_launcher
	    i := i + 1
	 end
      end
   
   customize_jvm_runtime is
--      local
--	i:INTEGER
      do
--	 jvm.write_super_agent_class
--         if (list/=Void) then
--	   from
--	     i := 0
--	   until
--	     i > (list.count-1)
--	   loop
--	     jvm.write_agent_class(list.item(i))
--	     i := i + 1
--	   end;--loop
--         end;--if
      end

feature {JVM}

   jvm_define_deferred_methods is
      local
	 i: INTEGER
      do
	 method_info.add_init(fz_java_lang_object)
	 from
	    i := 1
	 until
	    i > agent_call_set.count
	 loop
	    agent_call_set.item(i).jvm_define(False)
	    i := i + 1
	 end
	 method_info.finish
      end

   ajout_call_full(i:INTEGER) is
	 -- *** NOM MOCHE ***
      do
	 method_info.add_init(fz_java_lang_object)
	 agent_call_set.item(i).jvm_define(True)
	 method_info.finish
      end

feature {AGENT_INSTRUCTION,AGENT_EXPRESSION}

   register_agent_call(args: EFFECTIVE_ARG_LIST
		       rf: RUN_FEATURE): AGENT_ARGS is
	 -- Where `rf' is the `call' or the `item' feature.
      require
	 args.count = 1
      local
	 toa: TYPE_OF_AGENT
      do
	 check
	    rf.name.to_string = as_item or rf.name.to_string = as_call
	 end
	 toa ?= rf.current_type
	 create Result.make(toa, args, rf.result_type)
	 agent_call_set.add(Result)
      ensure
	 Result /= Void
      end

feature {C_PRETTY_PRINTER}

   customize_c_runtime is
      require
	 cpp.on_h
      local
	 i: INTEGER; boost: BOOLEAN; agent_args: AGENT_ARGS
      do
	 boost := ace.boost
	 if list /= Void then
	    cpp.put_string(once "struct _se_agent0{")
	    if not boost then
	       cpp.put_string(once "Tid id;")
	    end
	    cpp.put_string(once "int agent_id;void*(*afp)(")
	    if not boost then
	       cpp.put_string(once "se_dump_stack*,")
	    end
	    cpp.put_string(once "se_agent*);};%N")
	    from
	       i := list.upper
	    until
	       i < list.lower
	    loop
	       list.item(i).c_define_type_1(boost)
	       i := i - 1
	    end
	    cpp.put_string(once "union _se_agent{T0 s0;se_agent0 u0;")
	    from
	       i := list.upper
	    until
	       i < list.lower
	    loop
	       list.item(i).c_define_type_2
	       i := i - 1
	    end
	    cpp.put_string(once "};%N")
            cpp.sys_runtime_h_and_c(once "agents")
	    cpp.swap_on_c
	    echo.print_count(once "Agent definition wrapper",list.count)
	    from
	       i := list.upper
	    until
	       i < list.lower
	    loop
	       list.item(i).c_define_function(boost)
	       i := i - 1
	    end
	    echo.print_count(once "Agent call wrapper",agent_call_set.count)
	    from
	       i := 1
	    until
	       i > agent_call_set.count
	    loop
	       agent_args := agent_call_set.item(i)
	       agent_definition_set.add(agent_args.signature)
	       agent_args.c_define_agent_launcher
	       i := i + 1
	    end
	    cpp.swap_on_h
	 end
      ensure
	 cpp.on_h
      end

feature {GC_HANDLER}

   gc_info_in(body: STRING) is
         -- Produce C code to print GC information.
      do
         if list /= Void then
	    body.append(once "[
               if(gc_info_nb_agent)
                  fprintf(SE_GCINFO,
                  "%d\tagent(s) created. (store_left=%d).\n",
                  gc_info_nb_agent,store_left_agent);

                              ]")
	 end
      end

feature {AGENT_ARGS}

   c_switch_in(buffer: STRING; type_of_agent: TYPE_OF_AGENT; rt: E_TYPE) is
      local
	 i, argi, open1_count, id: INTEGER; e_agent: E_AGENT
	 toa: TYPE_OF_AGENT; base1: E_TYPE;
	 open1, open2: TYPE_TUPLE; match: BOOLEAN
      do
	 if list /= Void then
	    from
	       i := list.upper
	       base1 := type_of_agent.base
	       open1 := type_of_agent.open
	       open1_count := open1.count
	       buffer.extend('%N')
	    until
	       i < 0
	    loop	       
	       e_agent := list.item(i)
	       toa := e_agent.result_type
	       id := e_agent.se_agent_id
	       buffer.append(once "case ")
	       id.append_in(buffer)
	       comment_in(buffer, toa.run_time_mark)
	       buffer.append(once ":{%N")
	       -- Does this `e_agent' `match' the prototype:
	       match := False
	       open2 := toa.open
	       if open1_count = open2.count then
		  from
		     match := True
		     argi := open1_count
		  until
		     not match or else argi <= 0
		  loop
		     if open1.type(argi).is_reference then
			match := open2.type(argi).is_reference
		     else
			match := not open2.type(argi).is_reference
		     end
		     argi := argi - 1
		  end
	       end
	       if match then
		  if rt /= Void then
		     match := toa.res /= Void
		  end
	       end
	       -- (End of `match' computation.)
	       if match then
		  if rt /= Void then
		     buffer.append(once "return(")
		     rt.c_type_for_result_in(buffer)
		     buffer.append(fz_22)
		  end
		  buffer.append(once "((se_agent")
		  id.append_in(buffer)
		  buffer.append(once "*)a)->afp(")
		  if not ace.boost then buffer.append(once "&ds,") end
		  buffer.append(once "((/*agent*/void*)a)")
		  from
		     argi := 1
		  until
		     argi > open1_count
		  loop
		     buffer.extend(',')
		     buffer.extend('a')
		     argi.append_in(buffer)
		     argi := argi + 1
		  end
		  buffer.extend(')')
		  if rt /= Void then
		     buffer.extend(')')
		  end
		  buffer.append(fz_00)
	       else
		  error_handler.cancel
	       end
	       buffer.append(once "break;%N}%N")
	       i := i - 1
	    end
	 end
      end
   
   check_for_callee(agent_args: AGENT_ARGS; caller: POSITION) is
      do
	 if not agent_definition_set.has(agent_args.signature) then
	    error_handler.add_position(caller)
	    error_handler.append(
	       "There is no such agent ever defined in the live code.")
	    error_handler.print_as_warning
	    missing_call_set.add(agent_args)
	 end
      end

feature {NONE}

   list: FIXED_ARRAY[E_AGENT]
	 -- Of all "agent ..." definition in the live code.

   agent_call_set: SET[AGENT_ARGS] is
      once
	 create Result.make
      end

   missing_call_set: SET[AGENT_ARGS] is
      once
	 create Result.make
      end      
   
   agent_definition_set: SET[STRING] is
      once
	 create Result.make
      end

   comment_in(buffer, type: STRING) is
      do
	 buffer.append(once "/* ")
	 buffer.append(type)
	 buffer.append(once "*/")
      end
   
   singleton_memory: AGENT_POOL is
      once
	 Result := Current
      end

invariant

   is_real_singleton: Current = singleton_memory

end -- AGENT_POOL