#  gcompris - BarGame
#
#
#
# Copyright (C) 2004  Yves Combe
#
#   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, see <http://www.gnu.org/licenses/>.
#
import gnomecanvas
import gcompris
import gcompris.utils
import gcompris.bonus
import gcompris.skin
import pygtk
import gtk
import gtk.gdk
import random
import math

backgrounds = [ 'opt/school_bg1.jpg',
                'opt/school_bg2.jpg',
                'opt/school_bg3.jpg',
                'opt/school_bg4.jpg'
                ]

profs = [ 'images/tux.png',
          'images/tux_teen.png',
          'images/tux_graduate.png',
          'images/tux_albert.png'
          ]

class Gcompris_bargame:
  """The Bar Game"""

  def __init__(self, gcomprisBoard):
    random.seed()
    self.gcomprisBoard = gcomprisBoard
    self.rootitem = None

    # To display the bonus, we need to pause the board.
    self.board_paused  = 0
    self.number_balls = [[1,4],[2,6],[3,6]]
    self.board_size = [15,19,29]
    self.gcomprisBoard.level=1
    self.gcomprisBoard.maxlevel=4
    self.gcomprisBoard.sublevel=1
    self.gcomprisBoard.number_of_sublevel=3

    # global scale depending on the level
    self.scales = [0.208, 0.164, 0.107]

    self.holes = []
    self.balls = []
    self.list_win = []
    self.profbutton = []
    self.answer = []

    self.pixmap_blue_ball  = gcompris.utils.load_pixmap("bargame/blue_ball.png")
    self.pixmap_green_ball = gcompris.utils.load_pixmap("bargame/green_ball.png")
    self.pixmap_case       = gcompris.utils.load_pixmap("bargame/case.png")
    self.pixmap_case_last  = gcompris.utils.load_pixmap("bargame/case_last.png")
    self.pixmap_ombre      = gcompris.utils.load_pixmap("bargame/ombre.png")
    self.pixmap_mask       = gcompris.utils.load_pixmap("bargame/mask.png")
    self.pixmap_mask_last  = gcompris.utils.load_pixmap("bargame/mask_last.png")

  def start(self):
    # load pixmaps for the ui.
    #
    pixmap = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("button_reload.png"))
    if(pixmap):
      gcompris.bar_set_repeat_icon(pixmap)
      gcompris.bar_set(gcompris.BAR_LEVEL|gcompris.BAR_OK|gcompris.BAR_REPEAT_ICON)
    else:
      gcompris.bar_set(gcompris.BAR_LEVEL|gcompris.BAR_OK|gcompris.BAR_REPEAT)
    gcompris.bar_set_level(self.gcomprisBoard)

    # Create persistent over levels root item canvas for the board
    self.rootitem_p = self.gcomprisBoard.canvas.root().add(
      gnomecanvas.CanvasGroup,
      x=0,
      y=0
      )

    self.profbutton = self.prof_button(self,
                                       self.rootitem_p,
                                       profs[self.gcomprisBoard.level - 1])

    self.answer = self.answer_button(self.rootitem_p,
                                     self.scales[self.gcomprisBoard.sublevel-1],
                                     self.pixmap_green_ball,
                                     self.number_balls[self.gcomprisBoard.sublevel-1])

    #
    self.newGame()

  def end(self):
    self.cleanup()

    del self.profbutton
    self.profbutton = []

    del self.answer
    self.answer = []

    if self.rootitem_p:
      self.rootitem_p.destroy()


  def set_level(self,level):
    self.gcomprisBoard.level = level
    self.gcomprisBoard.sublevel = 1
    gcompris.bar_set_level(self.gcomprisBoard)

    self.newGame()
    pass

  def ok(self):
    self.answer.has_focus()
    self.play(self.answer.value,True)
    pass

  def key_press(self, keyval, commit_str, preedit_str):
    return False

  def repeat(self):
    self.newGame()

  def pause(self, pause):
    self.board_paused = pause

    # When the bonus is displayed, it call us first with pause(1) and then with pause(0)
    # the game is won
    if ((pause == 0) and self.finished_sublevel):
      self.set_sublevel(self.gcomprisBoard.sublevel+1)
      return 0


  #-------------------------------------------------
  #-------------------------------------------------
  #-------------------------------------------------

  def set_sublevel(self, sublevel):
    #sublevel change only in game_won
    if sublevel > self.gcomprisBoard.number_of_sublevel:
      if self.game_won:
        if self.gcomprisBoard.level == self.gcomprisBoard.maxlevel:
          gcompris.bonus.board_finished(gcompris.bonus.FINISHED_RANDOM)
          return 0
        else:
          self.set_level(self.gcomprisBoard.level+1)
      else:
        self.gcomprisBoard.sublevel = 1
        self.newGame()
    else:
      self.gcomprisBoard.sublevel = sublevel
      self.newGame()


  def calculate_win_places(self):
    winners = []

    min = self.number_balls[self.gcomprisBoard.sublevel-1][0]
    max = self.number_balls[self.gcomprisBoard.sublevel-1][1]
    period = (min + max)

    winners_list = [(self.board_size[self.gcomprisBoard.sublevel-1] -1 -x)% period for x in range(min)]
    for i in range(self.board_size[self.gcomprisBoard.sublevel-1]):
      if ((i+1) % period) in  winners_list:
        winners.append(i)

    level_win = (self.gcomprisBoard.level -1) * min

    if level_win == 0:
      winners = []
    else:
      winners = winners[-level_win:]

    return winners

  # Remove uneeded objects
  def cleanup(self):
    if self.rootitem:
      self.rootitem.destroy()

    # Holes reinit
    for h in self.holes:
      del h

    del self.holes
    self.holes = []

    # Balls reinit
    for h in self.balls:
      del h

    del self.balls
    self.balls = []


    # Other variable cleanup
    del self.list_win
    self.list_win = []

  def newGame(self):
    self.cleanup()

    width_ref = 256

    scale = self.scales[self.gcomprisBoard.sublevel-1]

    self.last_played = -1
    self.finished_sublevel = False
    self.game_won = False
    self.list_win = self.calculate_win_places()


    # Create root item canvas for the board
    self.rootitem = self.gcomprisBoard.canvas.root().add(
      gnomecanvas.CanvasGroup,
      x=0,
      y=0
      )

    # background
    gcompris.set_background(self.gcomprisBoard.canvas.root(),
                            backgrounds[self.gcomprisBoard.level - 1])

    self.profbutton.set_prof(profs[self.gcomprisBoard.level - 1])

    for i in range(self.board_size[self.gcomprisBoard.sublevel-1]):
      self.holes.append(self.hole(self,
                                  self.rootitem,
                                  i * width_ref * scale,
                                  gcompris.BOARD_HEIGHT - 120, i,
                                  self.board_size[self.gcomprisBoard.sublevel-1],
                                  scale))

    for i in range(self.number_balls[self.gcomprisBoard.sublevel-1][1]):
      self.balls.append(self.ball(self.rootitem,
                                  i * width_ref * scale + 150,
                                  gcompris.BOARD_HEIGHT - 160,
                                  scale,
                                  self.pixmap_blue_ball))
      self.balls.append(self.ball(self.rootitem,
                                  i * width_ref * scale +150,
                                  gcompris.BOARD_HEIGHT-70,
                                  scale,
                                  self.pixmap_green_ball))

    self.answer.set_number_of_balls(self.number_balls[self.gcomprisBoard.sublevel-1])


  def play(self, value, human):
    for i in range(1,value+1):
      self.last_played += 1
      if human:
        self.holes[self.last_played].isGreen()
      else:
        self.holes[self.last_played].isBlue()

      if self.last_played == self.board_size[self.gcomprisBoard.sublevel-1] - 1 :
        self.gamelost(human)
        return

    if human:
      self.machine_play()


  def machine_play(self):

    def accessible(x):
      if ((x + self.last_played) in self.list_win):
        return True
      return False

    playable = filter(accessible,
                      range(self.number_balls[self.gcomprisBoard.sublevel-1][0],
                            self.number_balls[self.gcomprisBoard.sublevel-1][1]+1))

    if playable != []:
      self.play(random.choice(playable),False)
    else:
      self.play(random.choice(range(self.number_balls[self.gcomprisBoard.sublevel-1][0],
                                    self.number_balls[self.gcomprisBoard.sublevel-1][1]+1)),
                False)

    self.answer.new_value(self.number_balls[self.gcomprisBoard.sublevel-1][0])

  def gamelost(self,human):
    self.finished_sublevel = True
    if human:
      gcompris.bonus.display(gcompris.bonus.LOOSE, gcompris.bonus.GNU)
    else:
      self.game_won = True
      gcompris.bonus.display(gcompris.bonus.WIN, gcompris.bonus.GNU)


  class hole:
    def __init__(self, board, root, x, y, index,
                 board_size,
                 scale):
      self.board = board

      self.itemgroup = root.add(
        gnomecanvas.CanvasGroup,
        x=x,
        y=y)

      self.scale = scale

      if (index == (board_size-1)):
        pixbuf_case = self.board.pixmap_case_last
        pixbuf_mask = self.board.pixmap_mask_last
      else:
        pixbuf_case = self.board.pixmap_case
        pixbuf_mask = self.board.pixmap_mask


      item = self.itemgroup.add(
        gnomecanvas.CanvasPixbuf,
        pixbuf = pixbuf_case,
        x=0,
        y=0)
      bounds = item.get_bounds()
      item.set(width  = (bounds[2]-bounds[0])*scale,
               height = (bounds[3]-bounds[1])*scale,
               width_set  = True,
               height_set = True)

      self.ombre = self.itemgroup.add(
        gnomecanvas.CanvasPixbuf,
        pixbuf = self.board.pixmap_ombre,
        x=0,
        y=0)
      self.ombre.hide()
      bounds = self.ombre.get_bounds()
      self.ombre.set(width  = (bounds[2]-bounds[0])*scale,
                     height = (bounds[3]-bounds[1])*scale,
                     width_set  = True,
                     height_set = True)

      self.ball = self.itemgroup.add(
        gnomecanvas.CanvasPixbuf,
        x=0,
        y=0)
      self.ball.hide()

      item = self.itemgroup.add(
        gnomecanvas.CanvasPixbuf,
        pixbuf = pixbuf_mask,
        x=0,
        y=0)
      bounds = item.get_bounds()
      item.set(width  = (bounds[2]-bounds[0])*scale,
               height = (bounds[3]-bounds[1])*scale,
               width_set  = True,
               height_set = True)

      if ((index+1)%5 == 0):
        self.itemgroup.add(
          gnomecanvas.CanvasText,
          x=(bounds[2]-bounds[0])/2,
          y=-10,
          fill_color_rgba=0x000000ffL,
          font=gcompris.skin.get_font("gcompris/board/small bold"),
          anchor=gtk.ANCHOR_CENTER,
          text = index + 1)


    def isBlue(self):
      self.ball.set(pixbuf = self.board.pixmap_blue_ball)
      bounds = self.ball.get_bounds()
      self.ball.set(width  = (bounds[2]-bounds[0])*self.scale,
                    height = (bounds[3]-bounds[1])*self.scale,
                    width_set  = True,
                    height_set = True)
      self.ball.show()
      self.ombre.show()

    def isGreen(self):
      self.ball.set(pixbuf = self.board.pixmap_green_ball)
      bounds = self.ball.get_bounds()
      self.ball.set(width  = (bounds[2]-bounds[0])*self.scale,
                    height = (bounds[3]-bounds[1])*self.scale,
                    width_set  = True,
                    height_set = True)
      self.ball.show()
      self.ombre.show()


  class ball:
    def __init__(self, root, x, y, scale, image):

      self.ball = root.add(
        gnomecanvas.CanvasPixbuf,
        pixbuf = image,
        x=x,
        y=y)
      bounds = self.ball.get_bounds()
      self.ball.set(width  = (bounds[2]-bounds[0])*scale,
                    height = (bounds[3]-bounds[1])*scale,
                    width_set  = True,
                    height_set = True)

  class answer_button:
    def __init__(self, root, scale, image, number_balls):
      self.focus = False

      self.number_balls = number_balls

      self.itemgroup = root.add(
        gnomecanvas.CanvasGroup,
        x = gcompris.BOARD_WIDTH - 200,
        )

      self.background = self.itemgroup.add(
        gnomecanvas.CanvasPixbuf,
        pixbuf = gcompris.utils.load_pixmap("images/enumerate_answer.png"),
        x=0,
        y=0
        )
      answer_bounds = self.background.get_bounds()

      self.itemgroup.set( y = gcompris.BOARD_HEIGHT - answer_bounds[3]-answer_bounds[1] - 5)

      self.background_focused = self.itemgroup.add(
        gnomecanvas.CanvasPixbuf,
        pixbuf = gcompris.utils.load_pixmap("images/enumerate_answer_focus.png"),
        x=0,
        y=0
        )
      self.background_focused.hide()

      self.icone = self.itemgroup.add(
        gnomecanvas.CanvasPixbuf,
        pixbuf = image,
        x=10,
        y=20
        )
      bounds = self.icone.get_bounds()
      self.icone.set(width  = (bounds[2]-bounds[0])*scale,
                     height = (bounds[3]-bounds[1])*scale,
                     width_set  = True,
                     height_set = True)

      self.value = number_balls[0]

      self.text = self.itemgroup.add(
        gnomecanvas.CanvasText,
        x = answer_bounds[2]-answer_bounds[0] - 50,
        y = 40,
        fill_color_rgba=0xff0000ffL,
        font=gcompris.skin.get_font("gcompris/board/huge bold"),
        anchor=gtk.ANCHOR_CENTER,
        text = self.value
        )

      self.background.connect("event",self.answer_event)
      self.background_focused.connect("event",self.answer_event)
      self.icone.connect("event",self.answer_event)
      self.text.connect("event",self.answer_event)


    def new_value(self, value):
      self.value = value
      self.text.set_property('text',value)

    def has_focus(self):
      self.background_focused.show()
      self.focus = True

    def set_number_of_balls(self, number_balls):
      self.number_balls = number_balls
      self.new_value(1)

    def answer_event(self, item, event):
      if ((event.type != gtk.gdk.BUTTON_PRESS) or
          (event.button != 1)):
        return False

      self.has_focus()

      value = ( (self.value
                 + 1
                 - self.number_balls[0])
                % (self.number_balls[1]
                   + 1
                   - self.number_balls[0])
                + self.number_balls[0]
                )
      self.new_value(value)

      return True

  class prof_button:
    def __init__(self, board, root, prof_image):
      self.board = board

      self.prof_item = root.add(
        gnomecanvas.CanvasPixbuf,
        y = 230
        )
      bounds = self.prof_item.get_bounds()
      self.prof_item.set(x  = ((gcompris.BOARD_WIDTH - bounds[2]-bounds[0])/2 - 90))

      self.prof_item.connect("event",self.event_play)
      # This item is clickeable and it must be seen
      self.prof_item.connect("event", gcompris.utils.item_event_focus)

    def set_prof(self, prof_image):
      self.prof_item.set(pixbuf = gcompris.utils.load_pixmap(prof_image))

    def event_play(self, item, event):
      if ((event.type != gtk.gdk.BUTTON_PRESS) or
          (event.button != 1)):
        return False

      # if answer button has been clicked, that play the human turn
      if self.board.last_played == -1 :
        self.board.machine_play()
        return True

      return False

