# Balazar
# Copyright (C) 2002-2003 Bertrand LAMY, Jean-Baptiste LAMY
#
# 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 2 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

# This file contain these classes :
#  - MainMenu
#  - MainMenuIdler
#  - Rectangle
#  - MsgWindow
#  - ConfigKey

import sys, os, os.path, random, math

import soya, soya.opengl  as soyaopengl
import soya.sdlconst      as soyasdlconst
import soya.widget        as widget
import balazar
import balazar.globdef    as globdef
from balazar.controller   import CONTROLS

COLOR     = (0.0, 0.0, 0.0, 1.0)
HIGHLIGHT = (0.0, 0.0, 1.0, 1.0)

def filter_string(s):
  return s.replace("\r", "").replace("\n", "")

class Rectangle(soya.widget.Widget):
  def __init__(self, master = None, color = (1.0, 1.0, 1.0, 0.8)):
    soya.widget.Widget.__init__(self, master)
    self.color = color
    self.visible = 1
    
  def render(self):
    if self.visible:
      if self.color[3] < 1.0: soyaopengl.glEnable(soyaopengl.GL_BLEND)
      soyaopengl.glColor4f (*self.color)
      soyaopengl.glBegin   (soyaopengl.GL_QUADS)
      soyaopengl.glVertex2f(self.left, self.top)
      soyaopengl.glVertex2f(self.left, self.top + self.height)
      soyaopengl.glVertex2f(self.left + self.width, self.top + self.height)
      soyaopengl.glVertex2f(self.left + self.width, self.top)
      soyaopengl.glEnd()
      if self.color[3] < 1.0: soyaopengl.glDisable(soyaopengl.GL_BLEND)


class MainMenuIdler(soya.Idler):
  def __init__ (self, mainmenu):
    soya.Idler.__init__ (self)
    self.mainmenu = mainmenu
    self.step     = 0
    
  def begin_round(self):
    soya.Idler.begin_round(self)
    if self.step == 0:
      for event in soya.process_event():
        if (event[0] == soyasdlconst.JOYBUTTONDOWN) or (event[0] == soyasdlconst.KEYDOWN and event[1]) or (event[0] == soyasdlconst.MOUSEBUTTONDOWN):
          self.mainmenu.set_current_menu(self.mainmenu.game_menu_1)
          self.mainmenu.bg_rect.visible = 1
          self.step = 1
          break
    elif self.mainmenu.current_menu:
      for event in soya.process_event(): self.mainmenu.current_menu.process_event(event)


class MainMenu:
  def __init__(self):
    self.current_menu = None
    self.old_menus = []
    
    self.root = widget.Group()

    self.bg_img = soya.widget.Image(self.root, soya.Material.get('splash'))
    self.bg_img.resize_style  = ('maximize', ('keep ratio', 1024 / 768.0), 'center x', 'center y')
    self.bg_img.resize_style  = ('maximize', 'center x', 'center y')
    self.bg_rect = Rectangle(self.root)
    self.bg_rect.resize_style = ('maximize', ('percent top', 0.4), 'maximize height', ('margin bottom', 20), ('margin left', 20), ('margin right', 20))
    self.bg_rect.visible = 0
    
    self.scene = soya.World()
    
    self.atm = soya.NoBackgroundAtmosphere()
    self.atm.ambient  = (0.2, 0.2, 0.2, 1.0)
    self.scene.atmosphere = self.atm
    
    CHOICELIST_RESIZE_STYLE = ('maximize', ('percent top', 0.4), 'maximize height', ('margin bottom', 20))
    self.game_menu_1 = soya.widget.ChoiceList(self.root, [
      soya.widget.Choice(_('Play solo game'       ), self.show_solo),
      soya.widget.Choice(_('Play multiplayer game'), self.show_multi),
      soya.widget.Choice(_('Hardware options'     ), self.show_h_option),
      soya.widget.Choice(_('Keyboard options'     ), self.show_key_option),
      soya.widget.Choice(_('Quit'                 ), self.go_back)
      ], None, COLOR, HIGHLIGHT, cancel = -1)
    self.game_menu_1.resize_style = CHOICELIST_RESIZE_STYLE
    self.game_menu_1.visible = 0
    
    checkbox = [_('off'), _('on')]
    
    self.menu_h_option = soya.widget.ChoiceList(self.root, [
      soya.widget.Choice(_('Resolution'), None, None, ['320x240', '640x480', '800x600', '1024x768', '1152x864', '1280x800', '1280x1024', '1400x1050', '1680x1050']),
      soya.widget.Choice(_('Fullscreen'), None, None, checkbox),
      soya.widget.Choice(_('Graphic quality'), None, None, [_('Low'), _('Medium'), _('High')]),
      soya.widget.Choice(_('Sounds'), None, None, checkbox),
      soya.widget.Choice(_('Music'), None, None, checkbox),
      soya.widget.Choice(_('Async load music'), None, None, checkbox),
      soya.widget.Choice(_('Sound system'), None, None, ["OpenAL", "SDL_mixer"]),
      soya.widget.ChoiceInput(_('Saved game directory')),
      soya.widget.Choice(_('Back'), self.back_h_option)
      ], None, COLOR, HIGHLIGHT, cancel = -1)
    self.menu_h_option.resize_style = CHOICELIST_RESIZE_STYLE
    self.menu_h_option.visible = 0

    self.label = widget.Group(self.root)
    self.label.visible = 0
    self.label.process_event = lambda event: self.menu_label.process_event(event)
    
    self.menu_label = soya.widget.ChoiceList(self.label, [
      soya.widget.Choice( u""     , None, None, [""]),
      soya.widget.Choice(_('Back'), self.go_back),
      ], None, COLOR, HIGHLIGHT, cancel = -1)
    self.menu_label.resize_style = ('maximize', ('percent top', 0.4), 'maximize height', ('margin top', 30), ('margin bottom', 20))
    
    
    self.solo = widget.Group(self.root)
    self.solo.visible = 0
    self.solo.process_event = lambda event: self.menu_solo.process_event(event)
    
    self.menu_solo = soya.widget.ChoiceList(self.solo, [
      soya.widget.Choice     (_('Start'), self.play_solo),
      soya.widget.ChoiceInput(_('Player name (new name => new game)')),
      soya.widget.Choice     (_('Back'), self.go_back),
      ], None, COLOR, HIGHLIGHT, cancel = -1)
    self.menu_solo.resize_style = ('maximize', ('percent top', 0.4), 'maximize height', ('margin top', 30), ('margin bottom', 20))
    
    
    self.multi = widget.Group(self.root)
    self.multi.visible = 0
    self.multi.process_event = lambda event: self.menu_multi.process_event(event)
    
    self.menu_multi = soya.widget.ChoiceList(self.multi, [
      soya.widget.Choice     (_('Start'), self.play_multi),
      soya.widget.ChoiceInput(_('Player name (new name to create new game)')),
      soya.widget.ChoiceInput(_('Password')),
      soya.widget.ChoiceInput(_('Remote host or IP')),
      soya.widget.ChoiceInput(_('Connect to port')),
      soya.widget.Choice     (_('Back'), self.go_back),
      ], None, COLOR, HIGHLIGHT, cancel = -1)
    self.menu_multi.resize_style = ('maximize', ('percent top', 0.4), 'maximize height', ('margin top', 30), ('margin bottom', 20))
    
    
  def set_current_menu(self, menu):
    if self.current_menu:
      self.current_menu.visible = 0
      self.old_menus.append(self.current_menu)
    self.current_menu = menu
    self.current_menu.visible = 1
    
  def go_back(self):
    if len(self.old_menus) == 0:
      globdef.generate_dot_balazar()
      soya.IDLER.stop()
      import sys
      sys.exit()
    if self.current_menu:
      self.current_menu.visible = 0
    self.current_menu = self.old_menus.pop()
    self.current_menu.visible = 1
    
  def show_h_option(self):
    self.menu_h_option.choices[0].value = str(globdef.SCREEN_WIDTH) + 'x' + str(globdef.SCREEN_HEIGHT)
    self.menu_h_option.choices[1].value = self.menu_h_option.choices[1].range[globdef.FULLSCREEN]
    self.menu_h_option.choices[2].value = self.menu_h_option.choices[2].range[globdef.QUALITY]
    self.menu_h_option.choices[3].value = self.menu_h_option.choices[3].range[globdef.SOUND]
    self.menu_h_option.choices[4].value = self.menu_h_option.choices[4].range[globdef.MUSIC]
    self.menu_h_option.choices[5].value = self.menu_h_option.choices[5].range[globdef.ASYNC_LOAD_MUSIC]
    self.menu_h_option.choices[6].value = globdef.SOUND_SYSTEM
    self.menu_h_option.choices[7].value = globdef.SAVED_GAME_DIR
    self.set_current_menu(self.menu_h_option)
    
  def back_h_option(self):
    resa = self.menu_h_option.choices[0].value
    globdef.SCREEN_WIDTH     = int(resa[: resa.find("x")])
    globdef.SCREEN_HEIGHT    = int(resa[resa.find("x") + 1:])
    globdef.FULLSCREEN       = (self.menu_h_option.choices[1].value == _('on'))
    globdef.QUALITY          = self.menu_h_option.choices[2].range.index(self.menu_h_option.choices[2].value)
    globdef.SOUND            = (self.menu_h_option.choices[3].value == _('on'))
    globdef.MUSIC            = (self.menu_h_option.choices[4].value == _('on'))
    globdef.ASYNC_LOAD_MUSIC = (self.menu_h_option.choices[5].value == _('on'))
    globdef.SOUND_SYSTEM     = self.menu_h_option.choices[6].value
    globdef.SAVED_GAME_DIR   = self.menu_h_option.choices[7].value
    soya.set_quality(globdef.QUALITY)
    soya.set_video(globdef.SCREEN_WIDTH, globdef.SCREEN_HEIGHT, globdef.FULLSCREEN, 1)
    import balazar.sound; reload(balazar.sound)
    self.go_back()
    
  def show_solo(self):
    self.menu_solo.choices[1].value = globdef.NAME
    self.set_current_menu(self.solo)
    
  def play_solo(self):
    idler = soya.IDLER
    globdef.NAME = filter_string(self.menu_solo.choices[1].value)
    try:
      r = balazar.game_interface.start_single(globdef.NAME, "test")
    except:
      error, value, traceback = sys.exc_info()
      sys.excepthook(error, value, traceback)
      r = "%s(%s)" % (error, value)
      
    soya.set_root_widget(self.root)
    idler.reset()
    soya.IDLER = idler
    
    if r: self.message("Error: " + str(r))

    
  def show_multi(self):
    self.menu_multi.choices[1].value = globdef.NAME
    self.menu_multi.choices[2].value = globdef.PASSWORD
    self.menu_multi.choices[3].value = globdef.SERVER_HOST
    self.menu_multi.choices[4].value = str(globdef.SERVER_PORT)
    self.set_current_menu(self.multi)
    
  def play_multi(self):
    idler = soya.IDLER
    globdef.NAME        = filter_string(self.menu_multi.choices[1].value)
    globdef.PASSWORD    = filter_string(self.menu_multi.choices[2].value)
    globdef.SERVER_HOST = filter_string(self.menu_multi.choices[3].value)
    globdef.SERVER_PORT = int          (self.menu_multi.choices[4].value)
    try:
      r = balazar.game_interface.start_client(globdef.SERVER_HOST, globdef.NAME, globdef.PASSWORD, globdef.SERVER_PORT)
    except:
      error, value, traceback = sys.exc_info()
      sys.excepthook(error, value, traceback)
      r = u"%s(%s)" % (error, value)
      
    soya.set_root_widget(self.root)
    idler.reset()
    soya.IDLER = idler
    
    if r:
      if r != "Connection was closed cleanly.": # Server close the connection, because the player is dead
        r = str(r)
        if "111" in r: r = r + u"\n\n" + _("__have_you_forget_the_server_?__")
        self.message(u"Error: " + r)
        
  def message(self, text):
    self.menu_label.choices[0].label = text
    self.set_current_menu(self.label)
    


  def show_key_option(self):
    self.keyconfig = widget.Group(self.root)
    self.keyconfig.visible = 0
    self.keyconfig.process_event = lambda event: self.menu_keyconfig.process_event(event)
    self.menu_keyconfig = soya.widget.ChoiceList(self.keyconfig, [
      soya.widget.Choice(CONTROLS.control_label(control), lambda control = control : self.define_control(control))
      for control in CONTROLS.controls()
      ] + [
      soya.widget.Choice(_('Back'), self.go_back),
      ], None, COLOR, HIGHLIGHT, cancel = -1)
    self.menu_keyconfig.resize_style = ('maximize', ('percent top', 0.4), 'maximize height', ('margin top', 30), ('margin bottom', 20))
    
    self.set_current_menu(self.keyconfig)
    
  def define_control(self, control):
    while 1:
      for event in soya.process_event():
        if   event[0] == soyasdlconst.KEYDOWN:
          CONTROLS.assign_event_to_control(event[1], control)
          break
        elif event[0] == soyasdlconst.JOYBUTTONDOWN:
          CONTROLS.assign_event_to_control(soyasdlconst.K_0 + event[1], control)
          break
      else: continue
      break
    
    self.show_key_option()
    
  def run (self):
    soya.set_root_widget(self.root)
    self.idler = MainMenuIdler(self)
    action = self.idler.idle()
  
