from parallels.ppa.source.helm4 import messages
import logging
import xml.etree.ElementTree as et
import os

from parallels.core.actions.hosting_settings.transfer_error_documents import TransferErrorDocumentsBase
from parallels.core.utils.error_docs_utils import ErrorDocumentsXMLConverter
from parallels.core.utils.common import xml
from parallels.ppa.source.helm4 import helm_utils
from parallels.core.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(messages.LOG_EXCEPTION, exc_info=True)
			logger.error(messages.CANNOT_GET_ERROR_DOCUMENTS_FOR_DOMAIN % (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

