#!/usr/bin/env python

# Custom module
import lightCommon as lc

# For communicating with GPIO on Raspberry Pi
import RPi.GPIO as gpio

import socket

import sys,signal,os,time
import struct

from threading import Thread

# Global
lights = []

def handler(signum, frame):
    print 'Signal handler called with signal', signum
    s.close()
    
def findRelayActive(pin):
    # All we get here is a pin. This function is called by turnOn or turnOff
    
    # No error handling yet.
    relays = lc.getNodeProps()['relays']
    for relay in relays:
        if relay['relay_pin'] == pin:
            return relay['relay_active']
        
      

def turnOn(num):
    '''
    This function turns on a locally-connected light based
    on the light number. This SHOULD BE the only place where
    lc.on/off gets mapped to a T/F write to GPIO
    '''
    # First look up the relay_active property
    relay_on = findRelayActive(lights[num][lc.l_pin])
    
    try:
        gpio.output(lights[num][lc.l_pin],relay_on)   
        lights[num][lc.l_stat] = lc.on

    except KeyError as e:
        print 'KeyError in turnOn: ' + str(e)

def turnOff(num):
    '''
    This function turns off a locally-connected light based
    on the light number. This SHOULD BE the only place where
    lc.on/off gets mapped to a T/F write to GPIO
    '''
    # First look up the relay_active property
    relay_off = not findRelayActive(lights[num][lc.l_pin])
        
    try:
        gpio.output(lights[num][lc.l_pin],relay_off)   
        lights[num][lc.l_stat] = lc.off

    except KeyError as e:
        print 'KeyError in turnOff: ' + str(e)

def setLight(num, status, tif=0):
    '''
    This either calls turnOn or turnOff based on the status requested
    It also sends messages to all linked lights
    '''
    
    # tif is time in future. tif is how long this function will wait before
    # it actuates the light. This function should probably be threaded if 
    # tif > 0
    
    if tif > 0:
        time.sleep(tif)      
        
    if status == lc.on:
        turnOn(num)
    else:
        turnOff(num)

    for link in lights[num][lc.l_links]:
        lc.sendSetMsg(link[lc.link_node],link[lc.link_num],status,0)


def getStatus(num):
    '''
    Returns a light number's name and status (on, off)
    '''
    try:
        status = lights[num][lc.l_stat]
        name = lights[num][lc.l_name]
        return status, name
    except IndexError as e:
        print 'IndexError in getStatus: ' + str(e)

def serverLoop(s):
    # Never end... This is a server after all
    while s:
        # Accept a connection from any client
        conn, addr = s.accept()
        print str(time.time()) + ' Connection accepted from: ', addr
        # Clients to the server immediately send a message
        recv_msg = conn.recv(struct.calcsize(lc.packString))
        try:
            # Unpack the message
            req_type, light_num, light_status, time_in_future = struct.unpack(lc.packString,recv_msg)

            # For debugging
            print('req_type: %d light_num: %d light_status: %d time_in_future = %d' % (req_type, light_num, light_status, time_in_future) )

            # Query that state of one light
            if ( req_type == lc.msg_info ):
                print 'msg_info'
                light_status, light_name = getStatus(light_num)
                print light_num,light_status,light_name
                send_msg = struct.pack(lc.queryPackString,req_type,light_num,light_status,light_name)
                conn.send(send_msg)

            # Set the state of one light
            elif ( req_type == lc.msg_set ):
                print 'msg_set'
                print light_num, light_status, time_in_future
                Thread(target=setLight,args=(light_num, light_status, time_in_future,)).start()
                
            # Query all the lights available
            elif ( req_type == lc.msg_dump ):
                print 'msg_dump'
                for light in lights:
                    light_num = lights.index(light)
                    light_status, light_name = getStatus(light_num)                    
                    print req_type,light_num, light_status, light_name
                    send_msg = struct.pack(lc.queryPackString,req_type,light_num,light_status,light_name)
                    conn.send(send_msg)

            else:
                print('Incorrect request type: %d' % (req_type) )

        # If a light is requested that doesn't exist
        except KeyError: