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

import errno
import logging
import sys
import time

try:
	import threading
except ImportError:
	import dummy_threading as threading

import portage
from portage import os
from portage.util._async.TaskScheduler import TaskScheduler
from _emerge.CompositeTask import CompositeTask
from .FetchIterator import FetchIterator
from .DeletionIterator import DeletionIterator

if sys.hexversion >= 0x3000000:
	# pylint: disable=W0622
	long = int

class MirrorDistTask(CompositeTask):

	__slots__ = ('_config', '_terminated', '_term_check_id')

	def __init__(self, config):
		CompositeTask.__init__(self, scheduler=config.event_loop)
		self._config = config
		self._terminated = threading.Event()

	def _start(self):
		self._term_check_id = self.scheduler.idle_add(self._termination_check)
		fetch = TaskScheduler(iter(FetchIterator(self._config)),
			max_jobs=self._config.options.jobs,
			max_load=self._config.options.load_average,
			event_loop=self._config.event_loop)
		self._start_task(fetch, self._fetch_exit)

	def _fetch_exit(self, fetch):

		self._assert_current(fetch)
		if self._was_cancelled():
			self.wait()
			return

		if self._config.options.delete:
			deletion = TaskScheduler(iter(DeletionIterator(self._config)),
				max_jobs=self._config.options.jobs,
				max_load=self._config.options.load_average,
				event_loop=self._config.event_loop)
			self._start_task(deletion, self._deletion_exit)
			return

		self._post_deletion()

	def _deletion_exit(self, deletion):

		self._assert_current(deletion)
		if self._was_cancelled():
			self.wait()
			return

		self._post_deletion()

	def _post_deletion(self):

		if self._config.options.recycle_db is not None:
			self._update_recycle_db()

		if self._config.options.scheduled_deletion_log is not None:
			self._scheduled_deletion_log()

		self._summary()

		self.returncode = os.EX_OK
		self._current_task = None
		self.wait()

	def _update_recycle_db(self):

		start_time = self._config.start_time
		recycle_dir = self._config.options.recycle_dir
		recycle_db = self._config.recycle_db
		r_deletion_delay = self._config.options.recycle_deletion_delay

		# Use a dict optimize access.
		recycle_db_cache = dict(recycle_db.items())

		for filename in os.listdir(recycle_dir):

			recycle_file = os.path.join(recycle_dir, filename)

			try:
				st = os.stat(recycle_file)
			except OSError as e:
				if e.errno not in (errno.ENOENT, errno.ESTALE):
					logging.error(("stat failed for '%s' in "
						"recycle: %s") % (filename, e))
				continue

			value = recycle_db_cache.pop(filename, None)
			if value is None:
				logging.debug(("add '%s' to "
					"recycle db") % filename)
				recycle_db[filename] = (st.st_size, start_time)
			else:
				r_size, r_time = value
				if long(r_size) != st.st_size:
					recycle_db[filename] = (st.st_size, start_time)
				elif r_time + r_deletion_delay < start_time:
					if self._config.options.dry_run:
						logging.info(("dry-run: delete '%s' from "
							"recycle") % filename)
						logging.info(("drop '%s' from "
							"recycle db") % filename)
					else:
						try:
							os.unlink(recycle_file)
						except OSError as e:
							if e.errno not in (errno.ENOENT, errno.ESTALE):
								logging.error(("delete '%s' from "
									"recycle failed: %s") % (filename, e))
						else:
							logging.debug(("delete '%s' from "
								"recycle") % filename)
							try:
								del recycle_db[filename]
							except KeyError:
								pass
							else:
								logging.debug(("drop '%s' from "
									"recycle db") % filename)

		# Existing files were popped from recycle_db_cache,
		# so any remaining entries are for files that no
		# longer exist.
		for filename in recycle_db_cache:
			try:
				del recycle_db[filename]
			except KeyError:
				pass
			else:
				logging.debug(("drop non-existent '%s' from "
					"recycle db") % filename)

	def _scheduled_deletion_log(self):

		start_time = self._config.start_time
		dry_run = self._config.options.dry_run
		deletion_delay = self._config.options.deletion_delay
		distfiles_db = self._config.distfiles_db

		date_map = {}
		for filename, timestamp in self._config.deletion_db.items():
			date = timestamp + deletion_delay
			if date < start_time:
				date = start_time
			date = time.strftime("%Y-%m-%d", time.gmtime(date))
			date_files = date_map.get(date)
			if date_files is None:
				date_files = []
				date_map[date] = date_files
			date_files.append(filename)

		if dry_run:
			logging.warning("dry-run: scheduled-deletions log "
				"will be summarized via logging.info")

		lines = []
		for date in sorted(date_map):
			date_files = date_map[date]
			if dry_run:
				logging.info(("dry-run: scheduled deletions for %s: %s files") %
					(date, len(date_files)))
			lines.append("%s\n" % date)
			for filename in date_files:
				cpv = "unknown"
				if distfiles_db is not None:
					cpv = distfiles_db.get(filename, cpv)
				lines.append("\t%s\t%s\n" % (filename, cpv))

		if not dry_run:
			portage.util.write_atomic(
				self._config.options.scheduled_deletion_log,
				"".join(lines))

	def _summary(self):
		elapsed_time = time.time() - self._config.start_time
		fail_count = len(self._config.file_failures)
		delete_count = self._config.delete_count
		scheduled_deletion_count = self._config.scheduled_deletion_count - delete_count
		added_file_count = self._config.added_file_count
		added_byte_count = self._config.added_byte_count

		logging.info("finished in %i seconds" % elapsed_time)
		logging.info("failed to fetch %i files" % fail_count)
		logging.info("deleted %i files" % delete_count)
		logging.info("deletion of %i files scheduled" %
			scheduled_deletion_count)
		logging.info("added %i files" % added_file_count)
		logging.info("added %i bytes total" % added_byte_count)

	def terminate(self):
		self._terminated.set()

	def _termination_check(self):
		if self._terminated.is_set():
			self.cancel()
			self.wait()
		return True

	def _wait(self):
		CompositeTask._wait(self)
		if self._term_check_id is not None:
			self.scheduler.source_remove(self._term_check_id)
			self._term_check_id = None
