
local lastID = 1000;
local access = {};
local locals = {};

-- Get id of Class
local function ClassID(class)
	
	return getmetatable(class).metaID;  --class; --string.sub(tostring(class),8,13);
end

-- enter and exits the local area of the class
local function Enter(class)
	access[ClassID(class)] = true;
	print("Enter",ClassID(class));
end

local function Exit(class)
	access[ClassID(class)] = false;
	print("Exit",ClassID(class));
end

-- set up hooks to register when entering the local area
local function HookIn(class,locals) 
	
	-- hooks
	local meta = getmetatable(class);
	for index,value in pairs(meta.__index) do
		if type(value)=="function" then
				meta.__index[index] = function(self,...) Enter(self); local t = {value(self,...)}; Exit(self); return unpack(t); end
		end
	end
	meta.metaID = lastID;
	lastID = lastID + 1;
	setmetatable(class,meta);
	
	-- insert locals
	locals[ClassID(class)] = locals or {};
end

-- handle lookups for local area
local function Get(class,key)
	if access[ClassID(class)] then
		return locals[ClassID(class)][key];
	end
	print("Access ",access[ClassID(class)],ClassID(class));
	error(format("Get. The index %s is non exsisting or private",key));
end

local function Set(class,key,value)
	if access[ClassID(class)] then
		locals[ClassID(class)][key] = value;
		return nil;
	end
	error(format("Set. The index %s is non exsisting or private",key));
end



function GHI_CreateClass(template,globals,locals)
	
	local order = {template};
	
	-- Create a list of all inheritated classes
	while (order[1].inherits) do
		assert(type(_G[order[1].inherits])=="table","Could not find class template "..(order[1].inherits or "nil"));
		table.insert(order,1,_G[order[1].inherits]);
	end
	
	-- metatable
	local metatable = {};
		
	for i=1,#(order) do
		for index,value in pairs(order[i]) do
			metatable[index] = value;
		end
	end
	
	setmetatable(metatable,{__index = Get,__newindex = Set,});
	
	local obj = setmetatable(globals or {},{__index = metatable});
	HookIn(obj,locals);
	return obj;
	
end


TestClass = {};
TestClass.inherits = "TestObject";
function TestClass:AA()
	print("AA");
end



TestObject = {}
TestObject.inherits = "TestObject2";
function TestObject:B1()
	print("B1");
end

function TestObject:GetL1()
	return self.l1;
end

function TestObject:SetL1(val)
	self.l1 = val;
end

TestObject2 = {}
function TestObject2:B2()
	print("B2");
end

-- /script t = GHI_CreateClass(TestClass,{g1=1},{l1=2}); print("run"); t:AA(); t:B1(); t:B2(); t:B3();
