# Copyright 2014 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

import portage
from portage.dep import Atom
from portage.exception import InvalidData
from portage.versions import _pkg_str

class IndexedVardb(object):
	"""
	A vardbapi interface that sacrifices validation in order to
	improve performance. It takes advantage of vardbdbapi._aux_cache,
	which is backed by vdb_metadata.pickle. Since _aux_cache is
	not updated for every single merge/unmerge (see
	_aux_cache_threshold), the list of packages is obtained directly
	from the real vardbapi instance. If a package is missing from
	_aux_cache, then its metadata is obtained using the normal
	(validated) vardbapi.aux_get method.

	For performance reasons, the match method only supports package
	name and version constraints.
	"""

	# Match returns unordered results.
	match_unordered = True

	_copy_attrs = ('cpv_exists',
		'_aux_cache_keys', '_cpv_sort_ascending')

	def __init__(self, vardb):
		self._vardb = vardb

		for k in self._copy_attrs:
			setattr(self, k, getattr(vardb, k))

		self._cp_map = None

	def cp_all(self, sort=True):
		"""
		Returns an ordered iterator instead of a list, so that search
		results can be displayed incrementally.
		"""
		if self._cp_map is not None:
			return iter(sorted(self._cp_map)) if sort else iter(self._cp_map)

		delta_data = self._vardb._cache_delta.loadRace()
		if delta_data is None:
			return self._iter_cp_all()

		self._vardb._cache_delta.applyDelta(delta_data)

		self._cp_map = cp_map = {}
		for cpv in self._vardb._aux_cache["packages"]:
			try:
				cpv = _pkg_str(cpv)
			except InvalidData:
				continue

			cp_list = cp_map.get(cpv.cp)
			if cp_list is None:
				cp_list = []
				cp_map[cpv.cp] = cp_list
			cp_list.append(cpv)

		return iter(sorted(self._cp_map)) if sort else iter(self._cp_map)

	def _iter_cp_all(self):
		self._cp_map = cp_map = {}
		previous_cp = None
		for cpv in self._vardb._iter_cpv_all(sort = True):
			cp = portage.cpv_getkey(cpv)
			if cp is not None:
				cp_list = cp_map.get(cp)
				if cp_list is None:
					cp_list = []
					cp_map[cp] = cp_list
				cp_list.append(cpv)
				if previous_cp is not None and \
					previous_cp != cp:
					yield previous_cp
				previous_cp = cp

		if previous_cp is not None:
			yield previous_cp

	def match(self, atom):
		"""
		For performance reasons, only package name and version
		constraints are supported, and the returned list is
		unordered.
		"""
		if not isinstance(atom, Atom):
			atom = Atom(atom)
		cp_list = self._cp_map.get(atom.cp)
		if cp_list is None:
			return []

		if atom == atom.cp:
			return cp_list[:]
		else:
			return portage.match_from_list(atom, cp_list)

	def aux_get(self, cpv, attrs, myrepo=None):
		pkg_data = self._vardb._aux_cache["packages"].get(cpv)
		if not isinstance(pkg_data, tuple) or \
			len(pkg_data) != 2 or \
			not isinstance(pkg_data[1], dict):
			pkg_data = None
		if pkg_data is None:
			# It may be missing from _aux_cache due to
			# _aux_cache_threshold.
			return self._vardb.aux_get(cpv, attrs)
		metadata = pkg_data[1]
		return [metadata.get(k, "") for k in attrs]
