# -*- coding:utf-8 -*-

import logging
import os
import sys
from itertools import chain

from portage import cvstree

from repoman.errors import caterror
from repoman._subprocess import repoman_popen


def scan(repolevel, reposplit, startdir, categories, repo_settings):
	scanlist = []
	if repolevel == 2:
		# we are inside a category directory
		catdir = reposplit[-1]
		if catdir not in categories:
			caterror(catdir, repo_settings.repodir)
		mydirlist = os.listdir(startdir)
		for x in mydirlist:
			if x == "CVS" or x.startswith("."):
				continue
			if os.path.isdir(startdir + "/" + x):
				scanlist.append(catdir + "/" + x)
		# repo_subdir = catdir + os.sep
	elif repolevel == 1:
		for x in categories:
			if not os.path.isdir(startdir + "/" + x):
				continue
			for y in os.listdir(startdir + "/" + x):
				if y == "CVS" or y.startswith("."):
					continue
				if os.path.isdir(startdir + "/" + x + "/" + y):
					scanlist.append(x + "/" + y)
		# repo_subdir = ""
	elif repolevel == 3:
		catdir = reposplit[-2]
		if catdir not in categories:
			caterror(catdir, repo_settings.repodir)
		scanlist.append(catdir + "/" + reposplit[-1])
		# repo_subdir = scanlist[-1] + os.sep
	else:
		msg = 'Repoman is unable to determine PORTDIR or PORTDIR_OVERLAY' + \
			' from the current working directory'
		logging.critical(msg)
		sys.exit(1)

	# repo_subdir_len = len(repo_subdir)
	scanlist.sort()

	logging.debug(
		"Found the following packages to scan:\n%s" % '\n'.join(scanlist))

	return scanlist


class Changes(object):
	'''Class object to scan and hold the resultant data
	for all changes to process.

	Basic plan is move the spaghetti code here, refactor the code
	to split it into separate functions for each cvs type.
	Later refactoring can then move the individual scan_ functions
	to their respective VCS plugin module.
	Leaving this class as the manager class which runs the correct VCS plugin.
	This will ease future addition of new VCS types.
	'''

	def __init__(self, options):
		self.options = options
		self._reset()

	def _reset(self):
		self.new_ebuilds = set()
		self.ebuilds = set()
		self.changelogs = set()
		self.changed = []
		self.new = []
		self.removed = []

	def scan(self, vcs_settings):
		self._reset()

		if vcs_settings.vcs:
			vcscheck = getattr(self, 'scan_%s' % vcs_settings.vcs)
			vcscheck()

		if vcs_settings.vcs:
			self.new_ebuilds.update(x for x in self.new if x.endswith(".ebuild"))
			self.ebuilds.update(x for x in self.changed if x.endswith(".ebuild"))
			self.changelogs.update(
				x for x in chain(self.changed, self.new)
				if os.path.basename(x) == "ChangeLog")

	def scan_cvs(self):
		tree = cvstree.getentries("./", recursive=1)
		self.changed = cvstree.findchanged(tree, recursive=1, basedir="./")
		self.new = cvstree.findnew(tree, recursive=1, basedir="./")
		if self.options.if_modified == "y":
			self.removed = cvstree.findremoved(tree, recursive=1, basedir="./")
		del tree

	def scan_svn(self):
		with repoman_popen("svn status") as f:
			svnstatus = f.readlines()
		self.changed = [
			"./" + elem.split()[-1:][0]
			for elem in svnstatus
			if elem and elem[:1] in "MR"]
		self.new = [
			"./" + elem.split()[-1:][0]
			for elem in svnstatus
			if elem.startswith("A")]
		if self.options.if_modified == "y":
			self.removed = [
				"./" + elem.split()[-1:][0]
				for elem in svnstatus
				if elem.startswith("D")]

	def scan_git(self):
		with repoman_popen(
			"git diff-index --name-only "
			"--relative --diff-filter=M HEAD") as f:
			changed = f.readlines()
		self.changed = ["./" + elem[:-1] for elem in changed]
		del changed

		with repoman_popen(
			"git diff-index --name-only "
			"--relative --diff-filter=A HEAD") as f:
			new = f.readlines()
		self.new = ["./" + elem[:-1] for elem in new]
		if self.options.if_modified == "y":
			with repoman_popen(
				"git diff-index --name-only "
				"--relative --diff-filter=D HEAD") as f:
				removed = f.readlines()
			self.removed = ["./" + elem[:-1] for elem in removed]
			del removed

	def scan_bzr(self):
		with repoman_popen("bzr status -S .") as f:
			bzrstatus = f.readlines()
		self.changed = [
			"./" + elem.split()[-1:][0].split('/')[-1:][0]
			for elem in bzrstatus
			if elem and elem[1:2] == "M"]
		self.new = [
			"./" + elem.split()[-1:][0].split('/')[-1:][0]
			for elem in bzrstatus
			if elem and (elem[1:2] == "NK" or elem[0:1] == "R")]
		if self.options.if_modified == "y":
			self.removed = [
				"./" + elem.split()[-3:-2][0].split('/')[-1:][0]
				for elem in bzrstatus
				if elem and (elem[1:2] == "K" or elem[0:1] == "R")]

	def scan_hg(self):
		with repoman_popen("hg status --no-status --modified .") as f:
			changed = f.readlines()
		self.changed = ["./" + elem.rstrip() for elem in changed]
		with repoman_popen("hg status --no-status --added .") as f:
			new = f.readlines()
		self.new = ["./" + elem.rstrip() for elem in new]
		if self.options.if_modified == "y":
			with repoman_popen("hg status --no-status --removed .") as f:
				removed = f.readlines()
			self.removed = ["./" + elem.rstrip() for elem in removed]
			del removed
		del changed, new
