#!/usr/bin/env python

#
# Based on simulated XIA PFCU-4 filter controller.
#
# For usage, see my printUsage function or run me with my -h option.
#

import getopt
import asynchat
import asyncore
import os
#import re
import signal
import socket
import sys
#import time

DEFAULT_PORT = 31337

def main(args):
	(port, isDebugOutputEnabled) = parseCommandLineArgs(args)
	d = ConnectionDispatcher(port, isDebugOutputEnabled)
	asyncore.loop()

def getProgramName(args=None):
  if args == None: args = sys.argv
  if len(args) == 0 or args[0] == "-c": return "PROGRAM_NAME"
  return os.path.basename(args[0])

def parseCommandLineArgs(args):
  (options, extra) = getopt.getopt(args[1:], "dp:h", ["debug", "port=",
    "help"])

  port = DEFAULT_PORT
  isDebugOutputEnabled = False

  for eachOptName, eachOptValue in options:
    if eachOptName in ("-d", "--debug"):
      isDebugOutputEnabled = True
    elif eachOptName in ("-p", "--port"):
      port = int(eachOptValue)
    elif eachOptName in ("-h", "--help"):
      printUsage(sys.stdout)
      sys.exit(0)

  if len(extra) > 0:
    print >> sys.stderr, "Error: unexpected command line argument \"%s\"" % \
      extra[0]
    printUsage(sys.stderr)
    sys.exit(1)

  return (port, isDebugOutputEnabled)

def printUsage(outStream):
  print >> outStream, """\
Usage: %s [-dph]

Options:
  -d,--debug        Print debug messages to stderr
  -p,--port=NUMBER  Listen on the specified port NUMBER for incoming
                    connections (default: %d)
  -h,--help         Print usage message and exit\
""" % (getProgramName(), DEFAULT_PORT)

class ConnectionDispatcher(asyncore.dispatcher):
  def __init__(self, port, debugOutputEnabled=False):
    asyncore.dispatcher.__init__(self)
    self.port = port
    self.debugOutputEnabled = debugOutputEnabled
    # xia pfcu 4 example used 16 devices
    self.device = KevinRelay()
    self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
    self.set_reuse_addr()
    self.bind(("", port))
    self.listen(5)
  
  def handle_accept(self):
    ConnectionSession(self.accept(), self.device, self.debugOutputEnabled)

class ConnectionSession(asynchat.async_chat):
  ## regular expressions, if necessary, can go here
  
  def __init__(self, (conn, addr), device, debugOutputEnabled=False):
    asynchat.async_chat.__init__(self, conn)
    self.debugOutputEnabled = debugOutputEnabled
    self.set_terminator("\r")
    self.outputTerminator = "\r\n"
    self.device = device
    self.buffer = ""
    
  def collect_incoming_data(self, data):
    self.buffer = self.buffer + data
    
  def found_terminator(self):
    data = self.buffer
    self.buffer = ""
    if self.debugOutputEnabled:
      print >> sys.stderr, "< \"%s\"" % \
        (data + self.get_terminator()).encode("string_escape")
    self.handleClientRequest(data)
    
  def handleClientRequest(self, request):
    request = request.strip()

    #print request
    ## handle actual commands here
    
    if len(request) >= 2:
      if request[0] == chr(254):
        ## NOTE chr(254) is 376 in octal
        if request[1] == chr(0):
          # turn off relay 1
          print("Turn off relay 1")
          self.device.setRelayState(0, 0)
        
        elif request[1] == chr(1):
          # turn on relay 1
          print("Turn on relay 1")
          self.device.setRelayState(0, 1)
          
        elif request[1] == chr(2):
          # turn off relay 2
          print("Turn off relay 2")
          self.device.setRelayState(1, 0)
        
        elif request[1] == chr(3):
          # turn on relay 2
          print("Turn on relay 2")
          self.device.setRelayState(1, 1)
          
        elif request[1] == chr(4):
          # get relay 1 status
          print("Get relay 1 status")
          status = self.device.getRelayState(0)
          self.sendClientResponse("%i" % status)
          
        elif request[1] == chr(5):
          # get relay 2 status
          print("Get relay 2 status")
          status = self.device.getRelayState(1)
          self.sendClientResponse("%i" % status)
          
        else:
          print("Other commands not implemented yet")

      else:
        print("First char wasn't the 254")

    else:
      print("Command wasn't at least two characters")
      ##
    return

  def sendClientResponse(self, response=""):
    data = response + self.outputTerminator
    self.push(data)
    if self.debugOutputEnabled:
      print >> sys.stderr, "> \"%s\"" % data.encode("string_escape")

class KevinRelay:

  def __init__(self):
    self.relayStates = [0, 0]
    
  def getRelayState(self, relay):
    return self.relayStates[relay]
  
  def setRelayState(self, relay, state):
    self.relayStates[relay] = state


if __name__ == '__main__':
  try:
    # command omitted
  	main(sys.argv)
  except Exception, e:
    if isinstance(e, SystemExit):
      raise e
    else:
      print >> sys.stderr
      print >> sys.stderr, "Error: %s" % e
      sys.exit(1)