# -*- coding: utf-8 -*-
# repoman: Herd database analysis
# Copyright 2010-2013 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2 or later

from __future__ import print_function, unicode_literals

import errno
import xml.etree.ElementTree
try:
	from xml.parsers.expat import ExpatError
except (SystemExit, KeyboardInterrupt):
	raise
except (ImportError, SystemError, RuntimeError, Exception):
	# broken or missing xml support
	# http://bugs.python.org/issue14988
	# This means that python is built without xml support.
	# We tolerate global scope import failures for optional
	# modules, so that ImportModulesTestCase can succeed (or
	# possibly alert us about unexpected import failures).
	pass

from portage import _encodings, _unicode_encode
from portage.exception import FileNotFound, ParseError, PermissionDenied
from portage import os

from repoman.errors import err

__all__ = [
	"make_herd_base", "get_herd_base"
]


def _make_email(nick_name):
	if not nick_name.endswith('@gentoo.org'):
		nick_name = nick_name + '@gentoo.org'
	return nick_name


class HerdBase(object):
	def __init__(self, herd_to_emails, all_emails):
		self.herd_to_emails = herd_to_emails
		self.all_emails = all_emails

	def known_herd(self, herd_name):
		return herd_name in self.herd_to_emails

	def known_maintainer(self, nick_name):
		return _make_email(nick_name) in self.all_emails

	def maintainer_in_herd(self, nick_name, herd_name):
		return _make_email(nick_name) in self.herd_to_emails[herd_name]


class _HerdsTreeBuilder(xml.etree.ElementTree.TreeBuilder):
	"""
	Implements doctype() as required to avoid deprecation warnings with
	>=python-2.7.
	"""
	def doctype(self, name, pubid, system):
		pass


def make_herd_base(filename):
	herd_to_emails = dict()
	all_emails = set()

	try:
		xml_tree = xml.etree.ElementTree.parse(
			_unicode_encode(
				filename, encoding=_encodings['fs'], errors='strict'),
			parser=xml.etree.ElementTree.XMLParser(
				target=_HerdsTreeBuilder()))
	except ExpatError as e:
		raise ParseError("metadata.xml: %s" % (e,))
	except EnvironmentError as e:
		func_call = "open('%s')" % filename
		if e.errno == errno.EACCES:
			raise PermissionDenied(func_call)
		elif e.errno == errno.ENOENT:
			raise FileNotFound(filename)
		raise

	herds = xml_tree.findall('herd')
	for h in herds:
		_herd_name = h.find('name')
		if _herd_name is None:
			continue
		herd_name = _herd_name.text.strip()
		del _herd_name

		maintainers = h.findall('maintainer')
		herd_emails = set()
		for m in maintainers:
			_m_email = m.find('email')
			if _m_email is None:
				continue
			m_email = _m_email.text.strip()

			herd_emails.add(m_email)
			all_emails.add(m_email)

		herd_to_emails[herd_name] = herd_emails

	return HerdBase(herd_to_emails, all_emails)


def get_herd_base(repoman_settings):
	try:
		herd_base = make_herd_base(
			os.path.join(repoman_settings["PORTDIR"], "metadata/herds.xml"))
	except (EnvironmentError, ParseError, PermissionDenied) as e:
		err(str(e))
	except FileNotFound:
		# TODO: Download as we do for metadata.dtd, but add a way to
		# disable for non-gentoo repoman users who may not have herds.
		herd_base = None
	return herd_base


if __name__ == '__main__':
	h = make_herd_base('/usr/portage/metadata/herds.xml')

	assert(h.known_herd('sound'))
	assert(not h.known_herd('media-sound'))

	assert(h.known_maintainer('sping'))
	assert(h.known_maintainer('sping@gentoo.org'))
	assert(not h.known_maintainer('portage'))

	assert(h.maintainer_in_herd('zmedico@gentoo.org', 'tools-portage'))
	assert(not h.maintainer_in_herd('pva@gentoo.org', 'tools-portage'))

	import pprint
	pprint.pprint(h.herd_to_emails)
