-- --- T2-COPYRIGHT-NOTE-BEGIN ---
-- This copyright note is auto-generated by ./scripts/Create-CopyPatch.
-- 
-- T2 SDE: misc/lua/sde/hooks.lua
-- Copyright (C) 2005 - 2006 The T2 SDE Project
-- Copyright (C) 2005 - 2006 Juergen "George" Sawinski
-- 
-- More information can be found in the files COPYING and README.
-- 
-- This program 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; version 2 of the License. A copy of the
-- GNU General Public License can be found in the file COPYING.
-- --- T2-COPYRIGHT-NOTE-END ---

-- TODO:
--  - add "protected" hooks (hooks, that can't be overriden simply)

-- DESCRIPTION:
-- 1. Create a new hook
--    h = hook() or h = hook.new()
--
-- 2. Using hooks
--
-- Access to the hooks with a given hook level (from 1 to 9):
--    h[num]:add(function-or-string)
--      Add a function to the hook with a hook level (num).
--
--    h[num]:set(function-or-string)
--      Replace the contents of hook-order "num" with a new function
--
--    h[num]:clear()
--      Clear all hooks.
--
--    h[num]:run()
--      Run a specific hook level
--
-- Access without hook level:
--    h:add(function-or-string) 
--      Equivalent to h[5]:add(function-or-string)
-- 
--    h:set(function-or-string)
--      Equivalent to h[5]:set(function-or-string), however, clears
--      all other levels
--
--    h:clear()
--      Clear all hooks in all levels.
--
--    h:run()
--      Execute the hooks in all levels, starting at hook level 1.

-- INTERFACE -----------------------------------------------------------------
hook = { level = {} }
meta = {}

function hook.new()
   local h = hook
   return setmetatable(h, meta)
end

function hook:add(data)
   self[5]:add(data)
end

function hook:set(data)
   self:clear()
   self[5]:set(data)
end

function hook:run()
   for _,l in pairs(self.level) do l:run() end
end

function hook:clear()
   for _,l in pairs(self.level) do l:clear() end
end

-- h = hook()
setmetatable(hook, { __call = hook.new })

-- INTERNAL HOOKS __hook -----------------------------------------------------
local __hook = {}
local __meta = { __index = {} }

-- create a new __hook
function __hook.new()
   local h = { hooks = {} }
   return setmetatable(h, __meta)
end

-- __hook.add(hook-table, function-or-string)
-- add a function to the __hook
function __hook.add(h, data)
   if type(data) == "table" then
      for _,f in pairs(data) do
	 __hook.add(h, f)
      end
      return
   end

   -- insert hook
   if type(data) == "function" then
      table.insert(h.hooks, data)
   elseif type(data) == "string" then
      local f = loadstring(data)
      table.insert(h.hooks, f)
   else
      assert(type(data) == "function", 
	     "function or string expected in hook.add(table, pos, function-or-string)")
   end
end

-- __hook.set(hook-table, function-or-string-or-nil)
-- add a function to the __hook
function __hook.set(h, data)
   h.hooks = {}
   __hook.add(h, data)
end

-- __hook.run(hook-table)
-- execute the hooks
function __hook.run(h)
   for _,f in pairs(h.hooks) do
      if f then f() end
   end
end

-- __hook.clear(hook-table)
-- clear all hooks
function __hook.clear(h)
   h.hooks = {}
end

-- METATABLE -----------------------------------------------------------------
function __meta.__index:add(data) __hook.add(self, data) end
function __meta.__index:set(data) __hook.set(self, data) end
function __meta.__index:clear()   __hook.clear(self) end
function __meta.__index:run()     __hook.run(self) end

function meta.__index(self, pos, data)
   -- clamp position
   if pos < 1 then pos = 1 end
   if pos > 9 then pos = 9 end

   -- create if it does not exist
   if not self.level[pos] then
      table.insert(self.level, pos, __hook.new())
   end

   return self.level[pos]
end

function meta.__newindex(self, pos, data)
   self[pos]:set(data)
end
