# Path: halibot/halmodule.py
# class HalModule(HalObject):
# 
# 	def reply(self, msg0=None, **kwargs):
# 		# Create the reply message
# 		body = kwargs.get('body', msg0.body)
# 		mtype = kwargs.get('type', msg0.type)
# 		author = kwargs.get('author', msg0.author)
# 		origin = kwargs.get('origin', self.name)
# 
# 		msg = Message(body=body, type=mtype, author=author, origin=origin)
# 
# 		# Synchronous reply?
# 		if msg0.sync:
# 			self.sync_replies[msg0.uuid].append(msg)
# 		else:
# 			self.send_to(msg, [ msg0.origin ])
# 
# 	def hasPermission(self, msg, perm):
# 		return self._hal.auth.hasPermission(msg.origin, msg.identity, perm)
# 
# Path: halibot/halagent.py
# class HalAgent(HalObject):
# 
# 	def dispatch(self, msg):
# 		out = self.config.get('out', self._hal.objects.modules.keys())
# 		self.send_to(msg, out)
# 
# 	def connect(self, to):
# 		# FIXME Don't modify the config like this?
# 		if 'out' in self.config:
# 			self.config['out'].append(to.name)
# 		else:
# 			self.config['out'] = [ to.name ]
# 
# Path: halibot/halauth.py
# class HalAuth():
# 
# 	def __init__(self):
# 		self.perms = []
# 		self.enabled = False
# 		self.log = logging.getLogger("Auth")
# 
# 	# Load permission file, and set to enabled
# 	def load_perms(self, path):
# 		self.path = path
# 
# 		try:
# 			with open(self.path, "r") as f:
# 				temp = json.loads(f.read())
# 
# 			# Roll back into triple, also technically validates format
# 			self.perms = [(a,b,c) for a,b,c in temp]
# 
# 		except Exception as e:
# 			self.log.error("Error loading permissions: {}".format(e))
# 			self.perms = []
# 			# Return if can't find auth?
# 
# 		self.enabled = True
# 
# 	# Write permissions back to the file that was originally loaded
# 	def write_perms(self):
# 		try:
# 			temp = [list(l) for l in self.perms]
# 
# 			with open(self.path, "w") as f:
# 				f.write(json.dumps(temp, indent=4))
# 		except Exception as e: # pragma: no cover
# 				self.log.error("Error storing permissions: {}".format(e))
# 
# 	def grantPermission(self, ri, identity, perm):
# 		if not self.enabled:
# 			return
# 
# 		t = (ri, identity, perm)
# 		if t not in self.perms:
# 			self.perms.append(t)
# 
# 	def revokePermission(self, ri, identity, perm):
# 		if not self.enabled:
# 			return
# 
# 		try:
# 			self.perms.remove((ri,identity, perm))
# 		except Exception as e:
# 			self.log.error("Revocation failed: {}".format(e))
# 
# 	def hasPermission(self, ri, identity, perm):
# 		if not self.enabled:
# 			return True
# 
# 		def tester(x):
# 			a,b,c = x
# 			return re.match(a, ri) and b in (identity, "*") and re.match(c, perm)
# 
# 		# Return True on the first successful perm match
# 		for l in self.perms:
# 			if tester(l):
# 				return True
# 		return False


import json
import threading
import os, sys
import importlib
import collections
import halibot.packages
import logging
from distutils.version import StrictVersion as Version
from queue import Queue,Empty
from string import Template
from .halmodule import HalModule
from .halagent import HalAgent
from .halauth import HalAuth
#
# Main bot class
#    Handles routing, config, agent/module loading
#

# Avoid appending "." if it i
if "." not in sys.path:
	sys.path.append(".")

HALDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))

class ObjectDict(dict):

	@property
	def modules(self):
		return dict(filter(lambda x: isinstance(x[1], HalModule), self.items()))

	@property
	def agents(self):
		return dict(filter(lambda x: isinstance(x[1], HalAgent), self.items()))

#
# This class represents the hierarchy of config files
#
class Config(collections.MutableMapping):

	def __init__(self):
		self.local = {}

# Path: halibot/halmodule.py
# class HalModule(HalObject):
# 
# 	def reply(self, msg0=None, **kwargs):
# 		# Create the reply message
# 		body = kwargs.get('body', msg0.body)
# 		mtype = kwargs.get('type', msg0.type)
# 		author = kwargs.get('author', msg0.author)
# 		origin = kwargs.get('origin', self.name)
# 
# 		msg = Message(body=body, type=mtype, author=author, origin=origin)
# 
# 		# Synchronous reply?
# 		if msg0.sync:
# 			self.sync_replies[msg0.uuid].append(msg)
# 		else:
# 			self.send_to(msg, [ msg0.origin ])
# 
# 	def hasPermission(self, msg, perm):
# 		return self._hal.auth.hasPermission(msg.origin, msg.identity, perm)
# 
# Path: halibot/halagent.py
# class HalAgent(HalObject):
# 
# 	def dispatch(self, msg):
# 		out = self.config.get('out', self._hal.objects.modules.keys())
# 		self.send_to(msg, out)
# 
# 	def connect(self, to):
# 		# FIXME Don't modify the config like this?
# 		if 'out' in self.config:
# 			self.config['out'].append(to.name)
# 		else:
# 			self.config['out'] = [ to.name ]
# 
# Path: halibot/halauth.py
# class HalAuth():
# 
# 	def __init__(self):
# 		self.perms = []
# 		self.enabled = False
# 		self.log = logging.getLogger("Auth")
# 
# 	# Load permission file, and set to enabled
# 	def load_perms(self, path):
# 		self.path = path
# 
# 		try:
# 			with open(self.path, "r") as f:
# 				temp = json.loads(f.read())
# 
# 			# Roll back into triple, also technically validates format
# 			self.perms = [(a,b,c) for a,b,c in temp]
# 
# 		except Exception as e:
# 			self.log.error("Error loading permissions: {}".format(e))
# 			self.perms = []
# 			# Return if can't find auth?
# 
# 		self.enabled = True
# 
# 	# Write permissions back to the file that was originally loaded
# 	def write_perms(self):
# 		try:
# 			temp = [list(l) for l in self.perms]
# 
# 			with open(self.path, "w") as f:
# 				f.write(json.dumps(temp, indent=4))
# 		except Exception as e: # pragma: no cover
# 				self.log.error("Error storing permissions: {}".format(e))
# 
# 	def grantPermission(self, ri, identity, perm):
# 		if not self.enabled:
# 			return
# 
# 		t = (ri, identity, perm)
# 		if t not in self.perms:
# 			self.perms.append(t)
# 
# 	def revokePermission(self, ri, identity, perm):
# 		if not self.enabled:
# 			return
# 
# 		try:
# 			self.perms.remove((ri,identity, perm))
# 		except Exception as e:
# 			self.log.error("Revocation failed: {}".format(e))
# 
# 	def hasPermission(self, ri, identity, perm):
# 		if not self.enabled:
# 			return True
# 
# 		def tester(x):
# 			a,b,c = x
# 			return re.match(a, ri) and b in (identity, "*") and re.match(c, perm)
# 
# 		# Return True on the first successful perm match
# 		for l in self.perms:
# 			if tester(l):
# 				return True
# 		return False


# Path: halibot/halibot.py
import json
import threading
import os, sys
import importlib
import collections
import halibot.packages
import logging
from distutils.version import StrictVersion as Version
from queue import Queue,Empty
from string import Template
from .halmodule import HalModule
from .halagent import HalAgent
from .halauth import HalAuth

#
# Main bot class
#    Handles routing, config, agent/module loading
#

# Avoid appending "." if it i
if "." not in sys.path:
	sys.path.append(".")

HALDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))

class ObjectDict(dict):

	@property
	def modules(self):
		return dict(filter(lambda x: isinstance(x[1], HalModule), self.items()))

	@property
	def agents(self):
		return dict(filter(lambda x: isinstance(x[1], HalAgent), self.items()))

#
# This class represents the hierarchy of config files
#
class Config(collections.MutableMapping):

	def __init__(self):
		self.local = {}

		self.system = {}