# OneDMapTool.py

# try importing modules, catch exceptions if a module isn't installed
try:
	import sys
	import matplotlib.pyplot as plt
	import numpy as np
	import OneDMapClasses as odm

except ImportError, msg:
	print 'Error importing modules:', msg
	sys.exit()

# Create a dictionary of map choices with pointers to their classes.
# Note that only references to the classes are stored below and no objects
# are actually created until the main loop.
maps = {
	'1' : ['Logistic Map: f(x)=r*x*(1-x)', odm.LogisticMap],
	'2' : ['Cosine Map: f(x)=r*cos(x)', odm.CosineMap],
}
mapList = maps.keys()	# convenient for looping in order
mapList.sort()	# dictionaries do not necessarily automatically sort, even if
				# items are entered in correct order, so we have to manually sort
mapChoice = None

# main loop...
while mapChoice != '0':

	# prompt user for map choice
	print '\nOne Dimensional Map Bifurcation Tool'
	print 'Maps available:'
	for item in mapList:
		print item, '-', maps[item][0]

	# get choice from user		
	mapChoice = raw_input('Enter choice (%s-%s) or 0 to quit): ' % (mapList[0], mapList[-1]))

	# check if user wants to quit
	if mapChoice == '0': 
		print 'Exiting bifurcation tool...'
		break	# break out of main loop

	# else check if valid choice
	elif mapChoice not in mapList: 
		print '\n-->Invalid choice! Please try again...'
		continue	# skip to beginning of main loop to try again

	# this is where we actually create a map object
	OneDMap = maps[mapChoice][1]()

	# get initial condition from user
	while True:
		ic = raw_input('Enter initial condition (leave blank for default of %0.2f): ' \
			% OneDMap.defaults[0]).strip()

		if ic != '':	# something was entered
			try:
				OneDMap.ic = float(ic)	# try saving value to the map object
				break	# break out of loop if valid ic

			except ValueError:	# catch non-numerical input
				print 'Invalid number... try again'
		else:	# user wants default
			break	# default value is already set, so jump out of loop, go to next prompt


	# get lower parameter limit
	while True:
		rLow = raw_input('Enter lower limit of r (leave blank for default of %0.2f): ' \
			% OneDMap.defaults[1]).strip()

		if rLow != '':	# something was entered
			try:
				OneDMap.rLow = float(rLow)	# try saving value to the map object
				break	# break out of loop if valid ic

			except ValueError:	# catch non-numerical input
				print 'Invalid number... try again'
		else:	# user wants default
			break	# default value is already set, so jump out of loop, go to next prompt

	# get upper parameter limit
	while True:
		rHi = raw_input('Enter upper limit of r (leave blank for default of %0.2f): ' \
			% OneDMap.defaults[2]).strip()

		if rHi != '':	# something was entered
			try:
				OneDMap.rHi = float(rHi)	# try saving value to the map object
				break	# break out of loop if valid ic

			except ValueError:	# catch non-numerical input
				print 'Invalid number... try again'
		else:	# user wants default
			break	# default value is already set, so jump out of loop, go to next prompt

	# now compute and plot the bifurcation diagram
	OneDMap.plotBifn()

	# delete object before creating a new one
	del OneDMap 

## end main loop ##
