# GVB - a GTK+/GNOME vibrations simulator
#
# Copyright © 2008-2013 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

from gi.repository import Gtk
from gi.repository 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))

            self.combo_model=Gtk.ListStore(str,str)
            for waveform in dispositions.waveforms:

                self.combo_model.append([_(waveform), waveform])
            self.widgets[dim]['waveform'].set_model(self.combo_model)
            self.widgets[dim]['waveform'].set_active(0)

            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 isinstance(self.widgets[dim][widget], Gtk.ComboBox):
                    self.widgets[dim][widget].connect('changed', self.update)
                elif isinstance(self.widgets[dim][widget], Gtk.CheckButton):
                    self.widgets[dim][widget].connect('toggled', self.update)
                elif isinstance(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):            

        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]:
                try:
                    size = shape[dim-1]
                except IndexError:
                    size = shape[0]
                print("dim", dim, "size", size)
                #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(size, 3, size, 4, 10))
                self.widgets[dim]['shift'].set_adjustment(Gtk.Adjustment(0, 0, size, 4, 10))
                self.widgets[dim]['wavelenght'].set_adjustment(Gtk.Adjustment(size, 5, size*3, 4, 10))

        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)
        
        self.points = points.Points(self.shape, None, 'flat', None, drawers.Drawer(self.xml.get_object('editor drawing'), self.xml.get_object('editor combo drawer')))

        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):
        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]
            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)
        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.points.drawer.invalidate()


    def set_defaults(self):
        defaults = [self.shape[0], 0, self.shape[1], 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()
