from __future__ import absolute_import
import logging
import urllib2
from contextlib import closing
import xml.etree.ElementTree as et
from StringIO import StringIO
from parallels.common.utils.config_utils import get_option
from parallels.utils.logging import BleepingLogger

class HttpClientError(Exception):
	def __init__(self, cause, content):
		self.cause = cause
		self.content = content

	def __str__(self): return repr(self)

	def __repr__(self):
		return "HttpClientError(%s, %r)" % (self.cause, self.content)

class HttpXmlClient(object):
	def __init__(self, url):
		log_context_length = get_option(
			'GLOBAL', 'log-message-context-length', 10)
		self.logger = BleepingLogger(
			logging.getLogger(__name__), xml_serializer=self._compose_xml,
			context_length=log_context_length)
		self.url = url
		
	def send_raw(self, data, extra=None):
		"""Send raw string.
		
		Returns a file-like object. It is caller's responsibility to close it.
		"""
		request = self._prepare_request_object(data, extra)
		try:
			return urllib2.urlopen(request)
		except urllib2.HTTPError as e:
			content = e.fp.read() if e.fp is not None else None
			raise HttpClientError(e, content)
		
	def send_xml(self, xml, extra=None):
		"""Serialize XML object and send an API request."""
		self.logger.debug(u"API request to %s:\n%s", self.url, xml)
		request = self._compose_xml(xml)
		response = self.send_raw(request, extra)
		with closing(response):
			tree = self._parse_xml(response)
		self.logger.debug(u"API response from %s:\n%s", self.url, tree)
		return tree
	
	def _compose_xml(self, xml):
		"""Serialize ElementTree XML object to string."""
		with closing(StringIO()) as buf:
			xml.write(buf, encoding='utf-8', xml_declaration=True)
			return buf.getvalue()

	def _parse_xml(self, response):
		tree = et.ElementTree()
		tree.parse(response)
		return tree

	def _prepare_request_object(self, data, extra=None):
		headers = {
			'Content-Type': 'text/xml',
			'Pragma': 'no-cache',
		}
		return urllib2.Request(self.url, data, headers)
