# set encoding=utf8
import sys
import re
import numpy as np
import visual as vis

#########################################
def read_colors(src):
    color_re = re.compile(
            r'#define\s+([A-Z_]+)\s+(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)')

    colors = []
    with open(src) as f:
        for line in f.readlines():
            m = color_re.match(line)
            if m:
                name = m.group(1)[:3]
                r = int(m.group(2))
                g = int(m.group(3))
                b = int(m.group(4))
                c = int(m.group(5))
                colors.append([name,np.array([r,g,b,c])])
    return colors

#########################################
def create_colormap(colors,table):
    m = {}
    for i,(name,_) in enumerate(colors):
        m[tuple(table[i,:3])] = name

    for r in range(8):
        for g in range(8):
            for b in range(8):
                src = np.array([r,g,b])
                dists = [sum((src-t)**2) for t in table[:,:3]]
                nearest = np.argmin(dists)
                m[(r,g,b)] = (colors[nearest][0],dists[nearest] == 0)
    return m

#########################################
def normalize_colors_1(table):
    '''compute range for each channel'''
    amin = np.amin(table,axis=0)
    amax = np.amax(table,axis=0)
    for i,col in enumerate(table.T):
        table[:,i] = np.interp(col,[amin[i],amax[i]],[0,7]).astype(int)

#########################################
def normalize_colors_2(table):
    '''compute range from BLACK and WHITE only'''
    amin = table[0]
    amax = table[1]
    for i,col in enumerate(table.T):
        table[:,i] = np.interp(col,[amin[i],amax[i]],[0,7]).astype(int)

#########################################
def normalize_colors_3(table):
    '''compute range from clear channel'''
    for i,row in enumerate(table):
        table[i,:] = np.interp(row,[0,table[i,-1]],[0,7]).astype(int)

#########################################
if len(sys.argv) != 2:
    print "Usage: %s <src-file>" % sys.argv[0]
    exit(1)

colors = read_colors(sys.argv[1])
table = np.array([values for name,values in colors])

print "Raw color values"
for i,(name,channels) in enumerate(colors):
    print name,list(table[i])

normalize_colors_2(table)
print "Normalized color values"
for i,(name,channels) in enumerate(colors):
    print name,list(table[i])
colormap = create_colormap(colors,table)

vis.scene.center = (3.5,3.5,3.5)
vis.scene.range = 6

dots = {}
labels = {}
for r in range(8):
    for g in range(8):
        for b in range(8):
            try:
                color,key = colormap[r,g,b]
            except KeyError:
                color = 'U'
            dots[(r,g,b)] = vis.sphere(
                    pos=(r,g,b),
                    radius=0.2,
                    color=(r/7.0,g/7.0,b/7.0),
                    material=vis.materials.emissive)
            if key:
                dots[(r,g,b)].radius = 0.5
            dots[(r,g,b)].tag = color
            if color != "U":
                labels[(r,g,b)] = vis.label(
                        pos=(r,g,b),
                        text=color,
                        height=10,
                        opacity=.0,
                        box=False,
                        visible=False)
                labels[(r,g,b)].tag = color

show_labels = False
while True:
    vis.rate(10)

    if vis.scene.kb.keys:
        key = vis.scene.kb.getkey()
        if key == 'r':
            for d in dots.values():
                d.visible = True
            if show_labels:
                for lb in labels.values():
                    lb.visible = True
        elif key == 'l':
            show_labels = not show_labels
            if show_labels:
                for rgb in dots.keys():
                    if dots[rgb].visible:
                        try:
                            labels[rgb].visible = True
                        except:
                            pass
            else:
                for lb in labels.values():
                    lb.visible = False
        elif key == 'q':
            vis.exit()

    if vis.scene.mouse.clicked:
        m = vis.scene.mouse.getclick()
        if m.pick.tag != "U":
            for d in dots.values():
                if d.tag != m.pick.tag:
                    d.visible = False
            for lb in labels.values():
                if lb.tag != m.pick.tag:
                    lb.visible = False
