# 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

#Give startup dispositions of the points

from scipy import array, zeros, sin, cos, pi, concatenate, ones, prod, sqrt
from scipy.linalg import norm

from .gvbi18n import _

def disposition(shape, type_descriptor):
    if len(shape) in dispositions and type_descriptor in dispositions[len(shape)]:
        return dispositions_dict[len(shape)][type_descriptor](shape)
    else:
        print("type not found:", type_descriptor)
        return zeros(shape)

waveforms_dict = {    #hl=half wave lenght, cen=centering (from 0 to 1), x is between 1 (not 0) and wl-1
    'square': (lambda hl, ce, t: 1)
    ,
    'triangular': (lambda hl, ce, t: min(t/ce, (hl-t)/(1-ce))/hl )
    ,
    'sinusoidal': (lambda hl, ce, t: sin(min(t/(2*ce), (hl-t)/(2*(1-ce))) * pi/hl) )
    ,
    'peak': (lambda hl, ce, t: max((abs(hl*ce-t),0),(.5,1))[1] )
                }

waveforms = ['sinusoidal', 'triangular', 'square', 'peak']


def waveformer_1d(shape, waveform, lenght, shift, wavelenght, fase_angle, height, centering, rule = None):
    n = shape[0]
    singlewave = array([waveforms_dict[waveform](wavelenght//2+1, centering, t)  for t in range (1,int(wavelenght//2)+1)])
    doublewave = concatenate([singlewave, zeros(1), -1*singlewave])*height

    fase = wavelenght * fase_angle/360
    calculated = doublewave
    while len(calculated) < lenght+fase:
        calculated = concatenate([calculated, array([0]), doublewave])

    calculated = calculated[fase:lenght+fase]

    wave_clip = lenght - max(0, shift + lenght - n)

    zeros_before = shift-(lenght-wave_clip)
    zeros_after = n - (shift + wave_clip)

    wave_final = concatenate([ calculated[wave_clip:], zeros(zeros_before), calculated[:wave_clip], zeros(zeros_after) ])
    return wave_final

def waveformer_2d(shape, *args):
    n1, n2 = shape
    wave1 = waveformer_1d((n1,), *args[:7])
    wave2 = waveformer_1d((n2,), *args[7:14])

    rules = {'sum' : sum, 'prod' : prod, 'max' : max, 'min': min}

    rule = rules[args[14]]

    #FIXME: really not efficient... should someway use scipy.
    wave_final = array( [[rule([wave2[i], wave1[j]]) for i in range(n2)] for j in range(n1)] )

    return wave_final

waveformer = {1: waveformer_1d, 2: waveformer_2d}


dispositions_1d={    #Dispositions are created combining waveformers and/or other dispositions
    'flat': zeros
    ,
#    'sin': (lambda (n,): array([sin(t*pi*2/(n+1)) for t in range(1,n+1)]))
    'sin': (lambda s: waveformer_1d(s, 'sinusoidal', s[0], 0, s[0], 0, 1, .5 ) )
    ,
#    'half sin': (lambda (n,): array([sin(t*pi/(n+1)) for t in range(1,n+1)]))
    'half sin': (lambda s: waveformer_1d(s, 'sinusoidal', s[0], 0, 2*s[0], 0, 1, .5 ) )
    ,
#    'picked': (lambda (n,): array([float(2*min(t, n-t+1))/n for t in range(1,n+1) ]))
    'picked': (lambda s: waveformer_1d(s, 'triangular', s[0], 0, 2*s[0], 0, 1, .5 ) )
    ,
    'triangular signal': (lambda s: concatenate([ disposition((s[0]//4,), 'picked'), disposition((s[0]-s[0]//4,), 'flat') ]))
    ,
    'sinusoidal signal': (lambda s: concatenate([ disposition((s[0]//4,), 'sin'), disposition((s[0]-s[0]//4,), 'flat') ]))
    ,
#    'picked lateral':  (lambda (n,): array([float(min(float(2*t)/n, float(n-t+1)/n)) for t in range(1,n+1) ]))
    'picked lateral': (lambda s: waveformer_1d(s, 'triangular', s[0], 0, 2*s[0], 0, 1, .25 ) )
    ,
    'opposite triangulars': (lambda s: concatenate([ disposition((s[0]//4,), 'picked'), disposition((s[0]-s[0]//4-s[0]//4,), 'flat'), disposition((s[0]//4,), 'picked') ]))
    ,
    'opposite sinusoidals': (lambda s: concatenate([ disposition((s[0]//4,), 'sin'), disposition((s[0]-s[0]//4-s[0]//4,), 'flat'), disposition((s[0]//4,), 'sin') ]))
    ,
    'square': ones
    ,
    'square signal': (lambda s: concatenate([ disposition((s[0]//4,), 'square'), disposition((s[0]-s[0]//4,), 'flat') ]))
    ,
#    'discontinuous peak': (lambda (n,): concatenate([ disposition((n/2,), 'flat'), [1], disposition((n-n/2-1,), 'flat') ]))
    'discontinuous peak': (lambda s: waveformer_1d(s, 'peak', s[0], 0, 2*s[0], 0, 1, .5 ) )
    ,
    'cos (shifted)': (lambda s: waveformer_1d(s, 'sinusoidal', s[0], 0, s[0], 270, 1, .5) + ones(s) )
                }


dispositions_2d={
    'flat': zeros
    ,
#    'picked': (lambda (n,m): array([array([float(2*min(t, m-t+1))/n for t in range(1,m+1) ])*float(2*min(j, n-j+1))/n for j in range(1,n+1)]))
    'picked': (lambda s: waveformer_2d(s, 'triangular', s[0], 0, 2*s[0], 0, 1, .5, 'triangular', s[1], 0, 2*s[1], 0, 1, .5 , 'prod' ) )
    ,
    'sin': (lambda s: waveformer_2d(s, 'sinusoidal', s[0], 0, s[0], 0, 1, .5, 'sinusoidal', s[1], 0, s[1], 0, 1, .5 , 'prod' ) )
    ,
    'half sin': (lambda s: waveformer_2d(s, 'sinusoidal', s[0], 0, 2*s[0], 0, 1, .5, 'sinusoidal', s[1], 0, 2*s[1], 0, 1, .5 , 'prod' ) )
    ,
    'pond': (lambda s: array([[(lambda x,y,r : -.1*cos(10*pi*norm([x,y])/r) * max(1-norm([x,y])/r, 0) ) (i-s[1]/2, j-s[0]/2, min(*s))/2 for i in range(1,s[1]+1) ] for j in range(1,s[0]+1)]))
    ,
    'waterfall': (lambda s: array([[(lambda x,y : 1 if norm([x,y]) < min(*s)/10 else 0)(i-s[1]/2, j-s[0]/2) for i in range(1,s[1]+1) ] for j in range(1,s[0]+1)]))
    ,
    'gut': (lambda s: array([[(lambda x,y,r : -1-cos(8*pi*norm([x,y])/r) if norm([x,y]) < r/8 else 0) (i-s[1]/2, j-s[0]/2, min(*s)) for i in range(1,s[1]+1) ] for j in range(1,s[0]+1)]))
                }

dispositions_dict={1:dispositions_1d, 2:dispositions_2d}

dispositions={}


for dim in [1,2]:
    keys = list(dispositions_dict[dim].keys())
    keys.sort()
    dispositions[dim]=keys






dummy_list_for_gettext=[_('flat'),    _('sin'), _('half sin'), _('picked'), _('triangular signal'), _('sinusoidal signal'), _('picked lateral'), _('opposite triangulars'), _('picked'), _('opposite sinusoidals'), _('square'), _('square signal'), _('discontinuous peak'), _('cos (shifted)'), _('pond'), _('waterfall'), _('gut'), _('peak'), _('sinusoidal') ]
