import os
import sys
import time
import datetime
import syslog
import boto.sqs
import boto.sqs.message
from boto.exception import SQSError
import boto.utils

#####
##### Subroutines ######
#####
def myLog(message, toSyslog=False):
	procName = __file__
	print '%s' % message
	sys.stdout.flush()
		
	if toSyslog:
		syslogMsg = procName + ": " + message
		syslog.syslog(syslogMsg)

def findQueues(sqsConn,pattern):
	myLog("Looking for queues containing pattern %s" % pattern)
	
	matchingQueues = []
	
	queues = sqsConn.get_all_queues()
	
	for queue in queues:
		if verbose: myLog("Found queue %s" % queue.name)
		if pattern in queue.name:
			if verbose: myLog("Found matching queue %s" %queue.name)
			matchingQueues.append(queue.name)
	
	return matchingQueues

def replaceMessage(queueName,sourceStr):
	# get a message from the queue, delete it and add a new one

	if verbose: myLog("replaceMessage: queueName %s" % queueName)

	retVal = None
	readAttempts = 10
	readDelay = 10

	queueObj = sqsConn.get_queue(queueName)

	if (queueObj):
	  if verbose: myLog("replaceMessage: Successfully found SQS queue")
	  currentReadAttempt = 0

	  while currentReadAttempt <= readAttempts:
		if verbose: myLog("replaceMessage: Reading from queue - attempt %s" % currentReadAttempt)
		messages = queueObj.get_messages(1)
		if ( len(messages) == 0 ):
		  # We did not get the message - sleep and try again
		  myLog("replaceMessage: No messages read from queue - retrying in %i seconds" % readDelay)
		  time.sleep(readDelay)
		else:
		  # We did get the message - delete it and post a new one
		  if verbose: myLog("replaceMessage: message read from queue")

		  if ( queueObj.delete_message(messages[0]) ):
			if verbose: myLog("replaceMessage: Successfully removed lock message from queue")

			datetimeStr = datetime.datetime.now().strftime("%I:%M%p %B %d, %Y")
			body = "Keep-alive message generated by " + sourceStr + " on " + datetimeStr

			myMessage = boto.sqs.message.RawMessage()
			myMessage.set_body(body)
			try:
			  if verbose: myLog("replaceMessage: Writing new message to SQS queue")
			  queueObj.write(myMessage)
			  retVal = True
			  break
			except SQSError, e:
			  myLog("replaceMessage: Unable to write message to SQS queue")
			  myLog("replaceMessage: Error %s - %s" % (e.code,  str(e)))

		  else:
			myLog("replaceMessage: Error removing lock message from queue")

		currentReadAttempt +=1
	else:
	  myLog("replaceMessage: Unable to create queue object for queue name %s" % queueName)

	return retVal	

####	
#### MAINLINE ####
####

verbose = os.environ.get("VERBOSE")
if verbose is None:
	verbose = False
else:
	verbose = True

frequency = os.environ.get('FREQUENCY')
if frequency is None:
	frequency = 86400
else:
	frequency = int(frequency)
	
SQS_queue_pattern = os.environ.get('SQS_NAME_PATTERN')
if SQS_queue_pattern is None:
	SQS_queue_pattern = "EIPQueue"			

region_exclude_str = os.environ.get('EXCLUDE_REGIONS')
if region_exclude_str is None:
	region_exclude_str = "cn-north-1,us-gov-west-1"

exclude_regions_list = region_exclude_str.split(",")
	
datetimeStr = datetime.datetime.now().strftime("%I:%M%p %B %d, %Y")
myLog("Queue keep-alive service starts at %s" % datetimeStr)
myLog("verbose: %s frequency: %d pattern: %s" % (verbose,frequency,SQS_queue_pattern))

while True:
	SQS_regions = boto.sqs.regions()

	for region in SQS_regions:
		regionName = region.name
		if regionName in exclude_regions_list:
			myLog("++++ Region %s is excluded - will not check" % regionName)
			next
		else:
			myLog("*** Checking queues for region %s" % regionName)
			sqsConn = boto.sqs.connect_to_region(regionName)
			sqsQueues = findQueues(sqsConn,SQS_queue_pattern)
			
			for sqsQueue in sqsQueues:
				myLog("Handling message for queue %s" % sqsQueue)
				
				if ( replaceMessage(sqsQueue,"SQS keep-alive service") ):
					myLog("Successfully posted new message to SQS queue")
				else:
					myLog("Unable to post keep-alive message to SQS queue")
	
	datetimeStr = datetime.datetime.now().strftime("%I:%M%p %B %d, %Y")
	myLog("Queue keep-alive service completes at %s (next run in %d seconds)" % (datetimeStr,frequency))
	
	time.sleep(frequency)
