import os, sys, time, socket
from marshal import dumps, loads
from WebKit.Object import Object
from MiscUtils.Configurable import Configurable
import struct, errno

class Adapter(Configurable, Object):

	def __init__(self, webKitDir):
		Configurable.__init__(self)
		Object.__init__(self)
		self._webKitDir = webKitDir
		self._respData = ''

	def name(self):
		return self.__class__.__name__

	def defaultConfig(self):
		return {
			'NumRetries':            20,
			'SecondsBetweenRetries': 3
		}

	def configFilename(self):
		return os.path.join(self._webKitDir, 'Configs/%s.config' % self.name())

	def transactWithAppServer(self, env, myInput, host, port):
		"""
		Used by subclasses that are communicating with a separate app server via
		socket.  Returns the unmarshaled response dictionary.
		"""
		dict = {
				'format': 'CGI',
				'time':   time.time(),
				'environ': env,
				}

		# @@ gat 2002-03-21: Changed retry strategy.  Now, we'll only retry the initial
		# connection to the appserver.  After that, any failure means the request failed.
		# This is to avoid processing a request twice.
		retries = 0
		while 1:
			try:
				# Send our request to the AppServer
				s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
				s.connect((host, port))
				break
			except socket.error:
				# retry
				if retries <= self.setting('NumRetries'):
					retries = retries + 1
					time.sleep(self.setting('SecondsBetweenRetries'))
				else:
					raise 'timed out waiting for connection to app server'

		data = dumps(dict)
		s.send(dumps(int(len(data))))
		s.send(data)
		
		sent=0				
		inputLength = len(myInput)
		while sent < inputLength:
			chunk = s.send(myInput[sent:])
			sent = sent+chunk
		s.shutdown(1)

		# Get the response from the AppServer
		bufsize = 8*1024
		# @@ 2000-04-26 ce: this should be configurable, also we should run some tests on different sizes
		# @@ 2001-01-25 jsl: It really doesn't make a massive difference.  8k is fine and recommended.
		
##		s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, struct.pack('ll',0,5)) #wait for 0.5 seconds for data
		while 1:
			data = s.recv(bufsize)
			if not data:
				break
			self.processResponse(data)
		return self._respData


	def processResponse(self, data):
		""" Process response data as it arrives."""
		self._respData = self._respData + data
		
