from contextlib import closing
from xml.etree import ElementTree

from parallels.core.actions.hosting_settings.transfer_error_documents import TransferErrorDocumentsBase
from parallels.core.utils.windows_utils import path_join as windows_path_join
from parallels.core.utils.error_docs_utils import  ErrorDocumentsXMLConverter
from parallels.source.hsphere import hsphere_utils
from parallels.core.utils.common import xml


class TransferErrorDocuments(TransferErrorDocumentsBase):
	def _get_site_error_documents(self, global_context, subscription, site):
		with closing(global_context.conn.hsphere.db()) as cursor:
			vhost_settings = hsphere_utils.get_site_vhost_settings(cursor, site.name)
			if vhost_settings is None:  # if domain has no IIS hosting, skip transfer of error documents
				return None
			(vhost_id, sysuser_name, vhosts_dir) = vhost_settings

			raw_error_docs_xml = self._get_error_docs(cursor, vhost_id, site.name, windows_path_join(vhosts_dir, sysuser_name))

		converter = self._create_converter(global_context)

		converted_error_docs_xml = converter.convert(subscription, site, raw_error_docs_xml)
		return converted_error_docs_xml

	def _get_site_vdir_error_documents(self, global_context, subscription, site):
		"""Return map: {vdir_name: error_documents_config_xml}
		"""
		converter = self._create_converter(global_context)

		with closing(global_context.conn.hsphere.db()) as cursor:
			vhost_settings = hsphere_utils.get_site_vhost_settings(cursor, site.name)
			if vhost_settings is None:  # if domain has no IIS hosting, skip transfer of error documents
				return None
			(vhost_id, sysuser_name, vhosts_dir) = vhost_settings

			vdirs_error_docs = {}
			cursor.execute(u"""
				SELECT wd.id, wd.dirname
				FROM iis_web_dir wd
				JOIN parent_child pc ON pc.child_id = wd.id
				WHERE pc.parent_id = %s
			""" % vhost_id)
			for (vdir_id, vdir_name) in cursor.fetchall():
				raw_vdir_error_docs_xml = self._get_error_docs(
					cursor, vdir_id, site.name, windows_path_join(vhosts_dir, sysuser_name)
				)
				converted_vdir_xml = converter.convert(
					subscription, site, raw_vdir_error_docs_xml
				)
				vdirs_error_docs[vdir_name] = converted_vdir_xml

			return vdirs_error_docs

	@staticmethod
	def _get_error_docs(cursor, parent_id, site_name, home_directory):
		errors_node = xml.elem('errors', [], {})
		cursor.execute(u"""SELECT code, subcode, type, msg FROM apache_edoc WHERE parent_id = %s""" % parent_id)
		for (code, subcode, doc_type, doc) in cursor.fetchall():
			if subcode == 0:
				code_str = '%d' % code
			else:
				code_str = "%d.%d" % (code, subcode)
			if doc_type == 2:  # URL
				errors_node.append(xml.elem('error', [], {'code': code_str, 'fileOnly': 'false', 'type': 'Url', 'location': u"http://%s%s" % (site_name, doc)}))  # FIXME it's wrong that we're forced to specify protocol. we don't know how end user came to this site, through http or through https. And redirecting it to the opposite protocol will be weird. But currently Plesk does not allow specifying a true URL-type error document.
			elif doc_type == 0:  # file
				errors_node.append(xml.elem('error', [], {'code': code_str, 'fileOnly': 'false', 'type': 'File', 'location': windows_path_join(home_directory, doc)}))

		return ElementTree.tostring(errors_node, 'utf-8', 'xml')

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