from time import gmtime, strftime
import random
import redis
import json
import base64


colors = ['blue', 'green', 'brown', 'red', 'purple', 'orange', 'magenta', 'darkcyan', 'gray', 'blue', 'red', 'purple',
          'blue', 'green', 'brown', 'red', 'purple', 'orange', 'magenta', 'darkcyan', 'gray', 'blue', 'red', 'purple']

corner = [820, 840, 860, 880, 900, 920, 940, 960, 980, 1000, 1020, 1040, 1060, 1080, 1100,
          820, 840, 860, 880, 900, 920, 940, 960, 980, 1000, 1020, 1040, 1060, 1080, 1100]

#
############  DRAW boxes
#

def headerText(x, y, name):
    ## draw header text
    data = '<text x="%s" y="%s" font-size="48" fill="brown">' % (x, y+30)
    data = data + name +' Replay'  + '</text>'

    data = data + '<text x="%s" y="%s" font-size="22" fill="brown">' % (x, y+60)
    data = data + 'Producer, Switch and Consumer Configurations'  + '</text>'

    data = data + '<text x="%s" y="%s" font-size="22" fill="brown">' % (x, y+90)
    data = data + strftime("%Y-%m-%d %H:%M:%S", gmtime())  + ' UTC </text>'

    return data

def headerLegends(x, y):
    ## Draw a legend - Replay
    data = data + '''
         <rect style="fill:#f8eeee; stroke:red; stroke-width:1;"
            id="legend"
            width="32"
            height="16"
            x="%s"
            y="%s"
            rx="3"
            ry="3"
         />''' % (x, y+120)

    data = data + '<text x="%s" y="%s" font-size="11" fill="brown">' % (x+38, y+132)
    data = data + '=  Replay Server </text>'

    # legend = consumer open
    data = data + '''
         <rect style="fill:#eef8ee; stroke:green; stroke-width:1;"
            id="legend"
            width="32"
            height="16"
            x="%s"
            y="%s"
            rx="3"
            ry="3"
         />''' % (x, y+145)

    data = data + '<text x="%s" y="%s" font-size="11" fill="brown">' % (x+38, y+157)
    data = data + '=  Consumer (PX - Open ) </text>'

    # legend - consumer reserved
    data = data + '''
         <rect style="fill:#c8dff8; stroke:green; stroke-width:1;"
            id="legend"
            width="32"
            height="16"
            x="%s"
            y="%s"
            rx="3"
            ry="3"
         />''' % (x, y+170)

    data = data + '<text x="%s" y="%s" font-size="11" fill="brown">' % (x+38, y+182)
    data = data + '=  Consumer (PX -Reserved)</text>'

    # disabled
    data = data + '''
         <rect style="fill:#eeeeee; stroke:gray; stroke-width:1;"
            id="legend"
            width="32"
            height="16"
            x="%s"
            y="%s"
            rx="3"
            ry="3"
         />''' % (x, y+195)

    data = data + '<text x="%s" y="%s" font-size="11" fill="brown">' % (x+38, y+207)
    data = data + '=  Disabled</text>'

    return data  #'''

######################################################################

def getRedisCount():
    r = redis.Redis(host='127.0.0.1', port='6379')
    return r.get("totalBoxCount")

# get server box data points from redis cache

def getRedis(k):
    r = redis.Redis(host='127.0.0.1', port='6379')
    rkey = "server-%d" % k
    if not r.hgetall(rkey):
       return None
    serverData = ""
    try:
       serverData = {
        'name'        : r.hget(rkey,'name'),
        'type'        : r.hget(rkey,'type'),
        'reserved'    : r.hget(rkey,'reserved'),
        'disabled'    : r.hget(rkey,'disabled'),
        'active'      : r.hget(rkey,'active'),
        'flicid'      : r.hget(rkey,'flicid'),
        'location'    : r.hget(rkey,'location'),
        'ports'       : json.loads(base64.b64decode(r.hget(rkey,'ports'))),
        'portconfig'  : json.loads(base64.b64decode(r.hget(rkey,'portconfig'))),
        'switchports' : json.loads(base64.b64decode(r.hget(rkey,'switchports'))),
        'pathstart'   : json.loads(base64.b64decode(r.hget(rkey,'pathstart'))),
        'pathend'     : json.loads(base64.b64decode(r.hget(rkey,'pathend'))),
        'rate'        : json.loads(base64.b64decode(r.hget(rkey,'rate'))),
        'pcaploop'    : json.loads(base64.b64decode(r.hget(rkey,'pcaploop'))),
        'linkstatus'  : json.loads(base64.b64decode(r.hget(rkey,'linkstatus'))),
        'playstatus'  : json.loads(base64.b64decode(r.hget(rkey,'playstatus'))),
        'pcaps'       : json.loads(base64.b64decode(r.hget(rkey,'pcaps'))),
        'stroke'      : r.hget(rkey,'stroke'),
        'fill'        : r.hget(rkey,'fill'),
       }
    except:
       pass
    return serverData

######################################################################

def drawSwitchBox(stroke, fill, x, y, h):
    data = '''
          <rect
            fill="#%s"
            style="stroke:%s;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
            id="switch"
            width="320"
            height="%s"
            x="%s"
            y="%s"
            rx="6"
            ry="6"
    />''' % (fill, stroke, h, x, y)    #'''
    return data

#
#######################################################################
# Producers
#

def drawProducer(input_json, x, y):
    indata      = json.loads(input_json)
    servername  = indata['name']
    location    = indata['location']
    flicid      = indata['flicid']
    disabled    = indata['disabled']
    reserved    = indata['reserved']
    ports       = indata['ports']
    switchports = indata['switchports']
    pathstart   = indata['pathstart']
    pathend     = indata['pathend']
    linkstatus  = indata['linkstatus']
    playstatus  = indata['playstatus']
    pcaps       = indata['pcaps']
    stroke      = indata['stroke']

    fill        = '#ffdddd'

    numports  = len(ports)
    portcolor = "#cccccc"
    boff      = [8, 8, 8, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    coff      = [0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

    yofs = boff[len(ports)]

    # drop shadow and blur filter
    data = '''
           <defs>
             <filter id="f1" x="0" y="0" rx="4" ry="4" width="105%" height="120%">
               <feOffset result="offOut" in="SourceGraphic" dx="2" dy="2" />
                <feColorMatrix result="matrixOut" in="offOut" type="matrix"
                  values="0.2 0 0 0 0 0 0.2 0 0 0 0 0 0.2 0 0 0 0 0 1 0" />
               <feGaussianBlur result="blurOut" in="matrixOut" stdDeviation="5" />
               <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
             </filter>
             <filter id="f2" x="0" y="0" width="100%" height="100%" filterUnits="userSpaceOnUse">
               <feOffset result="offOut" in="SourceGraphic" dx="4" dy="4" />
                <feColorMatrix result="matrixOut" in="offOut" type="matrix"
                  values="0.0 0 0 0 0 0 0.0 0 0 0 0 0 0.0 0 0 0 0 0 1 0" />
               <feGaussianBlur result="blurOut" in="matrixOut" stdDeviation="8" />
               <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
             </filter>
             <filter id="f3" x="0" y="0" width="200%" height="200%">
               <feOffset result="offOut" in="SourceAlpha" dx="4" dy="4" />
                <feGaussianBlur result="blurOut" in="offOut" stdDeviation="5" />
                 <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
             </filter>
           </defs>'''


   ### Draw paths

    for i in range(0, numports):
        j = unicode(i)
        try:
           psl = len(pathstart[j])
           paths = pathstart[j]
           pathe = pathend[j]
           for p in range(0, psl):
               c = colors[p]
               ya = int(paths[p][1])+10
               yb = int(pathe[p][1])+10
               mx = int(paths[p][2])
               data = data + drawpath(800, ya, mx, 1120, yb, c, servername+"*"+str(i)+"*"+str(p), servername, i, playstatus[i])
        except:
           pass

    # actual box for server with rounded corners
    data = data + '''
          <rect
            fill="%s"
            style="stroke:%s;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
            id="rect%s"
            width="400"
            height="%s"
            x="%s"
            y="%s"
            rx="6"
            ry="6"
          />''' % ( fill, stroke, servername, numports*32+yofs, x, y)      #'''

    if numports < 3:
       data = data + '<text x="%s" y="%s" font-size="24" fill="%s">' % (x+62, y+32, '#666666')
    else:
       data = data + '<text x="%s" y="%s" font-size="24" fill="%s">' % (x+12, y+30, '#666666')
    data = data + servername + '</text>'

    if numports < 3:
       data = data + '<text x="%s" y="%s" font-size="10" fill="%s">' % (x+63, y+46, 'black')
    else:
       data = data + '<text x="%s" y="%s" font-size="10" fill="%s">' % (x+13, y+44, 'black')
    data = data + reserved + '</text>'

    # port boxes on server
    for i in range(0, numports):
        data = data + '''
         <rect
            style="fill:%s;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
            id="port%s"
            width="20"
            height="20"
            x="%s"
            y="%s"
            rx="2"
            ry="2"
         />''' % (portcolor, i, x+410, y+(i*32)+6)     #'''

        data = data + '<text x="%s" y="%s" style="font-size:10px;fill:black;text-align:center;">' % (x+414, y+20+i*32)
        data = data + '%s</text>' % (ports[i])

    # draw boxes on switch that these are connected to
    for i in range(0, numports):
        data = data + '''
         <rect class="play"
            style="fill:%s;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
            id="port%s"
            width="20"
            height="20"
            x="%s"
            y="%s"
            rx="2"
            ry="2"
            onclick="javascript:setStartPoint('%s','%s','%s','%s');"
         />''' % (portcolor, i, x+560, y+(i*32)+6, servername, i, x+560, y+(i*32)+6)    #'''

        # xx or na in config means port not used, gray them out
        if switchports[i] != 'xx' and switchports[i] != 'na':
           pfill = 'black'
        else:
           linkstatus[i] = False
           pfill = portcolor

        data = data + '<text x="%s" y="%s" style="font-size:10px;fill:%s;text-align:center;">' % (x+564, y+20+i*32, pfill)
        data = data + '%s</text>' % (switchports[i])

        # path from server to packet broker is link status - loop@rate if ok, status and red if bad'''
        sname = "'" + servername + "'"
        if linkstatus[i]:
           color = 'green'
        else:
           color = 'red'

        data = data + ''' <rect x="%s" y="%s" rx="8" ry="8" width="190" height="100" style="fill:#acc2e5"
                          onmouseover="hidepathInfo(%s,%s);"
                          onmouseout="hidepathInfo(%s,%s);" id="%s%s" visibility="hidden"/> ''' % (x+410, y+(i*32)-120, i, sname, i, sname, servername, i )
        xt = x+480
        yt = y+(i*32)+16
        tf = "#acc2e5"

        # popup for the rate and loop values, hidden for now, unhides and populates with javascript and a callback

        data = data + '''<text x="%s" y="%s" font-size="16" fill="#000000" id="text0box%s%s" visibility="hidden">Port %s</text>''' % (x+480, y+(i*32)-96, servername, i, ports[i])
        data = data + '''<text x="%s" y="%s" font-size="16" fill="#000000" id="text1box%s%s" visibility="hidden"> </text>''' % (x+450, y+(i*32)-66, servername, i)
        data = data + '''<text x="%s" y="%s" font-size="16" fill="#000000" id="text2box%s%s" visibility="hidden"> </text>''' % (x+450, y+(i*32)-46, servername, i)

        data = data + '''<a onclick="javascript:openpathInfo(%s,%s,%s,%s);" onmouseout="hidepathInfo(%s,%s);" style="cursor:pointer;">
                         <path d="M%s %s L%s %s" stroke-opacity="0.30" stroke="%s" stroke-width="12" fill="none"/></a>''' % (x+430, y+(i*32)+17, switchports[i], sname, i, sname, x+430, y+(i*32)+17, x+560, y+(i*32)+17, color)

        data = data + '''<polygon points="%s,%s %s,%s %s,%s" style="fill:%s;stroke:gray;stroke-width:0" id="tri%s%s" visibility="hidden"/>''' % (xt, yt, xt+10, yt-40, xt+40, yt-40, tf, servername, i)

        # pcap file names
        for i in range(0,len(pcaps)):
            data = data + '<text x="%s" y="%s" font-size="14" fill="%s" text-anchor="end">' % (x+360, y+26+(i*30), '#444444')
            data = data + pcaps[i] + '</text>'

        # play/stop boxes
        for i in range(0,len(pcaps)):
            oy = i*30
            sid = servername+"*ps*"+str(i)
            data = data + '''
            <rect class="%s" fill="%s"
               style="stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
               id="playstop%s"
               width="20"
               height="20"
               x="%s"
               y="%s"
               rx="2"
               ry="2"
               onclick="javascript:startStop('%s');"
               onmouseover="evt.target.setAttribute('opacity', '0.5');"
               onmouseout="evt.target.setAttribute('opacity','1');"
            />''' % ( "play", '#ddd', sid, x+370, oy+y+12, sid)

            # start or stop graphic?
            if playstatus[i] == 'stop':
               data = data + '''
                 <polygon id="st%s" class="%s" points="%s,%s %s,%s %s,%s %s,%s %s,%s" fill="%s" style="stroke:black;stroke-width:1"
                  onclick="javascript:startStop('%s');"
                  onmouseover="evt.target.setAttribute('opacity', '0.5');"
                  onmouseout="evt.target.setAttribute('opacity','1');"
                 />''' % (i, "play", x+374, oy+y+16, x+386, oy+y+16, x+386, oy+y+28, x+374, oy+y+28, x+374, oy+y+16, '#ee8888', sid)
            else:
              data = data + '''
                <polygon id="pl%s" class="%s" points="%s,%s %s,%s %s,%s" fill="%s" style="stroke:black;stroke-width:1"
                 onclick="javascript:startStop('%s');"
                 onmouseover="evt.target.setAttribute('opacity', '0.5');"
                 onmouseout="evt.target.setAttribute('opacity','1');"
                />''' % (i, "play", x+375, oy+y+14, x+387, oy+y+22, x+375, oy+y+30, '#99dd99', sid)


    # Setup button
    if numports < 3:
       yf = 62
    else:
       yf = 52

    data = data + '''
           <rect class="cfg" x="%s" y="%s" width="40" height="20" rx="4" ry="4"
             stroke="black" stroke-width=".75" fill="#eeeeee"
             onclick="javascript:configure('%s','%s');"
             onmouseover="evt.target.setAttribute('opacity', '0.5');"
             onmouseout="evt.target.setAttribute('opacity','1');"
           />''' % (x+14, y+numports*32+yofs-yf, servername, location)

    if numports < 3:
       data = data + '<text x="%s" y="%s" style="font-size:10px;fill:black;text-align:center;">' % (x+20, y+numports*32+yofs-48)
    else:
       data = data + '<text x="%s" y="%s" style="font-size:10px;fill:black;text-align:center;">' % (x+20, y+numports*32+yofs-38)
    data = data + 'Setup</text>'


    # Info button
    if numports < 3:
       yf = 30
    else:
       yf = 26

    data = data + '''
           <rect class="cfg" x="%s" y="%s" width="40" height="20" rx="4" ry="4" 
             stroke="black" stroke-width=".75" fill="#eeeeee"
             onclick="javascript:info('%s');"
             onmouseover="evt.target.setAttribute('opacity', '0.5');"
             onmouseout="evt.target.setAttribute('opacity','1');"
           />''' % (x+14, y+numports*32+yofs-yf, flicid)     #'''

    if numports < 3:
       data = data + '<text x="%s" y="%s" style="font-size:10px;fill:black;text-align:center;">' % (x+25, y+numports*32+yofs-18)
    else:
       data = data + '<text x="%s" y="%s" style="font-size:10px;fill:black;text-align:center;">' % (x+25, y+numports*32+yofs-13)
    data = data + 'Info</text>'


    return data

#
#####################################################################
# Draw Consumer '''
#

def drawConsumer(input_json, x, y):
    indata      = json.loads(input_json)
    servername  = indata['name']
    flicid      = indata['flicid']
    disabled    = indata['disabled']
    ports       = indata['ports']
    reserved    = indata['reserved']
    switchports = indata['switchports']
    linkstatus  = indata['linkstatus']
    stroke      = indata['stroke']

    if reserved:
       fill = '#c8dff8'         # blue
    else:
       fill = '#ddffdd'         # green

    numports  = len(ports)
    portcolor = "#cccccc"
    boff      = [8, 8, 8, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    coff      = [0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

    yofs = boff[len(ports)]

# drop shadow and blur filter
    data = '''
           <defs>
             <filter id="f1" x="0" y="0" rx="4" ry="4" width="105%" height="120%">
               <feOffset result="offOut" in="SourceGraphic" dx="2" dy="2" />
                <feColorMatrix result="matrixOut" in="offOut" type="matrix"
                  values="0.2 0 0 0 0 0 0.2 0 0 0 0 0 0.2 0 0 0 0 0 1 0" />
               <feGaussianBlur result="blurOut" in="matrixOut" stdDeviation="5" />
               <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
             </filter>
             <filter id="f2" x="0" y="0" width="100%" height="100%" filterUnits="userSpaceOnUse">
               <feOffset result="offOut" in="SourceGraphic" dx="4" dy="4" />
                <feColorMatrix result="matrixOut" in="offOut" type="matrix"
                  values="0.0 0 0 0 0 0 0.0 0 0 0 0 0 0.0 0 0 0 0 0 1 0" />
               <feGaussianBlur result="blurOut" in="matrixOut" stdDeviation="8" />
               <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
             </filter>
             <filter id="f3" x="0" y="0" width="200%" height="200%">
               <feOffset result="offOut" in="SourceAlpha" dx="4" dy="4" />
                <feGaussianBlur result="blurOut" in="offOut" stdDeviation="5" />
                 <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
             </filter>
           </defs>'''

    # actual box for server with rounded corners
    data = data + '''
          <rect
            fill="%s"
            style="stroke:%s;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
            id="rect%s"
            width="400"
            height="%s"
            x="%s"
            y="%s"
            rx="6"
            ry="6"
          />''' % ( fill, stroke, servername, numports*32+yofs, x, y)      #'''

    data = data + '<text><tspan x="%s" y="%s" font-size="24" fill="%s">' % (x+12, y+30, '#666666')
    data = data + servername + ' ' + '</tspan>'

    if numports < 2:
       data = data + '<tspan font-size="10" dy="-4" fill="%s">' % 'black'
       data = data + reserved + '</tspan></text>'
    else:
       data = data + '</text><text x="%s" y="%s" font-size="10" fill="%s">' % (x+13, y+46, 'black')
       data = data + reserved + '</text>'

    # port boxes on server
    for i in range(0, numports):
        data = data + '''
         <rect
            style="fill:%s;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
            id="port%s"
            width="20"
            height="20"
            x="%s"
            y="%s"
            rx="2"
            ry="2"
         />''' % (portcolor, i, x-28, y+(i*32)+10)      #'''

        data = data + '<text x="%s" y="%s" style="font-size:10px;fill:black;text-align:center;">' % (x-24, y+24+i*32)
        data = data + '%s</text>' % (ports[i])

    # draw boxes on switch that these are connected to
    for i in range(0, numports):
        data = data + '''
         <rect class="play"
            style="fill:%s;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
            id="port%s"
            width="20"
            height="20"
            x="%s"
            y="%s"
            rx="2"
            ry="2"
            onclick="javascript:setEndPoint('%s','%s','%s','%s');"
         />''' % (portcolor, i, x-179, y+(i*32)+10, servername, switchports[i], x-179, y+(i*32)+10)     #'''

        # xx or na in config means port not used, gray them out
        if switchports[i] != 'xx' and switchports[i] != 'na':
           pfill = 'black'
        else:
       	   linkstatus[i] = False
           pfill = portcolor

        data = data + '<text x="%s" y="%s" style="font-size:10px;fill:black;text-align:center;">' % (x-174, y+24+i*32)
        data = data + '%s</text>' % (switchports[i])

        # path from server to packet broker is link status - loop@rate if ok, status and red if bad
        if linkstatus[i]:
           color = 'green'
           op = "0.30"
        else:
           color = 'red'
           op = "0.10"
        data = data + '<path d="M%s %s L%s %s"  stroke-opacity="0.30" stroke="%s" stroke-width="12" fill="none"/>' % (x-158, y+(i*32)+20, x-28, y+(i*32)+20, color)

    # configure button
    data = data + '''
           <rect class="cfg" x="%s" y="%s" width="40" height="20" rx="4" ry="4"
             stroke="black" stroke-width=".75" fill="#eeeeee"
             onclick="javascript:info('%s','%s');"
             onmouseover="evt.target.setAttribute('opacity', '0.5');"
             onmouseout="evt.target.setAttribute('opacity','1');"
           />''' % (x+346, y+numports*32+yofs-26, flicid, servername)  #'''

    data = data + '<text x="%s" y="%s" style="font-size:10px;fill:black;text-align:center;">' % (x+357, y+numports*32+yofs-13)
    data = data + 'Info</text>'

    return data

# draw path with random elbow for internal connections - note class="anims" causes line to animate on graphic- this is not particularly impressive but I've left it in'''

def drawpath(x0, y0, mx, x1, y1, color, id, name, port, anim):
    strdar = "0"
    strdof = "0"
    if anim == "play":
       strdar = "7"
       strdof = "70"
    else:
       strdar = "0"
       strdof = "0"
    data = '''<a onclick="javascript:deletepath('%s');" style="cursor:pointer;"><path class="animlines" d="M%s %s L%s %s L%s %s L%s %s"
                stroke-linejoin="round"
                stroke-opacity="0.30" stroke="%s" stroke-width="10" stroke-dasharray="%s" stroke-dashoffset="%s" fill="none" id="%s" </path>
              </a>''' % (id, x0, y0, mx, y0, mx, y1, x1, y1, color, strdar, strdof, id)  #'''
    return data



