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.ppa.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',
					# 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.
					'location': u"http://%s%s" % (site_name, doc)
				}))
			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