#!/usr/bin/env python

import os
import re
import sys

if sys.platform[:3] == 'win':
    MAPRGB = r'maprgb'
    GS = r'c:\gs\gs7.04\bin\gswin32c'
    PAGER = None
else:
    MAPRGB = r'maprgb'
    GS = r'gs'
    PAGER = os.getenv('PAGER', 'more')

# Ghostscript options:
margin = 10
resolution = 90

if len(sys.argv) != 3:
    print >> sys.stderr, '''
Usage: %s config_file difference_file
''' % os.path.basename(sys.argv[0])
    sys.exit()

def getline(fp):
    while True:
        i = fp.readline()
        if not i:
            return False
        i = i.strip()
        if i and i[0] != '#':
            return i

def unquote(s):
    if s[0] == '"' and s[-1] == '"':
        s = s[1:-1]
        s = re.sub(r'\\(.)', r'\1', s)
    return s

configfile = sys.argv[1]
infile = sys.argv[2]
tmpfile = 'maprefs.tmp'

fp = open(configfile, 'r')
for line in fp:
    if line[:12] == 'boundingbox:':
        x1, y1, x2, y2 = [int(i) for i in line[12:].split()]
        x1 -= margin
        y1 -= margin
        x2 += margin
        y2 += margin
    elif line[:7] == 'labels:':
        lblfile = line[7:].strip()
fp.close()

lblidx = {}
n_locations = 0
fp = open(lblfile, 'r')
while True:
    line = getline(fp)
    if not line:
        break
    m = re.match(r'(\d+)\s+(.*)',line)
    i = int(m.group(1))
    lblidx[unquote(m.group(2))] = i - 1
    if i > n_locations:
        n_locations = i
fp.close()
used = [False for i in range(n_locations)]
lbls = ['' for i in range(n_locations)]
for k in lblidx:
    lbls[lblidx[k]] = k

idxs = []
fp = open(infile, 'r')
n_loc = int(getline(fp))
for i in range(n_loc):
    j = lblidx[unquote(getline(fp))]
    idxs.append(j)
    used[j] = True

diffs = [None for i in range(n_locations)]
for i in range(n_locations):
    diffs[i] = [None for j in range(n_locations)]

for i in range(n_loc):
    ii = idxs[i]
    for j in range(i):
        jj = idxs[j]
        diffs[ii][jj] = diffs[jj][ii] = float(getline(fp))

fp.close()

fp = open(tmpfile, 'w')
fp.write('3\n')
for i in range(n_locations):
    if used[i]:
        fp.write(lbls[i] + '\n1\n0\n0\n')
fp.close()

Head = ['initgraphics %i %i translate\n' % (-x1, -y1)]
PP = []
PPpat = []
Tail = []

fp = os.popen('%s -r %s %s' % (MAPRGB, configfile, tmpfile), 'r')
state = 1
for line in fp:
    l = line.strip()
    if not l or l[0] == '%':
        continue
    if state == 1:
        Head.append(line)
        if line[:3] == '/PP':
            state = 2
    elif state == 2:
        if line[:5] == '] def':
            state = 3
            Tail.append(line)
        else:
            PP.append(line)
            PPpat.append(re.sub(r'\S+\s+\S+\s+\S+\s+Ord \]', '%g %g %g Ord ]', line))
    elif state == 3:
        if line[:8] != 'showpage':
            Tail.append(line)
fp.close()
Tail.append('flushpage\n')
os.remove(tmpfile)

fpgs = os.popen('%s -g%ix%i -r%i -q -' % (
    GS,
    int((x2 - x1) / 72.0 * resolution + 1),
    int((y2 - y1) / 72.0 * resolution + 1),
    resolution), 'w')

used_locations = [i for i in range(n_locations) if used[i]]

state = 0
validtxt = ''
for i in range(n_locations):
    if state == 0:
        if used[i]:
            validtxt = '%i' % (i + 1)
            i1 = i
            state = 1
    elif state == 1:
        if not used[i]:
            if i - 1 > i1:
                validtxt += '..%i' % i
            state = 2
    elif state == 2:
        if used[i]:
            validtxt += '  %i' % (i + 1)
            i1 = i
            state = 1
if state == 1:
    validtxt += '..%i' % (n_locations)

def phelp():
    print '''
COMMANDS:

number - location index
         valid numbers: %s

r - select red location
g - select green location
b - select blue location

l - linear differences
q - quadratic differences

i - index of locations
s - sorted index of locations

x - exit
''' % validtxt


def paintit():
    for i in used_locations:
        PP[i] = PPpat[i] % (reds[i] ** power, greens[i] ** power, blues[i] ** power)

    for line in Head:
        fpgs.write(line)
    for line in PP:
        fpgs.write(line)
    for line in Tail:
        fpgs.write(line)
    fpgs.flush()
    
def paint(idx):
    if idx >= 0 and idx < n_locations:
        print lbls[idx], '\n'
        if not used[idx]:
            print 'No data'            
  
    if idx < 0 or idx >= n_locations or not used[idx]:
        print '\nValid numbers: ', validtxt, '\n'
        return

    v = [diffs[idx][i] for i in used_locations if i != idx]    
    maximum = max(v)
    if min0:
        minimum = 0
    else:
        minimum = min(v)
    d = maximum - minimum

    for i in used_locations:
        if i == idx:
            current[i] = 1.0
        else:
            current[i] = (diffs[idx][i] - minimum) / d

    paintit()

def index():
    if PAGER:
        fp = os.popen(PAGER, 'w')
    else:
        fp = sys.stdout
    for i in used_locations:
        fp.write('%4i  %s\n' % (i + 1, lbls[i]))
    if PAGER:
        fp.close()

def sindex():
    s = ['%s\t%4i' % (lbls[i], i + 1) for i in used_locations]
    s.sort()
    if PAGER:
        fp = os.popen(PAGER, 'w')
    else:
        fp = sys.stdout
    for i in s:
        l, n = i.split('\t')
        fp.write('%s  %s\n' % (n, l))
    if PAGER:
        fp.close()

phelp()

power = 1
min0 = False

icol = 'red'

reds   = [0.0] * n_locations
greens = [0.0] * n_locations
blues  = [0.0] * n_locations
current = reds

while True:
    sys.stdout.write(icol + ' > ')
    l = sys.stdin.readline().strip().lower()
    if not l:
        phelp()
    elif l[0] >= '1' and l[0] <= '9':
        try:
            idx = int(l) - 1
        except:
            phelp()
        else:
            paint(idx)
    elif l[0] == 'r':
        current = reds
        icol = 'red'
    elif l[0] == 'g':
        current = greens
        icol = 'green'
    elif l[0] == 'b':
        current = blues
        icol = 'blue'
    elif l[0] == 'l':
        power = 1
        paintit()
    elif l[0] == 'q':
        power = 2
        paintit()
    elif l[0] == 'i':
        index()
    elif l[0] == 's':
        sindex()
    elif l[0] == 'x':
        break
    else:
        phelp()

fpgs.write('quit\n')
fpgs.close()
