# -*- coding: utf-8 -*-

import pycurl
import StringIO

import sys

from base import *

class CurlRequestException(Exception):
	def __init__(self, value): self.value = value
	def __str__(self): return repr(self.value)

class CurlRequest(TestBase):
	URL = None
	SCHEME = "http"
	PORT = 0 # offset to Env.port
	AUTH = None

	EXPECT_RESPONSE_BODY = None
	EXPECT_RESPONSE_CODE = None
	EXPECT_RESPONSE_HEADERS = []

	def __init__(self):
		super(CurlRequest, self).__init__()
		self.resp_header_list = []
		self.resp_headers = { }
		self.resp_first_line = None

	def _recv_header(self, header):
		header = header.rstrip()
		if None == self.resp_first_line:
			self.resp_first_line = header
			return
		if header == "":
			return
		try:
			(key, value) = header.split(":", 1)
		except:
			print >> sys.stderr, "Couldn't parse header '%s'" % header
			raise
		key = key.strip()
		value = value.strip()
		self.resp_header_list.append((key, value))
		if self.resp_headers.has_key(key):
			self.resp_headers[key] += ", " + value
		else:
			self.resp_headers[key] = value

	def Run(self):
		if None == self.URL:
			raise BasicException("You have to set URL in your CurlRequest instance")
		c = pycurl.Curl()
		c.setopt(pycurl.URL, self.SCHEME + ("://127.0.0.1:%i" % (Env.port + self.PORT)) + self.URL)
		c.setopt(pycurl.HTTPHEADER, ["Host: " + self.vhost])
		c.setopt(pycurl.NOSIGNAL, 1)
		c.setopt(pycurl.TIMEOUT, 10)
		b = StringIO.StringIO()
		c.setopt(pycurl.WRITEFUNCTION, b.write)
		c.setopt(pycurl.HEADERFUNCTION, self._recv_header)

		if None != self.AUTH:
			c.setopt(pycurl.USERPWD, self.AUTH)
			c.setopt(pycurl.FOLLOWLOCATION, 1)
			c.setopt(pycurl.MAXREDIRS, 5)

		self.curl = c
		self.buffer = b

		self.PrepareRequest()

		c.perform()

		try:
			if not self._checkResponse():
				raise CurlRequestException("Response check failed")
		except:
			if not Env.debugRequests:
				self.dump()
			raise
		finally:
			c.close()
			self.curl = None

		return True

	def PrepareRequest(self):
		pass

	def dump(self):
		c = self.curl
		Env.log.flush()
		print >> Env.log, "Dumping request for test '%s'" % self.name
		print >> Env.log, "Curl request: URL = %s://%s:%i%s" % (self.SCHEME, self.vhost, Env.port + self.PORT, self.URL)
		print >> Env.log, "Curl response code: %i " % (c.getinfo(pycurl.RESPONSE_CODE))
		print >> Env.log, "Curl response headers:"
		for (k, v) in self.resp_header_list:
			print >> Env.log, "  %s: %s" % (k, v)
		print >> Env.log, "Curl response body:"
		print >> Env.log, self.buffer.getvalue()
		Env.log.flush()

	def _checkResponse(self):
		c = self.curl
		if Env.debugRequests:
			self.dump()

		if not self.CheckResponse():
			return False

		if None != self.EXPECT_RESPONSE_CODE:
			code = c.getinfo(pycurl.RESPONSE_CODE)
			if code != self.EXPECT_RESPONSE_CODE:
				raise CurlRequestException("Unexpected response code %i (wanted %i)" % (code, self.EXPECT_RESPONSE_CODE))

		if None != self.EXPECT_RESPONSE_BODY:
			body = self.buffer.getvalue()
			if body != self.EXPECT_RESPONSE_BODY:
				raise CurlRequestException("Unexpected response body")

		for (k, v) in self.EXPECT_RESPONSE_HEADERS:
			if not self.resp_headers.has_key(k):
				raise CurlRequestException("Didn't get wanted response header '%s'" % (k))
			v1 = self.resp_headers[k]
			if v1 != v:
				raise CurlRequestException("Unexpected response header '%s' = '%s' (wanted '%s')" % (k, v1, v))

		return True

	def CheckResponse(self):
		return True
