from NCMapData import *
from Numeric import *
import Image, cPickle, math

class NCMap:
	#-----------------------------------------------
	#intialize the map with an index map and an attributes file
	#-----------------------------------------------
	def __init__(self, index_file, transform, att_file):
		#self.index = Image.open(index_file)
		f = open(index_file, 'rb')
		self.index = cPickle.load(f)
		f.close()
		
		f = open(att_file, 'rb')
		self.atts = cPickle.load(f)
		f.close()
		
		#intialize the area query size
		self.size = 1
		#set a default sampolation factor
		self.samp = 1
		
		#intialize the transformation to match the pretty image
		#set the scaling factor so that queries align
		self.trans = list(transform)

	#-----------------------------------------------
	#retrieve data for a single point
	#-----------------------------------------------
	def QueryPoint(self, x, y):
		oid = self.GetOID(x,y)
	
		if oid != None:
			md = NCMapData(oid,0,0)
			md.SetData(self.LookUp(oid))
			return md
			
		else:
			return None
		
	#-----------------------------------------------
	#retrieve all of the data within an area
	#-----------------------------------------------
	def QueryArea(self, x, y):
		#get the id directly under the point to speed things up	
		this = self.QueryPoint(x,y)
		
		#bail out if we're only interested in this one point
		if self.size == 1:
			return this

		#grab all of the ids in the local area
		#use the sampling factor so we don't have to check every
		#	pixel in a large area
		ystart = y-self.size/2
		yend = y+self.size/2
		xstart = x-self.size/2
		xend = x+self.size/2
		objs = {}

		#intialize the object array with the current object if it exists
		if this != None:
			objs[this.GetSharedOID()] = this
			cur_oid = this.GetOID()
			cur_soid = this.GetSharedOID()
		else:
			cur_oid = cur_soid = None
		
		for col in range(xstart,xend,self.samp):
			for row in range(ystart,yend,self.samp):
					oid = self.GetOID(col,row)
					
					#make sure we got some object back
					if oid != None and oid != cur_oid:
						data = self.LookUp(oid)
						soid = data['shared_index']
						
						#if this ID already exists in the list and is not the current
						#	object, just update its closest point
						if objs.has_key(soid) and soid != cur_soid:
							#calculate the new distance from here to the point
							dist = math.sqrt(pow(x-col,2) + pow(y-row,2))
							if dist < objs[soid].GetDist():
								objs[soid].SetDist(dist)
								objs[soid].SetPos(col-x,y-row)
						
						#if the ID has not already been encountered in the area
						#make a new data object
						elif soid != cur_soid:
							#calculate the new distance from here to the point
							dist = math.sqrt(pow(x-col,2) + pow(y-row,2))
							obj = objs[soid] = NCMapData(oid, col-x, y-row, dist)
							obj.SetData(data)
								
		return objs
				
	#-----------------------------------------------
	#set the size of the query area
	#-----------------------------------------------
	def SetAreaSize(self, size):
		if size < 1:
			size = 1
		self.size = size
		
	#-----------------------------------------------
	#set the sampolation factor for area queries
	#-----------------------------------------------
	def SetSampling(self, samp):
		if samp < 1:
			samp = 1
		self.samp = samp
		
	#-----------------------------------------------
	#look up the data associated with an id
	#-----------------------------------------------
	def LookUp(self, oid):
		return self.atts[oid]
		
	#-----------------------------------------------
	#get an id from the index map
	#-----------------------------------------------
	def GetOID(self, x, y):
		#transform the query coords into the index image coords
		x = int(x*self.trans[2])-self.trans[0]
		y = int(y*self.trans[3])-self.trans[1]
		
		#make sure we're within bounds
		if x < 0 or y < 0 or x >= self.index.shape[0] or y >= self.index.shape[1]:
			return None
		else:
			oid  = int(self.index[x,y])

		if oid == 0:
			return None
		else:
			return oid