-- Purpose of this file:
-- "Type" class for the mnoofltk library, that manages one class of objects

-- load libraries
local mnoo=require("mnoo_current/mnoo.lua")
local args_cl=require("mnoo_current/args_cl.lua")
local fun_cl=require("mnoofltk/libBuilder/libBuilderFun_cl.lua")

setfenv(1, mnoo:createPrivateEnvironment())

local cl=mnoo.newclass()
cl:declareObjectmethod("registerFunction", "writeC_function_bodies", "writeC_pushstore_typetable", "writeLua")
cl:declareObjectdata("ctype", "luatype", "parent", "funs_ilist")

local superclass_new=cl:getClassfunction("new")
cl.new=
   function(actualclass, t)
      assert(mnoo.classIsA(actualclass, cl))
      local self=superclass_new(actualclass) -- mnoo base class, no args

      local t=args_cl:new(t) -- +++++++++++++ arg handling starts ++++++++++++++++++
      self.ctype=t:get{name="ctype", type="string"}
      self.luatype=t:get{name="luatype", type="string"}
      self.parent=t:get{name="parent", class=cl, nilOK=true}
      assert(t:all_done())   -- +++++++++++++ arg handling ends ++++++++++++++++++++ 

      self.funs_ilist={}
      return self
   end

cl.registerFunction=
   function(self, t)
      assert(mnoo.objectIsA(self, cl))
      
      local t=args_cl:new(t) -- +++++++++++++ arg handling starts ++++++++++++++++++
      local fun=t:get{name="fun", class=fun_cl}
      assert(t:all_done())   -- +++++++++++++ arg handling ends ++++++++++++++++++++ 

      table.insert(self.funs_ilist, fun)
   end

cl.writeC_function_bodies=
   function(self, t)
      assert(mnoo.objectIsA(self, cl))

      local t=args_cl:new(t) -- +++++++++++++ arg handling starts ++++++++++++++++++
      local types_ilist=t:get{name="types_ilist", type="table"}
      assert(t:all_done())   -- +++++++++++++ arg handling ends ++++++++++++++++++++ 

      local data_ilist={}
      for _, t in ipairs(self.funs_ilist) do
	 table.insert(data_ilist, t:writeC{type=self, types_ilist=types_ilist})
      end
      return table.concat(data_ilist, "\n")
   end

cl.writeC_pushstore_typetable=
   function(self, t)
      assert(mnoo.objectIsA(self, cl))
      
      local t=args_cl:new(t) -- +++++++++++++ arg handling starts ++++++++++++++++++
      local types_ilist=t:get{name="types_ilist", type="table"}
      assert(t:all_done())   -- +++++++++++++ arg handling ends ++++++++++++++++++++ 

      local data_ilist={}
      table.insert(data_ilist, '\tlua_pushstring(l, "'..self.luatype..'"); /* name in typetable */')
      table.insert(data_ilist, '\tlua_newtable(l); /* "'..self.luatype..'" type table */')
      for _, t in ipairs(self.funs_ilist) do
	 table.insert(data_ilist, t:writeC_pushstore_function{type=self})
      end
      table.insert(data_ilist, "\tlua_rawset(l, -3); /* write "..self.luatype.." typetable into library table */")
      return table.concat(data_ilist, "\n")
   end

cl.writeLua=
   function(self, t)
      assert(mnoo.objectIsA(self, cl))
      
      local t=args_cl:new(t) -- +++++++++++++ arg handling starts ++++++++++++++++++
      local types_ilist=t:get{name="types_ilist", type="table"}
      assert(t:all_done())   -- +++++++++++++ arg handling ends ++++++++++++++++++++ 
      
      local data_ilist={}
      local cf_ilist={}
      local om_ilist={}

      -- ########################################################################################
      -- # Create new class
      -- ########################################################################################      
      if not self.parent then
	 -- base class
	 table.insert(data_ilist, "-- class '"..self.luatype.."'")
	 table.insert(data_ilist, "local cl=mnoo.newclass()")
      else
	 -- derived class
	 table.insert(data_ilist, "-- class '"..self.luatype.."'")
	 table.insert(data_ilist, "local cl=mnoo.newclass(classtable."..self.parent.luatype..")")
      end

      -- ########################################################################################
      -- # Write declarations and check presence of "new"
      -- ########################################################################################      
      local hasNew=false
      for _, f in ipairs(self.funs_ilist) do
	 if not f.overloaded then

	    if f.name=="new" then
	       hasNew=true
	    else	 
	       if f.lt=="classfunction" then
		  table.insert(cf_ilist, f.name)
	       elseif f.lt == "objectmethod" then
		  table.insert(om_ilist, f.name)
	       else assert(nil, f.lt) end
	    end
	 end -- if not overloaded
      end
      if table.getn(cf_ilist) > 0 then
	 table.insert(data_ilist, "cl:declareClassfunction('"..table.concat(cf_ilist, "', '").."')")
      end	 
      if table.getn(om_ilist) > 0 then
	 table.insert(data_ilist, "cl:declareObjectmethod('"..table.concat(om_ilist, "', '").."')")
      end	 

      -- ########################################################################################
      -- # Prevent access to object's inherited "new" classfunction (standard constructor
      -- # of mnoo.lua)
      -- ########################################################################################      
      if not hasNew then
	 table.insert(data_ilist, "cl.new=nonew") 
      end

      -- ########################################################################################
      -- # Write function bodies
      -- ########################################################################################      
      for _, f in ipairs(self.funs_ilist) do
	 table.insert(data_ilist, f:writeLua{type=self, types_ilist=types_ilist}) -- define into cl
      end
 
      -- ########################################################################################
      -- # Assign class to class table (list of all classes)
      -- ########################################################################################      
       table.insert(data_ilist, "classtable."..self.luatype.."=cl")
      return table.concat(data_ilist, "\n")
   end

return cl