# GVB - a GTK+/GNOME vibrations simulator
#
# Copyright (C) 2008 Pietro Battiston
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import gtk
import gobject

from gvbmod import drawers, dispositions, points

from scipy import array 	#Just until I find a "revert order" method for arrays...

param_names = ['lenght', 'shift', 'wavelenght', 'fase', 'amplitude', 'centering']
int_params = ['lenght', 'shift', 'wavelenght', 'fase']
rule_names = ['prod', 'sum', 'max', 'min']

reflect = -1
label = -2
rules = -3
rules_hbox = -4
drawer = -5

DIMS = [1,2]

def reflect_matrix(matrix):
	n = matrix.shape[0]
	return array([matrix[n - 1 - i ] for i in range(n) ])

class AdvancedEditor():
	def __init__(self, caller, xml, old_points, shape):
		self.caller = caller
		self.dim = len(shape)
		self.points = None
		self.ready = False
		self.skipped_one = False
		self.xml = xml

		self.window = xml.get_object('advanced editor')
		self.for_good = True

		self.widgets = {}
		for dim in DIMS:
			self.widgets[dim] = {}
			self.widgets[dim]['waveform'] = xml.get_object('editor waveform combo '+str(dim))
#			print self.widgets
			self.combo_model=gtk.ListStore(str,str)
			for waveform in dispositions.waveforms:
#				print "appended", waveform
				self.combo_model.append([_(waveform), waveform])
			self.widgets[dim]['waveform'].set_model(self.combo_model)
			self.widgets[dim]['waveform'].set_active(0)
#			print "combo:", self.combo_form, self.combo_form.get_active()

			self.widgets[dim][reflect] = xml.get_object('editor reflect check '+str(dim))
			self.widgets[dim][label] = xml.get_object('editor label '+str(dim))

			for name in param_names:
				self.widgets[dim][name] = xml.get_object('editor '+name+' scale '+str(dim))

		self.widgets[drawer] = xml.get_object('editor combo drawer')
		self.widgets[rules]=[]
		self.widgets[rules_hbox] = xml.get_object('editor rules hbox')

		for rule in rule_names:
			self.widgets[rules].append(xml.get_object('editor rule '+rule))


		self.invert_check = xml.get_object('editor invert check')
		self.add_check = xml.get_object('editor addto check')
		
		for dim in DIMS:
			for widget in self.widgets[dim]:
				if type(self.widgets[dim][widget]) == gtk.ComboBox:
					self.widgets[dim][widget].connect('changed', self.update)
				elif type(self.widgets[dim][widget]) == gtk.CheckButton:
					self.widgets[dim][widget].connect('toggled', self.update)
				elif type(self.widgets[dim][widget]) == gtk.HScale:
					self.widgets[dim][widget].connect('change-value', self.update)
		
		for widget in  [self.invert_check, self.add_check] + self.widgets[rules]:
			widget.connect('toggled', self.update)
		
		self.go(old_points, shape)


	def go(self, old_points, shape):			
#		print "shape:", shape
		self.old_points = old_points
		self.shape = shape
		self.dim = len(shape)

#		self.drawer=drawers.drawers[self.dim][self.widgets[drawer].get_active_text()]

		for dim in range(1, self.dim+1):
			if self.points == None  or len(self.points.shape) < dim or self.points.shape[dim-1] != shape[dim-1]:
				#If number of points or dimension changed since last editor call (or if this is the first call)...
				self.widgets[dim]['lenght'].set_adjustment(gtk.Adjustment(shape[0], 3, shape[0], 4, 10))
				self.widgets[dim]['shift'].set_adjustment(gtk.Adjustment(0, 0, shape[0], 4, 10))
				self.widgets[dim]['wavelenght'].set_adjustment(gtk.Adjustment(shape[0], 5, shape[0]*3, 4, 10))
#				print "reset"

		for dim in DIMS:
			useful = not (dim > self.dim)
			for widget in self.widgets[dim]:
				self.widgets[dim][widget].set_sensitive(useful)

		self.widgets[rules_hbox].set_sensitive(bool(self.dim-1))

		#If dimension is changing with this editor call, we cannot add
		self.add_check.set_sensitive(old_points.shape == shape)
#			print "reset"


		
		self.points = points.Points(self.shape, None, 'flat', None, drawers.Drawer(self.xml.get_object('editor drawing'), self.xml.get_object('editor combo drawer')))
#		print "reconfigure"

		gobject.timeout_add(10, self.update)

		resp = self.window.run()
		while True:
			self.response(None, resp)
			if resp == 2:
				resp = self.window.run()
			else:
				break


	def update(self, arg=None, arg2=None, arg3=None):
#		print arg, arg2, arg3
		if arg in self.widgets[rules]:		#The radiobuttons always send 2 signals: one for the toggled and one for the untoggled
			if self.skipped_one:
				self.skipped_one = False
			else:
				self.skipped_one = True
				return

		params = []
		for dim in range(1, self.dim+1):
			selected_iter = self.widgets[dim]['waveform'].get_active_iter()
			liststore = self.widgets[dim]['waveform'].get_model()
			params=params + [liststore.get(selected_iter, 1)[0]]
			params_dim = [self.widgets[dim][widget].get_value() for widget in param_names]
#			print params_dim
			for index in range(len(int_params)):
				params_dim[index]=int(params_dim[index])

			params = params + params_dim

		#Get selected rule:
		params.append(rule_names[ [rule.get_active() for rule in self.widgets[rules]].index(True)]) #FIXME (ugly)
#		print params
		self.new_disp = dispositions.waveformer[self.dim](self.shape, *params)


		if self.dim == 1:
			if self.widgets[1][reflect].get_active():
				self.new_disp = reflect_matrix(self.new_disp)
		else:
			if self.widgets[2][reflect].get_active():
				self.new_disp = reflect_matrix(self.new_disp)
			if self.widgets[1][reflect].get_active():
				self.new_disp = reflect_matrix(self.new_disp.transpose()).transpose()


		if self.invert_check.get_active():
			self.new_disp = self.new_disp * -1
		if self.add_check.get_active():
			self.points.reconfigure(pos = self.old_points.pos + self.new_disp)
		else:
			self.points.reconfigure(pos = self.new_disp)
		self.ready = True
#		self.draw()


	def set_defaults(self):
		defaults = [self.shape[0], 0, self.shape[0], 0, 1, .5]

		for dim in range(1, self.dim+1):
			self.widgets[dim]['waveform'].set_active(0)
			for index in range(len(param_names)):
				self.widgets[dim][param_names[index]].set_value(defaults[index])
			self.widgets[dim][reflect].set_active(False)

		self.widgets[rules][0].set_active(True)
		self.invert_check.set_active(False)
		self.add_check.set_active(False)
		self.update()


	def response(self, button, response):
		if response == 2:
			self.set_defaults()
			return

		if response == 1:
			self.caller.editor_save(self.points)

		self.window.hide()
