import logging
import xml.etree.ElementTree as et
import os

from parallels.common.actions.hosting_settings.transfer_error_documents import TransferErrorDocumentsBase
from parallels.common.utils.error_docs_utils import ErrorDocumentsXMLConverter
from parallels.utils import xml
from parallels.helm_migrator import helm_utils
from parallels.common.utils.windows_utils import path_join as windows_path_join


logger = logging.getLogger(__name__)


class TransferErrorDocuments(TransferErrorDocumentsBase):
	def _get_site_error_documents(self, global_context, subscription, site):
		domain_id = helm_utils.get_domain_id_by_name(
			global_context.conn, site.name
		)
		if domain_id is None:
			return None

		return self._get_error_documents(global_context, subscription, site, domain_id)

	def _get_site_vdir_error_documents(self, global_context, subscription, site):
		error_docs = self._get_site_error_documents(global_context, subscription, site)
		if error_docs is None:
			return None

		vdirs_error_docs = {}
		domain_id = helm_utils.get_domain_id_by_name(global_context.conn, site.name)
		vdirs = helm_utils.get_vdir_list(
			global_context.conn, site.name, domain_id
		)
		for vdir in vdirs:
			vdirs_error_docs[vdir.attrib['path']] = error_docs

		return vdirs_error_docs

	def _get_error_documents(self, global_context, subscription, site, domain_id):
		errors_node = xml.elem('errors', [], {})
		try:
			helm_config = global_context.conn.helm.conn_settings
			migration_tool_path = os.path.join(helm_config.migration_tool_dir, helm_config.migration_tool_name)

			with global_context.conn.helm.runner() as helm_runner:
				error_documents_xml = helm_runner.sh('{migration_tool_path} --error-documents {domain_id}',
						dict(migration_tool_path=migration_tool_path, domain_id=domain_id))
		except Exception as e:
			logger.debug(u'Exception:', exc_info=e)
			logger.error(u"Can't get error documents for domain '%s', error is '%s'; skip error documents for this domain. Check the connection to the control server and make sure that the version of Helm installed there is supported by the migrator." % (site.name, e))
			return None

		error_documents = et.fromstring(error_documents_xml).findall('.//httperror')

		if not error_documents:
			return None

		for error_document in error_documents:
			doc_type = error_document.attrib['type']
			if doc_type == "2":	# Absolute URL
				errors_node.append(xml.elem('error', [], {'code': error_document.attrib['code'], 'fileOnly': 'false', 'type': 'Url', 'location': u"%s" % (error_document.attrib['path'])}))
			if doc_type == "1":	# Relative URL
				errors_node.append(xml.elem('error', [], {'code': error_document.attrib['code'], 'fileOnly': 'false', 'type': 'Url', 'location': u"http://%s%s" % (site.name, error_document.attrib['path'])}))
			elif doc_type == "0":	# file
				home_directory  = helm_utils.get_helm_vhost_dir(
					global_context.conn, subscription.name
				)
				path = error_document.attrib['path']
				path = path.lstrip('\\')
				if path.startswith('wwwroot'):
					path = 'httpdocs' + path[len('wwwroot'):]
				errors_node.append(xml.elem('error', [], {'code': error_document.attrib['code'], 'fileOnly': 'false', 'type': 'File', 'location': windows_path_join(home_directory, path)}))

		raw_error_docs = et.tostring(errors_node, 'utf-8', 'xml')
		converter = self._create_converter(global_context)
		return converter.convert(subscription, site, raw_error_docs)

	@staticmethod
	def _create_converter(global_context):
		path_converter = helm_utils.PathConverter(global_context)
		converter = ErrorDocumentsXMLConverter()
		converter.set_path_convert_function(path_converter.convert)
		return converter

