#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-

'''
LJnano

v0.1b

Open localhost websocket 9001

Write Redis keys : 

- '/trckr/frame/WSclientid' : TrckrPts
- 'WSclients' : [{'id': 1, 'handler': <websocket_server.WebSocketHandler object at 0x114d35880>, 'address': ('127.0.0.1', 62718)}, {'id': 2, 'handler': <websocket_server.WebSocketHandler object at 0x114d35d60>, 'address': ('127.0.0.1', 62720)}]

'''
from __future__ import print_function
import websocket
import time
import argparse
import traceback
import sys
import random
from websocket_server import WebsocketServer
import redis
from socket import *

try:
    import thread
except ImportError:
    import _thread as thread

name = "exports::ljnano"

def debug(*args, **kwargs):
    if( verbose == False ):
        return
    print(*args, file=sys.stderr, **kwargs)

argsparser = argparse.ArgumentParser(description="ljnano v0.1b help mode")
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
argsparser.add_argument("-s","--server",help="WS server IP (127.0.0.1 by default)", type=str)
argsparser.add_argument("-p","--port",help="WS port to bind to (9001 by default)", type=str)
argsparser.add_argument("-k","--key",help="Redis key to update",default="0",type=str)
args = argsparser.parse_args()

key = args.key

if args.verbose:
    verbose = True
else:
    verbose = False

if args.server:
    serverIP = args.server
else:
    serverIP = "127.0.0.1"

if args.port:
    wsPORT = args.port
else:
    wsPORT = 9001

print("")
print("LJnano v0.1b")

points0 = "[(-150.0, 230.0, 65280), (-70.0, -170.0, 65280), (310.0, -170.0, 65280), (210.0, 230.0, 65280), (-150.0, 230.0, 65280)]"
points1 = "[(200.0, 170.0, 65280), (-180.0, -230.0, 65280)]"
points2 = "[(170.0, 190.0, 65280), (200.0, 170.0, 65280), (230.0, 190.0, 65280), (230.0, 200.0, 65280), (170.0, 230.0, 65280), (230.0, 230.0, 65280)]"
points3 = "[(170.0, 170.0, 65280), (200.0, 170.0, 65280), (230.0, 190.0, 65280), (200.0, 200.0, 65280), (230.0, 210.0, 65280), (200.0, 230.0, 65280), (170.0, 230.0, 65280)]"
points = [points0, points1, points2, points3]

LaserNumber = 1
SceneNumber = 0
Laser = 0


#
# Redis
#

r = redis.StrictRedis(host=serverIP , port=6379, db=0)

# read from redis key
def fromKey(keyname):

   return r.get(keyname)
 
# Write to redis key 
def toKey(keyname,keyvalue):

   #print(keyname,keyvalue)
   # Store encoded data in Redis
   return r.set(keyname,keyvalue)

# event key can be like "/midi/last_event"
# Send en event to eventkey (publish)
def toKeyevent(eventkey,eventname):

    print("redis midi event key :", eventname)
    r.publish(eventkey, eventname)

# examples 
#if toKey("/clientkey","/pl/"+str(gstt.SceneNumber)+"/")==True:
#    print("sent clientkey : /pl/"+str(gstt.SceneNumber)+"/")

# toKeyevent("/midi/noteon/"+str(MidiChannel)+"/"+str(MidiNote)+"/"+str(MidiVel))

    
def custom_handler(message):
       # do_something with the message
       print(message)
'''
p.psubscribe(**{'hello*':custom_handler})
thread = p.run_in_thread(sleep_time=0.001)
'''



# Change current laser.
def NoteOn(note):
    debug("NoteOn", note)

    # Change laser client
    if note < 8:

        Laser = note
        debug("Current Laser switched to", Laser)
        sendWSall("/status Laser " + str(Laser))
        sendWSall("/simul" +" "+ points[Laser])
    
    # Change PL displayed on webui
    if  note > 23 and note < 32:
        if note - 24 > LaserNumber -1:
            debug("Only",LaserNumber,"lasers asked, you dum ass !")
            sendWSall("/redstatus No Laser"+str(note-24))
            sendWSall("/laser "+str(LaserNumber-1))
            sendWSall("/simul" +" "+ points[LaserNumber-1])
        else: 
            Laser = note -24
            debug("Current Laser switched to", Laser)
            sendWSall("/status Laser " + str(Laser))
            sendWSall("/simul" +" "+ points[Laser])


def sendbroadcast():

    debug("Sending broadcast")
    cs = socket(AF_INET, SOCK_DGRAM)
    cs.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    cs.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
    cs.sendto("LJ nano 0.1".encode(), ("255.255.255.255", 54545))

            
#
# Websocket server
# 

def client_list():

    clients = []
    for client in wserver.clients_list():
        clients.append(client['id'])
        #print(clients)
    return str(clients)

# Called for every WS client connecting (after handshake)
def new_client(client, wserver):

    debug("WS server got new client connected and was given id %d" % client['id'])
    toKey('WSclients', client_list())
    sendWSall("/status nano:Hello " + str(client['id']))
    sendWSall("/laser "+str(0))
    sendWSall("/lack/" + str(0) + " 3")
    sendWSall("/lstt/" + str(0) + " 3")  
    sendWSall("/simul" +" "+ points[0])


# Called for every WS client disconnecting
def client_left(client, wserver):

    try:
      debug("WS server had client(%d) disconnected" % client['id'])

    except:
      debug("Something weird if coming from",client,"on the wire...")
      pass



# Called for each WS received message.
def message_received(client, wserver, message):

    #if len(message) > 200:
    #    message = message[:200]+'..'    
    
    oscpath = message.split(" ")
    #print("WS Client", client['id'], "said :", message, "splitted in an oscpath :", oscpath)
    #if( verbose == True ):
    #   debug("WS server's client", client['id'], "said :", message)

    if message[0:5] == "/simu":
        debug("WS server sending to simu page :",message)
        sendWSall(message)

    if message[0:7] == "/noteon":
        oscpath = message.split(" ")
        debug("WS server got new laser", int(oscpath[1]))
        NoteOn(int(oscpath[1]))


    # Get WS /aurora/trckr/frame layernumber framenumber points
    # Set redis /trckr/frame/WSclientID points
    if message.find('trckr/frame') > 0:

        args = message.split(" ")
        TrckrPts = []
        for dot in range(3,len(args)-1,2):
            TrckrPts.append([float(args[dot]), float(args[dot+1])])
        
        debug('/trckr/frame/'+str(client['id'])+" "+str(TrckrPts))
        toKey('/trckr/frame/'+str(client['id']),str(TrckrPts))

def sendWSall(message):
    if ( verbose == True ):
        debug("WS server is sending to all : %s" % (message))
    wserver.send_message_to_all(message)


def LaunchServer(*args):
    global wserver

    try:

        # Websocket server
        wserver = WebsocketServer(wsPORT,host=serverIP)
   
        print("Launching Websocket server at", serverIP, "port",wsPORT)
        wserver.set_fn_new_client(new_client)
        wserver.set_fn_client_left(client_left)
        wserver.set_fn_message_received(message_received)
        print("Nano is running. Open/reload www/simulocal.html in a browser !")
        print()

        # websocket server loop
        wserver.run_forever()
        

    except EOFError:
        debug("break")# no more information

    finally:
    
        debug("sendWS terminating...")


#
# Launch WS server 
#

if __name__ == "__main__":

    try:

        LaunchServer()

    except Exception:
        debug("nano Exception")
        traceback.print_exc()
    