--[[
Copyright (c) 2012-2013 Kaarle Ritvanen
See LICENSE file for license details
--]]

local M = {}

local model = require('acf2.model.model')
local node = require('acf2.model.node')
local object = require('acf2.object')
local pth = require('acf2.path')

local util = require('acf2.util')
local setdefault = util.setdefault


M.RootModel = model.new()

function M.RootModel:init(txn)
   object.super(self, M.RootModel):init{txn=txn, path='/', addr='/null/root'}
end

function M.RootModel:has_permission(user, permission)
   return permission == 'read'
end

function M.RootModel:meta(path)
   local obj = self:fetch(path, true)
   if object.isinstance(obj, node.TreeNode) then return node.meta(obj) end
   return node.mmeta(self:fetch(pth.parent(path), true), pth.name(path))
end


local _topology = {}
local order = 0

function M.topology(addr, create)
   local top = _topology
   if type(addr) == 'table' then addr = util.copy(addr)
   else addr = pth.split(addr) end

   local function defaults(top)
      return util.setdefaults(top, {members={}, paths={}, referrers={}})
   end

   while #addr > 0 do
      if create then
	 top = setdefault(defaults(top).members, addr[1], {})
      else
	 top = top.members[addr[1]] or top.members[pth.wildcard]
	 if not top then return end
      end
      table.remove(addr, 1)
   end

   return defaults(top)
end

function M.register(name, field, params)
   if not params then params = {} end
   params.create = true
   M.RootModel[name] = model.to_field(field, params)

   local root = M.RootModel()

   for _, record in ipairs(node.topology(root:fetch(name))) do
      local top = M.topology(record.addr, true)

      setdefault(top, 'order', order)
      order = order + 1

      local function set(k, v)
	 setdefault(top, k, v)
	 assert(top[k] == v)
      end

      set('type', record.type)
      table.insert(top.paths, record.path)

      if record.scope then
	 local scope = node.addr(
	    root:fetch(pth.to_absolute(record.scope, pth.parent(record.path)))
	 )
	 set('scope', scope)
	 table.insert(M.topology(scope, true).referrers, record.path)
      end
   end
end


return M
