function setMetaTableIndex(t, index)
  if t == nil or index == nil then
    return
  end
  local mt = getmetatable(t)
  mt = mt or {}
  if not mt.__index then
    mt.__index = index
    setmetatable(t, mt)
  elseif mt.__index ~= index then
    setMetaTableIndex(mt, index)
  end
end

function class(classname, ...)
  local cls = {__cname = classname}
  local supers = {
    ...
  }
  for _, super in ipairs(supers) do
    if type(super) == "table" then
      cls.__supers = cls.__supers or {}
      cls.__supers[#cls.__supers + 1] = super
      if not cls.super then
        cls.super = super
      end
    else
      return
    end
  end
  cls.__index = cls
  if not cls.__supers or #cls.__supers == 1 then
    setmetatable(cls, {
      __index = cls.super
    })
  else
    setmetatable(cls, {
      __index = function(_, key)
        local _supers = cls.__supers
        for i = 1, #_supers do
          local super = _supers[i]
          if super[key] then
            return super[key]
          end
        end
      end
    })
  end
  if not cls.ctor then
    function cls.ctor()
    end
  end
  
  function cls.new(...)
    local instance = {}
    setMetaTableIndex(instance, cls)
    instance.class = cls
    instance:ctor(...)
    return instance
  end
  
  function cls.getName()
    return cls.__cname
  end
  
  function cls.isSubclassOf(c)
    local t = cls
    if t == c then
      return false
    end
    while t ~= nil do
      if t == c then
        return true
      end
      t = t.super
    end
    return false
  end
  
  function cls:isInstanceOf(c)
    local cSelf = self.class
    if cSelf == nil then
      return false
    end
    if cSelf == c then
      return true
    end
    return cSelf.isSubclassOf(c)
  end
  
  function cls.importPartialClass(selfCls, partCls)
    table.merge(selfCls, partCls)
    partCls.super = selfCls.super
  end
  
  return cls
end
