# -*- coding: utf-8 -*-
#Copyright (c) 2009, 2011 Walter Bender

# 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.
#
# You should have received a copy of the GNU General Public License
# along with this library; if not, write to the Free Software
# Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA


from constants import *
from time import *
import pygtk
pygtk.require('2.0')
import gtk
import gobject
from sound import playWave, audioWrite
import os
import random
from gettext import gettext as _

try:
    from sugar.graphics import style
    GRID_CELL_SIZE = style.GRID_CELL_SIZE
except:
    GRID_CELL_SIZE = 0

from sprites import Sprites
from sprite_factory import Sprite

class swWindow: pass

#
# handle launch from both within and without of Sugar environment 
#
def new_window(canvas, path, parent=None):
    sw = swWindow()
    sw.path = path
    sw.activity = parent

    # starting from command line
    # we have to do all the work that was done in CardSortActivity.py
    if parent is None:
        sw.sugar = False
        sw.canvas = canvas

    # starting from Sugar
    else:
        sw.sugar = True
        sw.canvas = canvas
        parent.show_all()

    sw.canvas.set_flags(gtk.CAN_FOCUS)
    sw.canvas.add_events(gtk.gdk.BUTTON_PRESS_MASK)
    sw.canvas.add_events(gtk.gdk.BUTTON_RELEASE_MASK)
    sw.canvas.add_events(gtk.gdk.POINTER_MOTION_MASK)
    sw.canvas.connect("expose-event", _expose_cb, sw)
    sw.canvas.connect("button-press-event", _button_press_cb, sw)
    sw.canvas.connect("button-release-event", _button_release_cb, sw)
    sw.canvas.connect("motion-notify-event", _mouse_move_cb, sw)
    sw.width = gtk.gdk.screen_width()
    sw.height = gtk.gdk.screen_height()-GRID_CELL_SIZE
    sw.sprites = Sprites(sw.canvas)
    sw.sound = True
    sw.scale = 2
    sw.level = 1
    sw.seq = gen_seq(40)
    sw.counter = 0
    sw.playpushed = False

    # Open the buttons
    d = W/4 # position fudge factor
    sw.buttons_off = [Sprite(sw,"Aoff",sw.width/2-W/2,H/2-d,W/2,H/2),\
                      Sprite(sw,"Boff",sw.width/2-W-d,H,W/2,H/2),\
                      Sprite(sw,"Doff",sw.width/2+d,H,W/2,H/2),\
                      Sprite(sw,"Coff",sw.width/2-W/2,H+H/2+d,W/2,H/2)]
    sw.buttons_on  = [Sprite(sw,"Aon",sw.width/2-W/2,H/2-d,W/2,H/2),\
                      Sprite(sw,"Bon",sw.width/2-W-d,H,W/2,H/2),\
                      Sprite(sw,"Don",sw.width/2+d,H,W/2,H/2),\
                      Sprite(sw,"Con",sw.width/2-W/2,H+H/2+d,W/2,H/2)]
    sw.sounds = ['dog','sheep','cat','bird']
    sw.sound_files = []

    # Save sounds for repeated play
    for i in sw.sounds:
        playWave(i)
        path = sw.activity.get_activity_root() + "/instance/" + i + ".csd"
        sw.sound_files.append(path)
        audioWrite(path)

    _all_off(sw)

    # Start calculating
    sw.press = None
    sw.dragpos = 0
    return sw

#
# Play the sample sequence for the current level
#
def play_the_game(sw):
    sw.playpushed = True
    for i in sw.buttons_on:
        i.spr.hide()
    _stepper(sw,0,False)
    sw.counter = 0

#
# Display next graphic/play next sound in sequence
# Loop through twice: once to display the tile and once to pause between tiles
#
def _stepper(sw,i,j):
     if i > 0:
         sw.buttons_on[sw.seq[i-1]].spr.hide()
     if j is True:
         if i < sw.level*2:
             sw.buttons_on[sw.seq[i]].draw_sprite(1500)
             gobject.idle_add(__play_sound_cb, 
                              sw.sound_files[sw.seq[i]], sw.sound)
             sw.timeout_id = gobject.timeout_add(1000,_stepper,sw,i+1,False)
         else:
             _dance(sw,[0,1,2,3],1,0)
     else:
         sw.timeout_id = gobject.timeout_add(1000,_stepper,sw,i,True)

#
# Button press
#
def _button_press_cb(win, event, sw):
    win.grab_focus()
    x, y = map(int, event.get_coords())
    sw.dragpos = x
    spr = sw.sprites.find_sprite((x,y))
    sw.press = spr
    return True

#
# Mouse move
#
def _mouse_move_cb(win, event, sw):
    if sw.press is None:
        sw.dragpos = 0
        return True

    win.grab_focus()
    x, y = map(int, event.get_coords())

    dx = x-sw.dragpos

    # reset drag position
    sw.dragpos = x

#
# Play the csound associated with the button
#
def __play_sound_cb(sound, flag):
    if flag is True:
        # os.system('csound ' + sound + '/temp.csd >/dev/null 2>/dev/null')
        os.system('csound ' + sound)

#
# Button release -- where the work happens
#
def _button_release_cb(win, event, sw):
    if sw.press == None:
        return True
    for i in range (0,4):
        if sw.press == sw.buttons_off[i].spr:
            sw.buttons_on[i].draw_sprite(1500)
            gobject.idle_add(__play_sound_cb, sw.sound_files[i], sw.sound)
            gobject.timeout_add(500,sw.buttons_on[i].spr.hide)
            if sw.playpushed is False:
                sw.press = None
                return
            if sw.seq[sw.counter] == i: # correct reponse
                sw.counter += 1
                if sw.counter == sw.level*2:
                    gobject.timeout_add(1000, _dance, sw, [i], 10, 0)
                    sw.counter = 0
                    sw.level += 1
                    sw.activity.level_label.set_text(
                        "%s %d" % (_("Level"),sw.level))
                    if sw.level*2 < len(sw.seq):
                        gobject.timeout_add(3000, play_the_game, sw)
                    else: # game over
                        gobject.timeout_add(2000, _flash, sw, 7, True)
                        sw.playpushed = False
                        sw.level = 1
                        sw.seq = gen_seq(30)
                        sw.activity.level_label.set_text(
                            "%s %d" % (_("Level"),sw.level))
            else: # incorrect response
                _all_gone(sw)
                gobject.timeout_add(1000, _all_off, sw)
                sw.counter = 0
    sw.press = None

#
# Turn all the sprites bright
#
def _all_on(sw):
    for i in sw.buttons_off:
        i.draw_sprite(1000)
    for i in sw.buttons_on:
        i.draw_sprite(1500)

#
# Do a little dance
#
def _dance(sw, dancelist, dist, n):
    xo = [0,-dist,dist,0]
    yo = [-dist,0,0,dist]
    if n < 10:
        for i in dancelist:
            sw.buttons_off[i].spr.move_relative((xo[i],yo[i]))
        gobject.timeout_add(30,_dance,sw,dancelist,dist,n+1)
    else:
        for i in dancelist:
            sw.buttons_off[i].spr.move_relative((-xo[i]*10,-yo[i]*10))

#
# Flash
#
def _flash(sw, n, i):
    if n == 0:
        _all_off(sw)
        return
    if i is True:
        _all_on(sw)
        gobject.timeout_add(200,_flash,sw,n-1,False)
    else:
        _all_off(sw)
        gobject.timeout_add(200,_flash,sw,n,True)

#
# Turn all the sprites dim
#
def _all_off(sw):
    for i in sw.buttons_off:
        i.draw_sprite(1000)
    for i in sw.buttons_on:
        i.spr.hide()

#
# Hide all the sprites
#
def _all_gone(sw):
    for i in sw.buttons_off:
        i.spr.hide()
    for i in sw.buttons_on:
        i.spr.hide()

#
# Window expose event
#
def _expose_cb(sw, win, event):
    ''' Callback to handle window expose events '''
    sw.do_expose_event(event)
    return True

def do_expose_event(sw, event):
    ''' Handle the expose-event by drawing '''
    # Restrict Cairo to the exposed area
    cr = sw.canvas.window.cairo_create()
    cr.rectangle(event.area.x, event.area.y,
                 event.area.width, event.area.height)
    cr.clip()
    # Refresh sprite list
    sw.sprites.redraw_sprites(cr=cr)

#
# Shut it down
#
def _destroy_cb(win, event, sw):
    gtk.main_quit()

#
# Generate the sample sequences
#
def gen_seq(n):
    seq = []
    for i in range(1,n+1):
        seq.append(int(random.uniform(0,4)))
    print seq
    return seq
