#!/usr/bin/python
# -*- coding: utf-8 -*-

# Script to create a slightly more useful attempt
# at a prospecting guide.

# Now obsolete - replace y troggle/core/views/prospect.py

areas = ['', '1a','1b','1c','1d', '2a', '2b', '2c', '2d', '3', '4', '5', '6','7', '8a', '8b', '8c', '8d', '9', '10', '11']

areanames = {
	'':     'Location unclear',
	'1a':   '1a – Plateau: around Top Camp',
	'1b':   '1b – Western plateau near 182',
	'1c':   '1c – Eastern plateau near 204 walk-in path',
	'1d':   '1d – Further plateau around 76',
	'2a':   '2a – Southern Schwarzmooskogel near 201 path and the Nipple',
	'2b':   '2b – Eishöhle area',
	'2c':   '2c – Kaninchenhöhle area',
	'2d':   '2d – Steinbrückenhöhle area',
	'3':    '3 – Bräuning Alm',
	'4':	'4 – Kratzer valley',
	'5':	'5 – Schwarzmoos-Wildensee',
	'6':	'6 – Far plateau',
	'7':	'7 – Egglgrube',
	'8a':	'8a – Loser south face',
	'8b':	'8b – Loser below Dimmelwand',
	'8c':	'8c – Augst See',
	'8d':	'8d – Loser-Hochganger ridge',
	'9':	'9 – Gschwandt Alm',
	'10':	'10 – Altaussee',
	'11':	'11 – Augstbach'
	}

areacolours = {
	'1a' : '#00ffff',
	'1b' : '#ff00ff',
	'1c' : '#ffff00',
	'1d' : '#ffffff',
	'2a' : '#ff0000',
	'2b' : '#00ff00',
	'2c' : '#008800',
	'2d' : '#ff9900',
	'3'  : '#880000',
	'4'  : '#0000ff',
	'6'  : '#000000', # doubles for surface fixed pts, and anything else
	'7'  : '#808080'
	}


cavelists={}
for a in areas: cavelists[a]=[]

#check to see if cmd is on $PATH
def exists_in_path(cmd):
	# can't search the path if a directory is specified
	assert not os.path.dirname(cmd)

	extensions = os.environ.get("PATHEXT", "").split(os.pathsep)
	for directory in os.environ.get("PATH", "").split(os.pathsep):
		base = os.path.join(directory, cmd)
		options = [base] + [(base + ext) for ext in extensions]
		for filename in options:
			if os.path.exists(filename):
				return True
	return False

def chomp(s):
	if not s: return s
	if s[-1]=="\n": return s[:-1]
	else: return s

def find_effective_number(c):
	"""Determine an appropriate number to use."""
	if c["Kataster Number"]:
		return c["Kataster Number"]
	else:
		return c["Unofficial number"]

def longnumber(c, number):
	"""Both numbers"""
	if c["Unofficial number"] and c["Unofficial number"] != number:
		return number + " (" + c["Unofficial number"] + ")"
	else:
		return number

def find_location(cave):
	for fixtype in ["tag point in dataset", "other point in dataset", "exact entrance in dataset (drip line/highest enclosed contour)", "GPS post SA", "GPS pre SA"]:
		if cave[fixtype]:
			return positions[cave[fixtype]]
	return 0


def is_explored(cave):
	s = cave["Kat Status Code"]
	if not s: return "<td></td>"
	s = s.replace("(?)","")
	if s[-1] == " ": s=s[:-1]
	if not s:
		print "Rogue space in " + find_effective_number(cave)
		return "<td></td>"
	code = s[-1]
	if code == '+': status = "good"
	elif code in ['=', 'x']: status = "bad"
	elif code in ['-', '?']: status = "awful"
	else: return "<td>%s</td>" % code
	return "<td class=\"%s\">%s</td>" % (status, code)

def is_tagged(cave):
	s = chomp(cave["Marking"])
	s = re.sub(r'\s+(?:\(\?\))?$', "", s)
	if not s and cave["Multiple entrances"] in ["yes", "entrance", "last entrance"]:
		return "<td></td>"
	if s == "Tag": return "<td class=\"good\">%s</td>" % s
	if s in ["Retag", "Paint", "Spit"]: return "<td class=\"bad\">%s</td>" % s
	if s == "Unmarked": return "<td class=\"awful\">None</td>"
	if s == "": return "<td class=\"awful\"></td>"
	print "Unrecognised marking status on %s: %s" % (find_effective_number(cave), repr(s))
	return "<td>ERROR</td>"

def findability_color(cave):
	if cave["Findability"] == "Surveyed": return "good"
	elif cave["Findability"] == "Refindable": return "bad"
	elif cave["Findability"] == "Lost": return "awful"
	else:	return ""

def is_underground_surveyed(cave):
	s = chomp(cave["Underground drawn survey"])
	if cave["Multiple entrances"] not in ["", "yes"]: return "<td></td>"
	if not s:
		return "<td class=\"awful\">None</td>"
	if s.find("<img") > -1 or s.find("<a") > -1:
		return "<td class=\"good\">Yes</td>"
	else:
		return "<td class=\"bad\">Missing</td>"

def have_survey_data(cave):
	if cave["Multiple entrances"] not in ["", "yes"]: return "<td></td>"
	s = chomp(cave["Underground centre line"])
	if s: return "<td class=\"good\">Yes</td>"
	s = chomp(cave["Survex file to get length and depth"])
	if s: return "<td class=\"good\">Yes</td>"
	if cave["Kat Status Code"] and cave["Kat Status Code"][0] == '1':
		# Cave < 50m deep and < 50m long...
		# Sadly this band includes caves we really ought to have data for as
		# well as caves small enough that a grade 1 sketch is justifiable.
		return "<td class=\"bad\"><small>&lt;50m</small></td>"
	s = chomp(cave["Underground drawn survey"])
	if s: return "<td class=\"bad\">Missing</td>"
	return "<td class=\"awful\">None</td>"

def has_photo(cave):
	s = chomp(cave["Photo of location"])
	if (cave["Multiple entrances"] not in ["", "yes"]) and chomp(cave["Autogen file"]) == "":
		return "<td></td>"
	if not s:
		return "<td class=\"awful\">None</td>"
	if s.find("<img") > -1 or s.find("<a") > -1:
		return "<td class=\"good\">Yes</td>"
	else:
		return "<td class=\"bad\">Missing</td>"

def find_label(cave, number):
	t = longnumber(cave, number) + " "
	if(cave["Name"] and cave["Unofficial Name"]): t += cave["Name"] + " (" + cave["Unofficial Name"] + ")"
	elif cave["Name"]: t += cave["Name"]
	else: t += cave["Unofficial Name"]
	try:
		n = number
		if n[-1] in string.lowercase: n = n[:-1]
	except:
		n = "NONE"
	if lengths.has_key(n):
		t += (" %sm long %sm deep" % (lengths[n][0], lengths[n][1]))
	return t

def get_img_name(maparea):
	filename = "prospecting_guide"
	if maparea != "all":
		filename += "_" + maparea + "area"
	if showbg:
		filename += ".jpg"
	else:
		filename += ".png"
	return filename

# Parameters for big map and zoomed subarea maps:
# big map first (zoom factor ignored)

maps = {
# id	left		top			right		bottom		zoom	description
#		UTM33		UTM33		UTM33		UTM33		factor
# DO NOT just change the coordinates of "all" - they MUST match the borders of the background image.
"all": [ 409276., 5285237., 413197., 5279805., 1.0,	"All"],
"40":  [ 411110., 5281326., 411603., 5280722., 3.0,	"Eish&ouml;hle"],
"76":  [ 410293., 5282171., 410931., 5281607., 3.0,	"Eislufth&ouml;hle"],
"204": [ 411226., 5283086., 411904., 5282315., 3.0,	"Steinbr&uuml;ckenh&ouml;hle"],
"tc":  [ 410071., 5281646., 410939., 5281036., 3.0,	"Near Top Camp"],
"gk":  [ 410918., 5285237., 413197., 5283288., 4.0,	"Grie&szlig;kogel Area"],
}
# Keys in the order in which we want the maps output
mapcodes = ["all", "gk", "40", "76", "204", "tc"]
# Field codes
L = 0
T = 1
R = 2
B = 3
ZOOM = 4
DESC = 5

import Image, ImageDraw, ImageFont, string, os, sys
for FONT in [
		"/usr/share/fonts/truetype/freefont/FreeSans.ttf",
		"/usr/X11R6/lib/X11/fonts/truetype/arial.ttf",
		"C:\WINNT\Fonts\ARIAL.TTF"
		]:
	if os.path.isfile(FONT): break
SIZE = 8
myFont = ImageFont.truetype(FONT, SIZE)

showbg = not(len(sys.argv) > 1 and sys.argv[1] == '--white')
mainImage = Image.open("pguidemap.png")
if not showbg:
	mainImage = Image.new("RGB", mainImage.size, '#ffffff')

imgs = {}
draws = {}
imgmaps = {}
factors = {}
for maparea in maps.keys():
	m = maps[maparea]
	if maparea == "all":
		img = mainImage
	else:
		M = maps['all']
		W, H = mainImage.size
		l = int(float(m[L] - M[L]) / (M[R] - M[L]) * W)
		t = int(float(m[T] - M[T]) / (M[B] - M[T]) * H)
		r = int(float(m[R] - M[L]) / (M[R] - M[L]) * W)
		b = int(float(m[B] - M[T]) / (M[B] - M[T]) * H)
		img = mainImage.crop((l, t, r, b))
		w = int(round(m[ZOOM] * float(m[R] - m[L]) / (M[R] - M[L]) * W))
		h = int(round(m[ZOOM] * float(m[B] - m[T]) / (M[B] - M[T]) * H))
		print "%s: H %d W %d" % (maparea, h, w)
		img = img.resize((w, h), Image.BICUBIC)
	imgs[maparea] = img
	draw = ImageDraw.Draw(img)
	draw.setfont(myFont)
	draws[maparea] = draw
	imgmaps[maparea] = []
	# Draw scale bar
	m100 = int(100.0 / (m[R] - m[L]) * img.size[0])
	draw.line([10, SIZE*3, 10, SIZE*2], fill='#000000')
	draw.line([10, SIZE*2, 10+m100, SIZE*2], fill='#000000')
	draw.line([10+m100, SIZE * 3, 10+m100, SIZE*2], fill='#000000')
	label = "100m"
	draw.text([10 + (m100 - draw.textsize(label)[0]) / 2, SIZE/2], label, fill='#000000')
	factors[maparea] = img.size[0] / (m[R] - m[L]), img.size[1] / (m[T] - m[B])

def mungecoord(x, y, mapcode):
	# Top of Zinken is 73 1201 = dataset 34542 81967
	# Top of Hinter is 1073 562 = dataset 36670 83317
	# image is 1417 by 2201
	# FACTOR1 = 1000.0 / (36670.0-34542.0)
	# FACTOR2 = (1201.0-562.0) / (83317 - 81967)
	# FACTOR = (FACTOR1 + FACTOR2)/2
	# The factors aren't the same as the scanned map's at a slight angle. I
	# can't be bothered to fix this.  Since we zero on the Hinter it makes
	# very little difference for caves in the areas round 76 or 204.
	# xoffset = (x - 36670)*FACTOR
	# yoffset = (y - 83317)*FACTOR
	# return (1073 + xoffset, 562 - yoffset)

	m = maps[mapcode]
	return ((x - m[L]) * factors[mapcode][0], (m[T] - y) * factors[mapcode][1])


def plot(loctuple, number, area, label):
	shortnumber = number.replace("&mdash;","")

	if area in areacolours:
		fillcol = areacolours[area]
	else:
		fillcol = 6

	for maparea in maps.keys():
		(x,y) = map(int, mungecoord(loctuple[0], loctuple[1], maparea))
		draw = draws[maparea]
		imgmaps[maparea].append( [x-4, y-SIZE/2, x+4+draw.textsize(shortnumber)[0], y+SIZE/2, shortnumber, label] )
		draw.rectangle([(x+4, y-SIZE/2), (x+4+draw.textsize(shortnumber)[0], y+SIZE/2)], fill="#ffffff")
		draw.text((x+6,y-SIZE/2), shortnumber, fill="#000000")
		draw.ellipse([(x-4,y-4),(x+4,y+4)], fill=fillcol, outline="#000000")

def writeout_imagemap(data, mapname):
	# Munge the list of coordinates into a proper image map.
	# There is a wrinkle here: the HTML spec gives priority
	# to the _first_ defined elt, so we swap the order!
	n = len(data)
	htmlfile.write("<map id=\"%s\" name=\"%s\">" % (mapname, mapname))
	for j in xrange(n):
		try:
			i = data[n-j-1]
			htmlfile.write("<area shape=\"rect\" coords=\"%d, %d, %d, %d\" href=\"#id%s\" title=\"%s\" />\n" % (i[0],i[1],i[2],i[3],i[4],i[5]))
		except:
			print "Died on", repr( data[n-j-1] )
			#raise
	htmlfile.write("</map>")


import csv, re, time
cavetabfile = file("../CAVETAB2.CSV")
fieldnames=chomp(cavetabfile.next()).replace('"','').split(",")
cavetab = csv.DictReader(cavetabfile, fieldnames)

print "Munging lengths.dat"
lengthsfile = file("../lengths.dat")
lengths = {}
for l in lengthsfile:
	t = l.replace("\"","").replace("\n", "").split("\t")
	lengths[t[0]] = (t[1], t[2])
print "Done"

# Draw cave passage
print "Munging dump3d output"

if exists_in_path("dump3d"):
	dump3d_binary = "dump3d"
else:
	# assume it's in this directory
	dump3d_binary = os.path.join(os.path.dirname(os.path.realpath(__file__)),"./dump3d")
positions = {}
surfacecolour = "#808080"
repath = re.compile(r'^(?:182to(?:tc|184)|tctocol|82to97|vd1to161d|161ftod|161etof|161etog|40entlink2|surfnr161|surf161|kansurf)$')
for fnm in ("../all.3d", "../alltracks.3d"):
	for mapcode in draws.keys():
		file3d = os.popen(dump3d_binary + " " + fnm)
		draw = draws[mapcode]
		lastx, lasty = 0, 0
		for l in file3d:
			# Quickly skip data we aren't interested in
			if l.startswith("ERROR_INFO"): continue
			if l.startswith("XSECT"): continue

			match = re.match(r'''
			                  ^                 #start
					  (MOVE|LINE|NODE)   #data type
					  \s+(-?[0-9.]+)     #X-co-ord
					  \s+(-?[0-9.]+)     #Y-co-ord
					  \s+(-?[0-9.]+)     #altitude
					  (?:                #grouping without saving result - for station name
					    \s+              #at least one space
					    \[               #opening [
					    (\S*)            #the station name we want to save
					    \]               #closing ]
					  )?                 #end of optional station name group
					  (?:                #grouping without saving result - for flags
					    \s+              #at least one space separating from [station]
					    (.*)             #all the flags, including spaces
					  )?                 #end of optional flags group
					  $                  #end of the line
					  ''', l, re.VERBOSE)
			if not match:
				print "Unknown: " + l
				continue


			act,E,N,alt,name,flags = match.groups()
#			print "act:%s, E:%s, N:%s, name:%s flags:%s" % (act,E,N,name,flags)
			# Only need to process NODEs once
			if act == "NODE" and mapcode != "all": continue

			if not flags: flags = ""
			E,N = map(float, (E,N))
			if act == "NODE":
				positions[name] = (E,N,float(alt))
				continue

			x,y = map(int, mungecoord(E, N, mapcode))

			if act == "LINE":
				if re.search(r'\bSURFACE\b', flags):
					if re.search(repath, name):
						draw.line([lastx, lasty, x, y], fill='#008000')
					else:
						draw.line([lastx, lasty, x, y], fill='#808080')
				else:
					draw.line([lastx, lasty, x, y], fill="#800080")
			lastx,lasty = x,y
		#if not file3d.close():
			# FIXME: If dump3d can't give an error and exits with non-zero status, this
			# doesn't get triggered...
			#print "Running command: %s %s failed: %s" % (dump3d_binary, fnm, file3d)
	surfacecolour = "#008000"
	repath = re.compile(r'^')
print "Done"

cavestoplot = []
for cave in cavetab:
	if cave["Link file"]: continue
	number = find_effective_number(cave)
	if cave["Multiple entrances"] not in ["", "yes"]:
		number = "&mdash;" + cachednumber + cave["Entrances"]
		shortnumber = cachednumber
		if not cave["Area"]: cave["Area"] = cachedarea
		if not cave["Name"]: cave["Name"] = cachedname
	else:
		cachednumber = number
		shortnumber = number
		cachedname = cave["Name"] or cave["Unofficial Name"]
		cachedarea = cave["Area"]

	area = cave["Area"]
	# We have some areas like '2b or 4 (unclear)' - just chop the space
	# and everything after it for these.
	area = re.sub(r' .*', "", area)
	if area == '1626' or area == 'nonexistent': continue

	try:
		loctuple = find_location(cave)
	except:
		print "Unable to find location for %s" % (number)
	else:
		label = find_label(cave, shortnumber)
		if(cave["Multiple entrances"] == "yes"):
			locn = "<td colspan=\"3\">&nbsp;</td>"
		elif(loctuple):
			locn = "<td class=\"locn good\">%d</td><td class=\"locn good\">%d</td><td class=\"locn good\">%d</td>" % loctuple
			cavestoplot.append((loctuple, number, area, label))
		else:
			locn = "<td colspan=\"3\" class=%s>" % findability_color(cave) + (cave["Findability"] or '?') + "</td>"
		try:
			cavelists[area].append((number, cave, locn))
		except:
			print "Bad area '%s' for cave %s" % (area, number)

if showbg:
    htmlfile = file("/dev/null", "w")
else:
	htmlfile = file("../../handbook/prospecting_guide.html", "w")

htmlfile.write("<html><head><meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\"><title>Prospecting Guide</title>\n")
htmlfile.write("<script lang=\"Javascript\"><!--\n")
for maparea in mapcodes:
	htmlfile.write("bg%s = false;\n" % maparea)
htmlfile.write("//-->\n</script>\n")
htmlfile.write("""
<style type="text/css">
.locn { font-size: x-small }
.bad	{ background-color: #ff9955; text-align: center }
.good	{ background-color: #99f<p><b>Notes:</b></p><ul><li>A marking status of \"Retag\" means a tag is in place but it carries a provisional number, or in some cases an incorrect number, and needs replacing with a new tag.</li>\n<li>Kataster status codes indicate the size of a cave, its character and its exploration status, as described <a href=\"../katast.htm\">here</a>.</li><li>For more info on each cave, see the links to detailed description pages.</li></ul>\nf99; text-align: center }
.awful	{ background-color: #ff5555; text-align: center }
.notours .good  { background-color: #ffffff; }
.notours .bad   { background-color: #ffffff; }
.notours .awful { background-color: #ffffff; }
</style>
<meta name="keywords" content="NOEDIT">
</head>""")
htmlfile.write("<body><h1>Prospecting Guide</h1>")
htmlfile.write("<p><small>Generated " + time.strftime("%Y-%m-%d %H:%M:%S %Z") + " by " + sys.argv[0] + "</small></p>\n")
htmlfile.write("<p><b>Notes:</b></p><ul><li>A marking status of \"Retag\" means a tag is in place but it carries a provisional number, or in some cases an incorrect number, and needs replacing with a new tag.</li>\n<li>Kataster status codes indicate the size of a cave, its character and its exploration status, as described <a href=\"../katast.htm\">here</a>.</li><li>For more info on each cave, see the links to detailed description pages.</li></ul>\n")

for maparea in mapcodes:
	filename = get_img_name(maparea)
	if maparea != "all":
		htmlfile.write("<h3 id=\"idsubmap%s\">%s area detail</h3>\n" % (maparea, maps[maparea][DESC]))
	basename = filename[0:-3]
	htmlfile.write("<button onclick=\"if (bg%s) img%s.src = '%spng'; else img%s.src = '../noinfo/%sjpg'; bg%s = !bg%s;\">Toggle Background</button>\n" % (maparea, maparea, basename, maparea, basename, maparea, maparea))
	htmlfile.write("<small>Note: this requires a login to work!</small>\n")
	htmlfile.write("<p><img src=\"%s\" usemap=\"#map%s\" ismap=\"ismap\" name=\"img%s\"" % (filename, maparea, maparea))
	htmlfile.write(" width=\"%d\" height=\"%d\" /></p>\n" % imgs[maparea].size)

cachednumber = ""
cachedarea = ""
cachedname = ""

# Plot the subareas on the full map
for maparea in maps.keys():
	if maparea == "all":
		continue
	m = maps[maparea]
	l,t = mungecoord(m[L], m[T], "all")
	r,b = mungecoord(m[R], m[B], "all")
	text = maparea + " map"
	textlen = draws['all'].textsize(text)[0] + 3
	draws['all'].rectangle([l, t, l+textlen, t+SIZE+2], fill='#ffffff')
	draws['all'].text((l+2, t+1), text, fill="#000000")
	imgmaps['all'].append( [l, t, l+textlen, t+SIZE+2, "submap" + maparea, maparea + " subarea map"] )
	draws['all'].rectangle([l, t, r, b], outline='#777777')
	draws['all'].rectangle([l, t, l+textlen, t+SIZE+2], outline='#777777')

# Plot faked positions first so that real caves go on top of the large circles
fakedpositions = file("fakedpositions.dat")
for p in fakedpositions:
	try:
		(x,y,d,name) = re.match(r'\(([0-9.]*?),\t([0-9.]*?),\t([0-9.]*?)\)\t(.*?)[\t ]*#', chomp(p)).groups()
	except:
		print "Couldn't understand" + repr(chomp(p))
		continue

	# Find the area with this cave in
	area = ''
	for tryarea in areas:
		for (number, cave, locn) in cavelists[tryarea]:
			if name == number:
				area = tryarea
				break
		# FIXME really want to break from both loops at once
		# but I don't know how to in Python
		if area != '':
			break

	(x,y,d) = map(float, (x,y,d))
	for maparea in maps.keys():
		lo = mungecoord(x-d, y+d, maparea)
		hi = mungecoord(x+d, y-d, maparea)
		lpos = mungecoord(x-d, y, maparea)
		draw = draws[maparea]
		draw.ellipse([lo,hi], outline="#000000")
		draw.ellipse([lo[0]+1, lo[1]+1,hi[0]-1, hi[1]-1], outline=areacolours[area])
		draw.ellipse([lo[0]+2, lo[1]+2,hi[0]-2, hi[1]-2], outline=areacolours[area])
		draw.rectangle([lpos[0],lpos[1]-SIZE/2, lpos[0] + draw.textsize(name)[0], lpos[1]+SIZE/2], fill="#ffffff")
		imgmaps[maparea].append( [lpos[0],lpos[1]-SIZE/2, lpos[0] + draw.textsize(name)[0], lpos[1]+SIZE/2, name, "Approx position of %s" % name] )

		draw.text((lpos[0], lpos[1]-SIZE/2), name, fill="#000000")

plot(positions["laser.0_7"], "BNase", "6", "Br&auml;uning Nase laser point")
plot(positions["226-96"], "BZkn", "6", "Br&auml;uning Zinken trig point")
plot(positions["vd1"],"VD1","6", "VD1 survey point")
plot(positions["laser.kt114_96"],"HSK","6", "Hinterer Schwarzmooskogel trig point")
plot(positions["2000"],"Nipple","6", "Nipple (Wei&szlig;e Warze)")
plot(positions["3000"],"VSK","6", "Vorderer Schwarzmooskogel summit")
plot(positions["topcamp"], "TC", "6", "Top Camp")
plot(positions["laser.0"], "LSR0", "6", "Laser Point 0")
plot(positions["laser.0_1"], "LSR1", "6", "Laser Point 0/1")
plot(positions["laser.0_3"], "LSR3", "6", "Laser Point 0/3")
plot(positions["laser.0_5"], "LSR5", "6", "Laser Point 0/5")
plot(positions["225-96"], "BAlm", "6", "Br&auml;uning Alm trig point")

for (loctuple, number, area, label) in cavestoplot:
	plot(loctuple, number, area, label)

for area in areas:
	if area:
		htmlfile.write("<h3><span style=\"background-color: %s; border: 1px solid black\">&nbsp;&nbsp;</span> %s</h3>" % (areacolours.get(area, "#ffffff"), areanames[area]))
	else:
		htmlfile.write("<h3>Location unclear</h3>")
	htmlfile.write("<table border=\"1\">\n")
	htmlfile.write("<tr><th>Cave Number</th><th>Name</th><th>Finished</th><th>Survey<br>Data</th><th>Survey<br>Drawn</th><th>Marked</th><th>Photo</th><th>E</th><th>N</th><th>Alt</th><th>Location</th>")

	for (number, cave, locn) in cavelists[area]:
		# We only check the "oursness" for the first entrance.
		if cave["Multiple entrances"] in ["", "yes"]:
			notours = not re.search(r'CUCC', cave['Explorers'])
		if notours:
			htmlfile.write("<tr class=\"notours\">")
		else:
			htmlfile.write("<tr>")

		if cave["Autogen file"]:
			htmlfile.write("<td><a href=\"../%s\">%s</a></td><td><a id=\"id%s\">%s</a></td>" % (cave["Autogen file"], longnumber(cave, number), number.replace("&mdash;", ""), cave["Name"] or cave["Unofficial Name"]))
		else:
			htmlfile.write("<td>%s</td><td><a id=\"id%s\">%s</a></td>" % (longnumber(cave, number), number.replace("&mdash;", ""), cave["Name"] or cave["Unofficial Name"]))

		htmlfile.write(is_explored(cave))
		htmlfile.write(have_survey_data(cave))
		htmlfile.write(is_underground_surveyed(cave))
		htmlfile.write(is_tagged(cave))
		htmlfile.write(has_photo(cave))

		htmlfile.write(locn)
		if cave["Findability"] != "Surveyed" and cave["Multiple entrances"] != "yes":
			htmlfile.write("<td class=\"locn\">%s %s</td>" % (cave["Location"], cave["Bearings"]))
		htmlfile.write("</tr>\n")

	htmlfile.write("</table>\n")

for maparea in imgmaps.keys():
	writeout_imagemap(imgmaps[maparea], "map" + maparea)

htmlfile.write("</body></html>")
htmlfile.close()

if showbg:
	imgpath = "../"
else:
	imgpath = "../../handbook/"

for maparea in imgs.keys():
	del draws[maparea]
	filename = get_img_name(maparea)
	imgs[maparea].save(imgpath + filename)

# vim:syntax=python:set ts=4: