#!/usr/bin/env python
import getopt
import socket
import sys
import cbor
#from cbor2 import dumps, loads
import json
import time
import traceback

from coapthon.client.helperclient import HelperClient
from coapthon.utils import parse_uri
from coapthon import defines

client = None
paths = {}
paths_extend = {}

my_base = ""


def usage():  # pragma: no cover
    print("Command:\tknxcoapclient.py -o -p [-P]")
    print("Options:")
    print("\t-o, --operation=\tGET|GETNONE|PUT|POST|DELETE|DISCOVER|OBSERVE")
    print("\t-p, --path=\t\t\tPath of the request")
    print("\t-P, --payload=\t\tPayload of the request")
    print("\t-c, --contenttype=\t\tcontenttype of the request")
    print("\t-f, --payload-file=\t\tFile with payload of the request")


def get_url(line):
    data = line.split(">")
    url = data[0]
    return url[1:]

def get_ct(line):
    tagvalues = line.split(";")
    for tag in tagvalues:
       if tag.startswith("ct"):
          ct_value_all = tag.split("=")
          ct_value = ct_value_all[1].split(",")
          return ct_value[0]
    return ""

def get_base(url):
    # python3 knxcoapclient.py -o GET -p coap://[fe80::6513:3050:71a7:5b98]:63914/a -c 50
    my_url = url.replace("coap://","")
    mybase = my_url.split("/")
    return mybase[0]


def get_base_from_link(payload):
    print("get_base_from_link\n")
    global paths
    global paths_extend
    lines = payload.splitlines()
    
    # add the 
    if len(paths) == 0:
        my_base = get_base(get_url(lines[0]))
        return my_base
        

def get_sn(my_base):
    print("Get SN :");
    sn = execute_get("coap://"+my_base+"/dev/sn", 60)
    json_data = cbor.loads(sn.payload)
    #print ("SN : ", json_data)
    return json_data

def install(my_base):
    sn = get_sn(my_base)
    print (" SN : ", sn)
    iid = "5"  # installation id
    if "000001" == sn :
       # sensor, e.g sending  
       print ("--------------------")
       print ("Installing SN: ", sn)
       
       content = { 2: "reset"}
       print("reset :", content);
       execute_post("coap://"+my_base+"/.well-known/knx", 60, 60, content)
       
       content = True
       print("set PM :", content);
       execute_put("coap://"+my_base+"/dev/pm", 60, 60, content)
       content = 1
       print("set IA :", content);
       execute_put("coap://"+my_base+"/dev/ia", 60, 60, content)
       content = iid
       execute_put("coap://"+my_base+"/dev/iid", 60, 60, content)
       
       
       content = { 2: "startLoading"}
       print("lsm :", content);
       execute_post("coap://"+my_base+"/a/lsm", 60, 60, content)
       execute_get("coap://"+my_base+"/a/lsm", 60)
       # group object table
       # id (0)= 1
       # url (11)= /p/light
       # ga (7 )= 1
       # cflags (8) = ["r" ] ; read = 1, write = 2, transmit = 3 update = 4
       content = [ {0: 1, 11: "p/push", 7:[1], 8: [2] } ] 
       execute_post("coap://"+my_base+"/fp/g", 60, 60, content)
       
       execute_get("coap://"+my_base+"/fp/g", 40)
       
       
       # recipient table
       # id (0)= 1
       # ia (12)
       # url (11)= .knx
       # ga (7 )= 1
       # cflags (8) = ["r" ] ; read = 1, write = 2, transmit = 3 update = 4
       content = [ {0: 1, 11: "/p/push", 7:[1], 12 :"blah.blah" } ] 
       execute_post("coap://"+my_base+"/fp/r", 60, 60, content)
       
       content = False
       print("set PM :", content);
       execute_put("coap://"+my_base+"/dev/pm", 60, 60, content)
       
       content = { 2: "loadComplete"}
       print("lsm :", content);
       execute_post("coap://"+my_base+"/a/lsm", 60, 60, content)
       execute_get("coap://"+my_base+"/a/lsm", 60)
       
       
    if "000002" == sn :
       # actuator ==> receipient
       # should use /fp/r
       print ("--------------------")
       print ("installing SN: ", sn)
       content = True
       print("set PM :", content);
       execute_put("coap://"+my_base+"/dev/pm", 60, 60, content)
       content = 2
       print("set IA :", content);
       execute_put("coap://"+my_base+"/dev/ia", 60, 60, content)
       content = iid
       execute_put("coap://"+my_base+"/dev/iid", 60, 60, content)
       
       
       content = { 2: "startLoading"}
       print("lsm :", content);
       execute_post("coap://"+my_base+"/a/lsm", 60, 60, content)
       execute_get("coap://"+my_base+"/a/lsm", 60)
       
       # group object table
       # id (0)= 1
       # url (11)= /p/light
       # ga (7 )= 1
       # cflags (8) = ["r" ] ; read = 1, write = 2, transmit = 3 update = 4
       content = [ { 0: 1, 11: "/p/light", 7:[1], 8: [1] } ] 
       execute_post("coap://"+my_base+"/fp/g", 60, 60, content)
       
       execute_get("coap://"+my_base+"/fp/g", 40)
       # publisher table
       # id (0)= 1
       # ia (12)
       # url (11)= .knx
       # ga (7 )= 1
       # cflags (8) = ["r" ] ; read = 1, write = 2, transmit = 3 update = 4
       content = [ {0: 1, 11: ".knx", 7:[1], 12 :"blah.blah" } ] 
       execute_post("coap://"+my_base+"/fp/p", 60, 60, content)
       
       content = False
       print("set PM :", content);
       execute_put("coap://"+my_base+"/dev/pm", 60, 60, content)
       
       content = { 2: "loadComplete"}
       print("lsm :", content);
       execute_post("coap://"+my_base+"/a/lsm", 60, 60, content)
       execute_get("coap://"+my_base+"/a/lsm", 60)
       
       

    # do a post
    content = {"sia": 5678, "st": 55, "ga": 1, "value": 100 }
    content = { 4: 5678, "st": 55, 7: 1, "value": 100 }
    #                 st       ga       value (1)
    #content = { 5: { 6: 1, 7: 1, 1: True } } 
    #execute_post("coap://"+my_base+"/.knx", 60, 60, content)
    
    content = {4: 5678, 5: { 6: 1, 7: 1, 1: False } } 
    #execute_post("coap://"+my_base+"/.knx", 60, 60, content)
    #execute_post("coap://[FF02::FD]:5683/.knx", 60, 60, content)
    


# no json tags as strings
def do_sequence_dev(my_base):

    print("===================")
    print("Get SN :");
    sn = execute_get("coap://"+my_base+"/dev/sn", 60)
    sn = get_sn(my_base)
    print (" SN : ", sn)
   

    print("===================")
    print("Get HWT :");
    execute_get("coap://"+my_base+"/dev/hwt", 60)
    
    print("===================")
    print("Get HWV :");
    execute_get("coap://"+my_base+"/dev/hwv", 60)

    print("===================")
    print("Get FWV :");
    execute_get("coap://"+my_base+"/dev/fwv", 60)

    print("===================")
    print("Get Model :");
    execute_get("coap://"+my_base+"/dev/model", 60)

    print("===================")
    content = True
    print("set PM :", content);
    execute_put("coap://"+my_base+"/dev/pm", 60, 60, content)
    execute_get("coap://"+my_base+"/dev/pm", 60)
    content = False
    print("set PM :", content);
    execute_put("coap://"+my_base+"/dev/pm", 60, 60, content)
    execute_get("coap://"+my_base+"/dev/pm", 60)
    
    print("===================")
    content = 44
    print("set IA :", content);
    execute_put("coap://"+my_base+"/dev/ia", 60, 60, content)
    execute_get("coap://"+my_base+"/dev/ia", 60)
    
    print("===================")
    content = "my host name"
    print("set hostname :", content);
    execute_put("coap://"+my_base+"/dev/hostname", 60, 60, content)
    execute_get("coap://"+my_base+"/dev/hostname", 60)
    
    
    print("===================")
    content = " iid xxx"
    print("set iid :", content);
    execute_put("coap://"+my_base+"/dev/iid", 60, 60, content)
    execute_get("coap://"+my_base+"/dev/iid", 60)



# id ==> 0
# href ==> 11
# ga ==> 7
# cflag ==> 8
def do_sequence_fp_g_int(my_base):

    #  url, content, accept, contents
    content = [ {0: 1, 11: "xxxx1", 8: [1,2,3,4,5], 7:[2222,3333]} ] 
    execute_post("coap://"+my_base+"/fp/g", 60, 60, content)
    execute_get("coap://"+my_base+"/fp/g/1", 60)
    execute_get("coap://"+my_base+"/fp/g", 40)
    content = [ {0: 2, 11: "xxxxyyy2", 8: [1,4,5], 7:[44,55,33]}, {0: 3, 1: "xxxxyyy3", 8: [1,4,5], 7:[44,55,33]} ] 
    execute_post("coap://"+my_base+"/fp/g", 60, 60, content)
    execute_get("coap://"+my_base+"/fp/g/2", 60)
    execute_get("coap://"+my_base+"/fp/g/3", 60)
    execute_get("coap://"+my_base+"/fp/g", 40)
    
    execute_del("coap://"+my_base+"/fp/g/3", 60)
    execute_get("coap://"+my_base+"/fp/g/3", 60)
    execute_get("coap://"+my_base+"/fp/g", 40)

def do_sequence_fp_g(my_base):

    #  url, content, accept, contents
    content = [ {"id": 1, "href": "xxxx1", "cflag": [1,2,3,4,5], "ga":[2222,3333]} ] 
    execute_post("coap://"+my_base+"/fp/g", 60, 60, content)
    execute_get("coap://"+my_base+"/fp/g/1", 60)
    execute_get("coap://"+my_base+"/fp/g", 40)
    content = [ {"id": 2, "href": "xxxxyyy2", "cflag": [1,4,5], "ga":[44,55,33]}, {"id": 3, "href": "xxxxyyy3", "cflag": [1,4,5], "ga":[44,55,33]} ] 
    execute_post("coap://"+my_base+"/fp/g", 60, 60, content)
    execute_get("coap://"+my_base+"/fp/g/2", 60)
    execute_get("coap://"+my_base+"/fp/g/3", 60)
    execute_get("coap://"+my_base+"/fp/g", 40)
    
    execute_del("coap://"+my_base+"/fp/g/3", 60)
    execute_get("coap://"+my_base+"/fp/g/3", 60)
    execute_get("coap://"+my_base+"/fp/g", 40)
    
        
# id ==> 0
# ia ==> 12
# path ==> 112
# url ==> 10
# ga ==> 7
def do_sequence_fp_p_int(my_base):

    #  url, content, accept, contents
    content = [ {0: 1, 12: "Ia.IA1", 112: "path1", 7:[2222,3333]} ] 
    execute_post("coap://"+my_base+"/fp/p", 60, 60, content)
    execute_get("coap://"+my_base+"/fp/p/1", 60)
    # 40 == application-link format
    execute_get("coap://"+my_base+"/fp/p", 40)
    content = [ {0: 2, 12: "xxxxyyyia2", 112: "path2", 7:[44,55,33]}, 
                {0: 3, 12: "xxxxyyyia3", 112: "path3", 7:[44,55,33]} ] 
    execute_post("coap://"+my_base+"/fp/p", 60, 60, content)
    execute_get("coap://"+my_base+"/fp/p/2", 60)
    execute_get("coap://"+my_base+"/fp/p/3", 60)
    execute_get("coap://"+my_base+"/fp/p", 40)
    
    execute_del("coap://"+my_base+"/fp/p/3", 60)
    execute_get("coap://"+my_base+"/fp/p/3", 60)
    execute_get("coap://"+my_base+"/fp/p", 40)

def do_sequence_fp_p(my_base):

    #  url, content, accept, contents
    content = [ {"id": 1, "ia": "Ia.IA1", "path": "path1", "ga":[2222,3333]} ] 
    execute_post("coap://"+my_base+"/fp/p", 60, 60, content)
    execute_get("coap://"+my_base+"/fp/p/1", 60)
    # 40 == application-link format
    execute_get("coap://"+my_base+"/fp/p", 40)
    content = [ {"id": 2, "ia": "xxxxyyyia2", "path": "path2","ga":[44,55,33]}, {"id": 3, "ia": "xxxxyyyia3", "path": "path3","ga":[44,55,33]} ] 
    execute_post("coap://"+my_base+"/fp/p", 60, 60, content)
    execute_get("coap://"+my_base+"/fp/p/2", 60)
    execute_get("coap://"+my_base+"/fp/p/3", 60)
    execute_get("coap://"+my_base+"/fp/p", 40)
    
    execute_del("coap://"+my_base+"/fp/p/3", 60)
    execute_get("coap://"+my_base+"/fp/p/3", 60)
    execute_get("coap://"+my_base+"/fp/p", 40)



# id ==> 0
# ia ==> 12
# path ==> 112
# url ==> 10
# ga ==> 7
def do_sequence_fp_r_int(my_base):

    #  url, content, accept, contents
    content = [ { 0: 1, 12: "r-Ia.IA1", 112: "r-path1", 7:[2222,3333]}  ] 
    execute_post("coap://"+my_base+"/fp/r", 60, 60, content)
    execute_get("coap://"+my_base+"/fp/r/1", 60)
    execute_get("coap://"+my_base+"/fp/r", 40)
    content = [ { 0: 2, 12: "r-Ia.IA2", 10: "url2", 112: "r-path2", 7:[44,55,33]}, 
                {0: 3, 12: "r-Ia.IA3", 112: "r-path3", 7:[44,55,33]} ] 
    execute_post("coap://"+my_base+"/fp/r", 60, 60, content)
    execute_get("coap://"+my_base+"/fp/r/2", 60)
    execute_get("coap://"+my_base+"/fp/r/3", 60)
    execute_get("coap://"+my_base+"/fp/r", 40)
    
    execute_del("coap://"+my_base+"/fp/r/3", 60)
    execute_get("coap://"+my_base+"/fp/r/3", 60)
    execute_get("coap://"+my_base+"/fp/r", 40)

def do_sequence_fp_r(my_base):

    #  url, content, accept, contents
    content = [ {"id": 1, "ia": "r-Ia.IA1", "path": "r-path1", "ga":[2222,3333]}  ] 
    execute_post("coap://"+my_base+"/fp/r", 60, 60, content)
    execute_get("coap://"+my_base+"/fp/r/1", 60)
    execute_get("coap://"+my_base+"/fp/r", 40)
    content = [ {"id": 2, "ia": "r-Ia.IA2", "path": "r-path2", "ga":[44,55,33]}, {"id": 3, "ia": "r-Ia.IA3", "path": "r-path3", "ga":[44,55,33]} ] 
    execute_post("coap://"+my_base+"/fp/r", 60, 60, content)
    execute_get("coap://"+my_base+"/fp/r/2", 60)
    execute_get("coap://"+my_base+"/fp/r/3", 60)
    execute_get("coap://"+my_base+"/fp/r", 40)
    
    execute_del("coap://"+my_base+"/fp/r/3", 60)
    execute_get("coap://"+my_base+"/fp/r/3", 60)
    execute_get("coap://"+my_base+"/fp/r", 40)


# cmd ==> 2
def do_sequence_lsm_int(my_base):

    #  url, content, accept, contents

    execute_get("coap://"+my_base+"/a/lsm", 60)
    
    content = {2 : "startLoading"}
    execute_post("coap://"+my_base+"/a/lsm", 60, 60, content)
    execute_get("coap://"+my_base+"/a/lsm", 60)
    
    content = {2 : "loadComplete"}
    execute_post("coap://"+my_base+"/a/lsm", 60, 60, content)
    execute_get("coap://"+my_base+"/a/lsm", 60)
    
    content = {2 : "unload"}
    execute_post("coap://"+my_base+"/a/lsm", 60, 60, content)
    execute_get("coap://"+my_base+"/a/lsm", 60)

def do_sequence_lsm(my_base):

    #  url, content, accept, contents

    execute_get("coap://"+my_base+"/a/lsm", 60)
    
    content = {"cmd": "startLoading"}
    execute_post("coap://"+my_base+"/a/lsm", 60, 60, content)
    execute_get("coap://"+my_base+"/a/lsm", 60)
    
    content = {"cmd": "loadComplete"}
    execute_post("coap://"+my_base+"/a/lsm", 60, 60, content)
    execute_get("coap://"+my_base+"/a/lsm", 60)
    
    content = {"cmd": "unload"}
    execute_post("coap://"+my_base+"/a/lsm", 60, 60, content)
    execute_get("coap://"+my_base+"/a/lsm", 60)


# ./knx resource
# sia ==> 4
# ga ==> 7
# st 6 
def do_sequence_knx_knx_int(my_base):

    #  url, content, accept, contents
    execute_get("coap://"+my_base+"/.knx", 60)
    content = {"value": { 4 : 5, 7: 7777 , 6 : "rp"}}
    execute_post("coap://"+my_base+"/.knx", 60, 60, content)
    execute_get("coap://"+my_base+"/.knx", 60)

# ./knx resource
def do_sequence_knx_knx(my_base):

    #  url, content, accept, contents
    execute_get("coap://"+my_base+"/.knx", 60)
    content = {"value": { "sia" : 5, "ga": 7, "st": "rp"}}
    execute_post("coap://"+my_base+"/.knx", 60, 60, content)
    execute_get("coap://"+my_base+"/.knx", 60)


def do_sequence_knx_spake(my_base):

    #  url, content, accept, contents
    
    # sequence:
    # - parameter exchange: 15 (rnd)- return value
    # - credential exchange: 10 - return value
    # - pase verification exchange: 14  - no return value
    
    content = { 15: b"a-15-sdfsdred"}
    execute_post("coap://"+my_base+"/.well-known/knx/spake", 60, 60, content)
    
    # pa
    content = { 10: b"s10dfsdfsfs" }
    execute_post("coap://"+my_base+"/.well-known/knx/spake", 60, 60, content)
    
    # ca
    content = { 14: b"a15sdfsdred"}
    execute_post("coap://"+my_base+"/.well-known/knx/spake", 60, 60, content)
    # expecting return 
    

def do_sequence_knx_idevid(my_base):
    #  url, content, accept, contents
    execute_get("coap://"+my_base+"/.well-known/knx/idevid", 282)
    
def do_sequence_knx_ldevid(my_base):
    #  url, content, accept, contents
    execute_get("coap://"+my_base+"/.well-known/knx/ldevid", 282)


def do_sequence_knx_osn(my_base):
    #  url, content, accept, contents
    execute_get("coap://"+my_base+"/.well-known/knx/osn", 60)


def do_sequence_knx_crc(my_base):
    #  url, content, accept, contents
    execute_get("coap://"+my_base+"/.well-known/knx/crc", 60)
    
    
def do_sequence_oscore(my_base):
    #  url, content, accept, contents
    execute_get("coap://"+my_base+"/f/oscore", 40)
    
    execute_get("coap://"+my_base+"/p/oscore/replwdo", 60)
    content = 105 
    execute_put("coap://"+my_base+"/p/oscore/replwdo", 60, 60, content)
    execute_get("coap://"+my_base+"/p/oscore/replwdo", 60)
    
    execute_get("coap://"+my_base+"/p/oscore/osndelay", 60)
    content =  1050
    execute_put("coap://"+my_base+"/p/oscore/osndelay", 60, 60, content)
    execute_get("coap://"+my_base+"/p/oscore/osndelay", 60)


def do_sequence_core_knx(my_base):
    #  url, content, accept, contents
    execute_get("coap://"+my_base+"/.well-known/knx", 60)
    content = { 1 : 5, 2: "reset"}
    execute_post("coap://"+my_base+"/.well-known/knx", 60, 60, content)
    
    
def do_sequence_a_sen(my_base):
    #  url, content, accept, contents
    content = {2: "reset"}
    execute_post("coap://"+my_base+"/a/sen", 60, 60, content)
    
    
def do_sequence_auth(my_base):
    #  url, content, accept, contents
    
    execute_get("coap://"+my_base+"/auth", 40)
    
    
def do_sequence_auth_at(my_base):
    #  url, content, accept, contents
    
    execute_get("coap://"+my_base+"/auth/at", 40)
    # 
    content = {0: b"id", 1 : 20, 2:b"ms",3:"hkdf", 4:"alg", 5:b"salt", 6:b"contextId"}
    execute_post("coap://"+my_base+"/auth/at", 60, 60, content)
    
    
    content = {0: b"id2", 1 : 20, 2:b"ms",3:"hkdf", 4:"alg", 5:b"salt", 6:b"contextId2"}
    execute_post("coap://"+my_base+"/auth/at", 60, 60, content)
    
    execute_get("coap://"+my_base+"/auth/at", 40)
    
    execute_get("coap://"+my_base+"/auth/at/id", 60)
    execute_del("coap://"+my_base+"/auth/at/id", 60)
    
    
def do_sequence_f(my_base):

    #  url, content, accept, contents
    execute_get("coap://"+my_base+"/f", 40)
    # note this one is a bit dirty hard coded...
    execute_get("coap://"+my_base+"/f/417", 40)
    execute_get("coap://"+my_base+"/.well-known/core", 40)
    

def do_sequence(my_base):
    
    #sn = get_sn(my_base)
    install(my_base)
    return
    do_sequence_dev(my_base)
    
    
    #return
    do_sequence_fp_g_int(my_base)
    #do_sequence_fp_g(my_base)
    
    do_sequence_fp_p_int(my_base)
    #do_sequence_fp_p(my_base)
    
    do_sequence_fp_r_int(my_base)
    #do_sequence_fp_r(my_base)
    
    do_sequence_lsm_int(my_base)
    #do_sequence_lsm(my_base)
    do_sequence_lsm_int(my_base)
    # .knx
    do_sequence_knx_knx_int(my_base)
    #do_sequence_knx_knx(my_base)
    
    do_sequence_knx_spake(my_base)
    do_sequence_knx_idevid(my_base)
    do_sequence_knx_ldevid(my_base)
    do_sequence_knx_crc(my_base)
    do_sequence_knx_osn(my_base)
    
    do_sequence_oscore(my_base)
    do_sequence_core_knx(my_base)
    
    do_sequence_a_sen(my_base)
    do_sequence_auth(my_base)
    do_sequence_auth_at(my_base)
    
    do_sequence_f(my_base)
    
        

def client_callback_discovery(response, checkdata=None):
    print(" --- Discovery Callback ---")
    global my_base
    if response is not None:
        print ("response code:",response.code)
        print ("response type:",response.content_type)
        if response.code > 100:
            print("+++returned error+++")
            return
        if response.content_type == defines.Content_types["application/link-format"]:
            print (response.payload.decode())
            my_base = get_base_from_link(response.payload.decode())
            do_sequence(my_base)

def code2string(code):
   if code == 68:
      return "(Changed)"
   if code == 69:
      return "(Content)"
   if code == 132:
      return "(Not Found)"
   if code == 133:
      return "(METHOD_NOT_ALLOWED)"
   if code == 160:
      return "(INTERNAL_SERVER_ERROR)"
   
   return ""


def client_callback(response, checkdata=None):
    print(" --- Callback ---")
    if response is not None:
        print ("response code:",response.code, code2string(response.code))
        print ("response type:",response.content_type)
        if response.code > 100:
            print("+++returned error+++")
            return
        #print(response.pretty_print())
        if response.content_type == defines.Content_types["text/plain"]:
            if response.payload is not None:
              print (type(response.payload), len(response.payload))
              print ("=========")
              print (response.payload)
              print ("=========")
            else: 
                print ("payload: none")
        elif response.content_type == defines.Content_types["application/cbor"]:
            print (type(response.payload), len(response.payload))
            print ("=========")
            print (response.payload)
            print ("=========")
            #json_data = loads(response.payload)
            #print(json_data)
            #print ("=========")
            json_string = ""
            try:
                json_data = cbor.loads(response.payload)
                json_string = json.dumps(json_data, indent=2, sort_keys=True)
            except:
                print("error in cbor..")
            print (json_string)
            print ("===+++===")
            if checkdata is not None:
               check_data = cbor.loads(checkdata)
               check_string = json.dumps(check_data, indent=2, sort_keys=True)
               print("  check: ")
               print (check_string)
               if check_string == json_string:
                  print("  =+++===> OK  ")
               else:
                  print("  =+++===> NOT OK  ")
            
            print (json_string)
        elif response.content_type == defines.Content_types["application/vnd.ocf+cbor"]:
            print ("application/vnd.ocf+cbor")
            try:
                print (type(response.payload), len(response.payload))
                print ("=========")
                print (response.payload)
                print ("=========")
                json_data = cbor.loads(response.payload)
                print (json_data)
                print ("---------")
            except:
                traceback.print_exc()
            json_string = json.dumps(json_data, indent=2, sort_keys=True)
            print (json_string)
        elif response.content_type == defines.Content_types["application/link-format"]:
            print (response.payload.decode())
        else:
            if response.payload is not None:
              print ("type, len", type(response.payload), len(response.payload))
              print (response.payload)
            #else:
            #    print ("    not handled: ", response)
    else:
        print (" Response : None")
    #check = True
    #while check:
    #    chosen = eval(input("Stop observing? [y/N]: "))
    #    if chosen != "" and not (chosen == "n" or chosen == "N" or chosen == "y" or chosen == "Y"):
    #        print("Unrecognized choose.")
    #        continue


def client_callback_observe(response):  # pragma: no cover
    global client
    print("Callback_observe")
    check = True
    while check:
        chosen = eval(input("Stop observing? [y/N]: "))
        if chosen != "" and not (chosen == "n" or chosen == "N" or chosen == "y" or chosen == "Y"):
            print("Unrecognized choose.")
            continue
        elif chosen == "y" or chosen == "Y":
            while True:
                rst = eval(input("Send RST message? [Y/n]: "))
                if rst != "" and not (rst == "n" or rst == "N" or rst == "y" or rst == "Y"):
                    print("Unrecognized choose.")
                    continue
                elif rst == "" or rst == "y" or rst == "Y":
                    client.cancel_observing(response, True)
                else:
                    client.cancel_observing(response, False)
                check = False
                break
        else:
            break


def execute_get(mypath, ct_value):
      print ("---------------------------")
      print ("execute_get: ", ct_value, mypath)
      print (type(mypath))
      
      if (mypath is None or len(mypath) < 5):
        return
      if mypath.startswith("coap://") == False:
        print(" not executing: ", mypath);
        return;

      ct = {}
      ct['accept'] = ct_value
      host, port, path = parse_uri(mypath)
      try:
        tmp = socket.gethostbyname(host)
        host = tmp
      except socket.gaierror:
        pass
      nclient = HelperClient(server=(host, port))
      response = nclient.get(path, None, None, **ct)
      client_callback(response)
      nclient.stop()
      return response

def execute_del(mypath, ct_value):
      print ("---------------------------")
      print ("execute_del: ", ct_value, mypath)
      do_exit = False
      ct = {}
      ct['accept'] = ct_value
      ct['content_type'] = ct_value
      
      if mypath.startswith("coap://") == False:
        print(" not executing: ", mypath);
        return;
      
      host, port, path = parse_uri(mypath)
      try:
        tmp = socket.gethostbyname(host)
        host = tmp
      except socket.gaierror:
        pass
      nclient = HelperClient(server=(host, port))
      nclientcheck = HelperClient(server=(host, port))
      payload = 0

      response = nclient.delete(path, None, None, **ct)
      client_callback(response)
        #nclient.stop()
        #sys.exit(2)
      print ("=======")



def execute_put(mypath, ct_value, accept, content):
      print ("---------------------------")
      print ("execute_put: ", ct_value, mypath)
      do_exit = False
      ct = {}
      ct['accept'] = accept
      ct['content_type'] = ct_value
      
      if mypath.startswith("coap://") == False:
        print(" not executing: ", mypath);
        return
      
      host, port, path = parse_uri(mypath)
      try:
        tmp = socket.gethostbyname(host)
        host = tmp
      except socket.gaierror:
        pass
      nclient = HelperClient(server=(host, port))
      nclientcheck = HelperClient(server=(host, port))
      payload = 0

      if accept == 60:
        payload = cbor.dumps(content)
      else:
        payload = content
      print ("payload: ", payload)
      response = nclient.put(path, payload, None, None , None, **ct)
      client_callback(response)
      nclient.stop()
      
      
def execute_post(mypath, ct_value, accept, content):
      print ("---------------------------")
      print ("execute_post: ", ct_value, mypath)
      print (content)
      print ("     ---------------------")
      do_exit = False
      ct = {}
      ct['accept'] = accept
      ct['content_type'] = ct_value
      
      if mypath.startswith("coap://") == False:
        print(" not executing: ", mypath);
        return
      
      host, port, path = parse_uri(mypath)
      try:
        tmp = socket.gethostbyname(host)
        host = tmp
      except socket.gaierror:
        pass
      nclient = HelperClient(server=(host, port))
      #nclientcheck = HelperClient(server=(host, port))
      payload = 0

      if accept == 60:
        #print(" content :", content)
        payload = cbor.dumps(content)
      else:
        payload = content
      response = nclient.post(path, payload, None, None , None, **ct)
      client_callback(response)
      nclient.stop()


def main():  # pragma: no cover
    global client
    op = None
    path = None
    payload = None
    content_type = None
    #ct = {'content_type': defines.Content_types["application/link-format"]}
    ct = {}
    ct['accept'] = 40
    try:
        opts, args = getopt.getopt(sys.argv[1:], "ho:p:P:f:c:", ["help", "operation=", "path=", "payload=",
                                                               "payload_file=","content-type"])
    except getopt.GetoptError as err:
        # print help information and exit:
        print((str(err)))  # will print something like "option -a not recognized"
        usage()
        sys.exit(2)
    for o, a in opts:
        if o in ("-o", "--operation"):
            op = a
        elif o in ("-p", "--path"):
            path = a
        elif o in ("-P", "--payload"):
            payload = a
        elif o in ("-c", "--content-type"):
            ct['accept'] = a
            print ("content type request : ", ct)
        elif o in ("-f", "--payload-file"):
            with open(a, 'r') as f:
                payload = f.read()
        elif o in ("-h", "--help"):
            usage()
            sys.exit()
        else:
            usage()
            sys.exit(2)

    if op is None:
        print("Operation must be specified")
        usage()
        sys.exit(2)

    if path is None:
        print("Path must be specified")
        usage()
        sys.exit(2)

    if not path.startswith("coap://"):
        print("Path must be conform to coap://host[:port]/path")
        usage()
        sys.exit(2)

    host, port, path = parse_uri(path)
    try:
        tmp = socket.gethostbyname(host)
        host = tmp
    except socket.gaierror:
        pass
    client = HelperClient(server=(host, port))
    if op == "GET":
        if path is None:
            print("Path cannot be empty for a GET request")
            usage()
            sys.exit(2)
        response = client.get(path, None, None, **ct)
        print((response.pretty_print()))
        if response.content_type == defines.Content_types["application/json"]:
            json_data = json.loads(response.payload)
            json_string = json.dumps(json_data, indent=2, sort_keys=True)
            print ("JSON ::")
            print (json_string)
        if response.content_type == defines.Content_types["application/cbor"]:
            json_data = cbor.loads(response.payload)
            json_string = json.dumps(json_data, indent=2, sort_keys=True)
            print ("JSON ::")
            print (json_string)
        if response.content_type == defines.Content_types["application/link-format"]:
            #json_data = cbor.loads(response.payload)
            #json_string = json.dumps(json_data, indent=2, sort_keys=True)
            #print ("JSON ::")
            print (response.payload.decode())
            print ("\n\n")
            
            
        if response.content_type == defines.Content_types["application/vnd.ocf+cbor"]:
            json_data = cbor.loads(response.payload)
            json_string = json.dumps(json_data, indent=2, sort_keys=True)
            print ("JSON ::")
            print (json_string)
        client.stop()
    elif op == "GETNONE":
        if path is None:
            print("Path cannot be empty for a GET-None request")
            usage()
            sys.exit(2)
        response = client.get_non(path, None, None, **ct)
        print((response.pretty_print()))
        if response.content_type == defines.Content_types["application/json"]:
            json_data = json.loads(response.payload)
            json_string = json.dumps(json_data, indent=2, sort_keys=True)
            print ("JSON ::")
            print (json_string)
        if response.content_type == defines.Content_types["application/cbor"]:
            json_data = cbor.loads(response.payload)
            json_string = json.dumps(json_data, indent=2, sort_keys=True)
            print ("JSON ::")
            print (json_string)
        if response.content_type == defines.Content_types["application/vnd.ocf+cbor"]:
            json_data = cbor.loads(response.payload)
            json_string = json.dumps(json_data, indent=2, sort_keys=True)
            print ("JSON ::")
            print (json_string)
        client.stop()
    elif op == "OBSERVE":
        if path is None:
            print("Path cannot be empty for a GET request")
            usage()
            sys.exit(2)
        client.observe(path, client_callback_observe)
        
    elif op == "DELETE":
        if path is None:
            print("Path cannot be empty for a DELETE request")
            usage()
            sys.exit(2)
        response = client.delete(path)
        print((response.pretty_print()))
        client.stop()
    elif op == "POST":
        if path is None:
            print("Path cannot be empty for a POST request")
            usage()
            sys.exit(2)
        if payload is None:
            print("Payload cannot be empty for a POST request")
            usage()
            sys.exit(2)
        print ( "payload for POST (ascii):", payload )
        print (ct['accept'] )
        if ct['accept'] == str(defines.Content_types["application/cbor"]):
            json_data = json.loads(payload)
            cbor_data = cbor.dumps(json_data)
            payload = bytes(cbor_data)
        if ct['accept'] == str(defines.Content_types["application/vnd.ocf+cbor"]):
            json_data = json.loads(payload)
            cbor_data = cbor.loads(json_data)
            payload = cbor_data
            
        response = client.post(path, payload, None, None, **ct)
        
        print((response.pretty_print()))
        if response.content_type == defines.Content_types["application/cbor"]:
            json_data = cbor.loads(response.payload)
            json_string = json.dumps(json_data, indent=2, sort_keys=True)
            print (json_string)
        if response.content_type == defines.Content_types["application/vnd.ocf+cbor"]:
            json_data = cbor.loads(response.payload)
            json_string = json.dumps(json_data, indent=2, sort_keys=True)
            print (json_string)
        client.stop()
    elif op == "PUT":
        if path is None:
            print("Path cannot be empty for a PUT request")
            usage()
            sys.exit(2)
        if payload is None:
            print("Payload cannot be empty for a PUT request")
            usage()
            sys.exit(2)
        response = client.put(path, payload)
        print((response.pretty_print()))
        client.stop()
    elif op == "DISCOVER":
        #response = client.discover( path, client_callback, None, **ct)
        response = client.discover( path, None, None, **ct)
        if response is not None:
            print(response.pretty_print())
            if response.content_type == defines.Content_types["application/cbor"]:
                json_data = cbor.loads(response.payload)
                json_string = json.dumps(json_data, indent=2, sort_keys=True)
                print (json_string)
            if response.content_type == defines.Content_types["application/vnd.ocf+cbor"]:
                json_data = cbor.loads(response.payload)
                json_string = json.dumps(json_data, indent=2, sort_keys=True)
                print (json_string)
            if response.content_type == defines.Content_types["application/link-format"]:
                #json_data = cbor.loads(response.payload)
                #json_string = json.dumps(json_data, indent=2, sort_keys=True)
                print (response.payload.decode())
                # do_get(response.payload.decode(), client)
                client_callback_discovery(response)
        
        counter = 2
        try:
           while counter > 0:
              time.sleep(1)
              counter = counter - 1
           #client.stop()
        except KeyboardInterrupt:
           print("Client Shutdown")
           #client.stop()
           
        #execute_list()
        client.stop()
    else:
        print("Operation not recognized")
        usage()
        sys.exit(2)


if __name__ == '__main__':  # pragma: no cover
    main()

[(68, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (719, 'coapthon.utils.parse_uri', 'parse_uri', False, 'from coapthon.utils import parse_uri\n'), (725, 'coapthon.client.helperclient.HelperClient', 'HelperClient', False, 'from coapthon.client.helperclient import HelperClient\n'), (743, 'coapthon.utils.parse_uri', 'parse_uri', False, 'from coapthon.utils import parse_uri\n'), (749, 'coapthon.client.helperclient.HelperClient', 'HelperClient', False, 'from coapthon.client.helperclient import HelperClient\n'), (750, 'coapthon.client.helperclient.HelperClient', 'HelperClient', False, 'from coapthon.client.helperclient import HelperClient\n'), (773, 'coapthon.utils.parse_uri', 'parse_uri', False, 'from coapthon.utils import parse_uri\n'), (779, 'coapthon.client.helperclient.HelperClient', 'HelperClient', False, 'from coapthon.client.helperclient import HelperClient\n'), (780, 'coapthon.client.helperclient.HelperClient', 'HelperClient', False, 'from coapthon.client.helperclient import HelperClient\n'), (807, 'coapthon.utils.parse_uri', 'parse_uri', False, 'from coapthon.utils import parse_uri\n'), (813, 'coapthon.client.helperclient.HelperClient', 'HelperClient', False, 'from coapthon.client.helperclient import HelperClient\n'), (879, 'coapthon.utils.parse_uri', 'parse_uri', False, 'from coapthon.utils import parse_uri\n'), (885, 'coapthon.client.helperclient.HelperClient', 'HelperClient', False, 'from coapthon.client.helperclient import HelperClient\n'), (721, 'socket.gethostbyname', 'socket.gethostbyname', False, 'import socket\n'), (745, 'socket.gethostbyname', 'socket.gethostbyname', False, 'import socket\n'), (775, 'socket.gethostbyname', 'socket.gethostbyname', False, 'import socket\n'), (784, 'cbor.dumps', 'cbor.dumps', False, 'import cbor\n'), (809, 'socket.gethostbyname', 'socket.gethostbyname', False, 'import socket\n'), (819, 'cbor.dumps', 'cbor.dumps', False, 'import cbor\n'), (837, 'getopt.getopt', 'getopt.getopt', False, 'import getopt\n'), (867, 'sys.exit', 'sys.exit', False, 'import sys\n'), (872, 'sys.exit', 'sys.exit', False, 'import sys\n'), (877, 'sys.exit', 'sys.exit', False, 'import sys\n'), (881, 'socket.gethostbyname', 'socket.gethostbyname', False, 'import socket\n'), (843, 'sys.exit', 'sys.exit', False, 'import sys\n'), (890, 'sys.exit', 'sys.exit', False, 'import sys\n'), (894, 'json.loads', 'json.loads', False, 'import json\n'), (895, 'json.dumps', 'json.dumps', False, 'import json\n'), (899, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (900, 'json.dumps', 'json.dumps', False, 'import json\n'), (912, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (913, 'json.dumps', 'json.dumps', False, 'import json\n'), (921, 'sys.exit', 'sys.exit', False, 'import sys\n'), (925, 'json.loads', 'json.loads', False, 'import json\n'), (926, 'json.dumps', 'json.dumps', False, 'import json\n'), (930, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (931, 'json.dumps', 'json.dumps', False, 'import json\n'), (935, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (936, 'json.dumps', 'json.dumps', False, 'import json\n'), (632, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (633, 'json.dumps', 'json.dumps', False, 'import json\n'), (639, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (640, 'json.dumps', 'json.dumps', False, 'import json\n'), (661, 'json.dumps', 'json.dumps', False, 'import json\n'), (944, 'sys.exit', 'sys.exit', False, 'import sys\n'), (656, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (951, 'sys.exit', 'sys.exit', False, 'import sys\n'), (660, 'traceback.print_exc', 'traceback.print_exc', False, 'import traceback\n'), (959, 'sys.exit', 'sys.exit', False, 'import sys\n'), (963, 'sys.exit', 'sys.exit', False, 'import sys\n'), (967, 'json.loads', 'json.loads', False, 'import json\n'), (968, 'cbor.dumps', 'cbor.dumps', False, 'import cbor\n'), (971, 'json.loads', 'json.loads', False, 'import json\n'), (972, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (979, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (980, 'json.dumps', 'json.dumps', False, 'import json\n'), (983, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (984, 'json.dumps', 'json.dumps', False, 'import json\n'), (859, 'sys.exit', 'sys.exit', False, 'import sys\n'), (862, 'sys.exit', 'sys.exit', False, 'import sys\n'), (991, 'sys.exit', 'sys.exit', False, 'import sys\n'), (995, 'sys.exit', 'sys.exit', False, 'import sys\n'), (1034, 'sys.exit', 'sys.exit', False, 'import sys\n'), (1005, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (1006, 'json.dumps', 'json.dumps', False, 'import json\n'), (1009, 'cbor.loads', 'cbor.loads', False, 'import cbor\n'), (1010, 'json.dumps', 'json.dumps', False, 'import json\n'), (1022, 'time.sleep', 'time.sleep', False, 'import time\n')]