"""
EUD1_Dev -Python Code
(v1.0)

Developer: Microbob
Contact: microbob@is88.com
Library credits: kennethreitz (requests), Python (socket, threading, logging), and pySerial
"""
import requests
import socket
import threading
import logging
import serial

#signal to show that the app has started
print 'Started'

# MCS web console data
DEVICE_INFO = {'device_id': 'xxxxxxxx',
               'device_key': 'xxxxxxxxxxxxxxxx'}

# setup logging
logging.basicConfig(level='INFO')

#setup variable to handle heartBeat signals
heartBeatTask = None

#setup variable serial
ss = None

#data channel ids
timedatachannel="time"


#function to setup internal serial connection with Arduino side
def setup():
    global ss
    ss = serial.Serial('/dev/ttyS0', 57600)


#function to create and connec to a channel to recieve data
def establishCommandChannel():
    connectionAPI = \
        'https://api.mediatek.com/mcs/v2/devices/%(device_id)s/connections.csv'
    r = requests.get(connectionAPI % DEVICE_INFO,
                     headers={'deviceKey': DEVICE_INFO['device_key'],
                     'Content-Type': 'text/csv'})
    logging.info('Command Channel IP, port=' + r.text)
    (ip, port) = r.text.split(',')

    # conect to command server
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((ip, int(port)))
    s.settimeout(None)

    # heartbeat to keep channel alive
    def sendHeartBeat(commandChannel):
        keepAliveMessage = '%(device_id)s,%(device_key)s,0' \
            % DEVICE_INFO
        commandChannel.sendall(keepAliveMessage)
        logging.info('beats:%s' % keepAliveMessage)

    def heartBeat(commandChannel):
        sendHeartBeat(commandChannel)

        # restart timer
        global heartBeatTask
        heartBeatTask = threading.Timer(40, heartBeat,
                [commandChannel]).start()

    heartBeat(s)
    return s #channel "id" and data


#wait for serial confirmation from Arduino (confirming that it has recieved the previous sent data point)
def waitForConfirm():
    while True:
        fromBoard = ss.read()
        print fromBoard
        if fromBoard == '1':
            break


#"main" function. When data comes through the commandChannel, it will interpret and run code based on what it got
def waitAndExecuteCommand(commandChannel):
    while True:
        command = commandChannel.recv(1024)
        logging.info('recv:' + command)

        # put in try/except clause because the "command" variable might not have any data
        try:
            #split incomming data to figure out its message type
            messageType = command.split(',')[3] #data channel name will always be the fourth entry (if splitted by ",")
            inData = command.split('%s,' % messageType)[1] #by splitting the data by the messageType+",",
                                                           #you will split the devicekey/id and that data from the content of the data

            #message data clauses will be split by two "#", split the data content by "##" to get the
            #"Upper" data is: email from address, calendar event name, or notification title/name
            #"Lower" data is: email subject, calendar event start time, or notificaiton details
            if messageType!=timedatachannel: #if message type isn't time, then it must be a notification.
                splitted = inData.split('##') #split data to upper and lower

                #set upper and lower variables
                upper = splitted[0]
                lower = splitted[1]
                print 'Upper: %s, Lower: %s' % (upper, lower)

                #send data (over serial) to Arduino
                ss.write('MT: %s' % messageType) #send message type
                print "sent MT"
                waitForConfirm() #wait for Arduino to confirm that it has recieved
                print "confirmed"
                ss.write(upper) #send upper data
                print "sent upper"
                waitForConfirm() #wait for Arduino to confirm that it has recieved
                print "confirmed"
                ss.write(lower) #send lower data
                print "sent lower"
            else: #message type is time, start time setup
                #conversion dict for month
                monthNum={"January":1,"February":2,"March":3,"April":4,"May":5,"June":6,"July":7,"August":8,"September":9,"October":10,"November":11,"December":12}

                #time data comes in a wierd format: MONTH DD, YYYY "at" HH:MMAM/PM, ie March 18, 2017 at 08:47PM
                #utilize python's data manipulation powers to split data and format it to be entered into the DS3231 RTC
                print "splitting time data"
                timeparts=inData.split(' ') #split data by " "
                mmth=monthNum[timeparts[0]] #enter and convert month data (the 1st item in timeparts)
                ddte=timeparts[1][0:2] #cut the 1st two characters in the 2nd item in timeparts (DD, -> DD)
                yyrs=timeparts[2] #get 3rd item in timeparts (YYYY)
                hhrs=timeparts[4][0:2] #cut the 1st two characters in the 4th item in timeparts (HH:MMAM/PM -> HH)
                hrs=int(hhrs) #convert into int, may add 12 if AM/PM is PM
                mmin=timeparts[4][3:5] #cut the 4th and 5th character in the 4th item in timeparts (HH:MMAM/PM -> MM)

                #add 12 if AM/PM is PM
                if timeparts[4][5:]=="PM": #cut the 6th and whatever comes after that (7th) character in the 4th item in timeparts (HH:MMAM/PM -> AM/PM)
                    hrs+=12
                #set hrs to 0 if HH si 24
                if hrs==24:
                    hrs=0
                hhrs=str(hrs) #convert back to string

                print "prompt time data to arduino"
                ss.write('MT: time') #send MT as time to Arduino
                print "wait for confirm"
                waitForConfirm() #wait for Arduinot to confirm that it has recieved
                print "confirmed, sending minutes"
                ss.write(mmin) #send minutes
                print "sent, waiting for confirmation"
                waitForConfirm() #wait for Arduinot to confirm that it has recieved
                print "confirmed, sending hours"
                ss.write(hhrs) #send hours
                print "sent, waiting for confirmation"
                waitForConfirm() #wait for Arduinot to confirm that it has recieved
                print "confirmed, sending date"
                ss.write(ddte) #send date
                print "sent, waiting for confirmation"
                waitForConfirm() #wait for Arduinot to confirm that it has recieved
                print "confirmed, sending month"
                ss.write(mmth) #send month
                print "sent, waiting for confirmation"
                waitForConfirm() #wait for Arduinot to confirm that it has recieved
                print "confirmed, sending year"
                ss.write(yyrs) #send years
                print "sent, done"
        except Exception: #if there is no data...
            print "haven't recieved yet..."


if __name__ == '__main__': #program loop
    setup() #setup serial connection
    channel = establishCommandChannel() #set channel data
    waitAndExecuteCommand(channel)

