# Main eruta script.
#
# This will be executed on start up, and certain well-known functions will be
# called on input events, on timer ticks, or on screen updates.
# Note that, due to muby's syntax, everythg that is defined in this
# file at file scope, will actually be defined at the scope of Object.
# then, though inheritance, every other object will inherit it.
# This may or may not be what you want!!!
# Therefore, it's probably a a good idea to include everything
# except the well-known functions into the module Main below.
#
# The well-known functions that will be called are as follows:
# "on_bump" when a physics collision takes place
# "on_poll" when input events or timer events are received
# "on_start" when the script is loaded the first time
# "on_reload" when the script is reloaded (using the F5 key)
# "on_update" whenever the screen redraw is about to take place
# All these functions should execute quickly so they don't block the Eruta
# engine. They should set the Eruta engine state and let the C side do the
# heavy work.

# Set this to true to start a test map in stead of the normal main menu on startup.
START_TEST_MAP = false
# Play music at startup
PLAY_MUSIC     = false
# Show main background
MAIN_BACKGROUND = true

# Helpers
script 'forwardable.rb'

# Registry module 
script 'registry.rb'

# Game state
script 'state.rb'


# Load keycodes
script 'keycode.rb'
# Load OO wrappers
script 'timer.rb'
script 'thing.rb'
script 'sprite.rb'
script 'graph.rb'
script 'store.rb'
script 'bitmap.rb'
script 'font.rb'
script 'music.rb'
script 'sound.rb'
script 'tilemap.rb'

# Load UI subsystem
script 'zori.rb'

# Attacks
script 'attack.rb'

# Main menu
script 'mainmenu.rb'

script 'helpers.rb'

puts "Hi from ruby!"



module Main

  def ulpcss_load(sprite, layer, name)
    full_name = "image/ulpcss/#{name}"
    sprite_loadulpcss sprite, layer, full_name
  end

  def torso_tint(sprite, r, g, b, a = 255)
    sprite_tint_rgba sprite, SPRITELAYER_TORSO, r, g, b, a
  end


  def hair_tint(sprite, r, g, b, a = 255)
    sprite_tint_rgba sprite, SPRITELAYER_HAIR, r, g, b, a
  end

  def start_load_sprites
    Timer.make(1.0) do | timer |
      puts "In timer tick_tock, total run time: #{timer.total}."   
      timer.total > 10.0   
    end
  
    puts "Loading some things and sprites"
    player_1 = Thing.make(:player_1, Thing::Kind::PLAYER, 300, 400, 1, 32, 32)
    player_1.load_ulpcss(Sprite::Layer::BODY , "body/female/light.png")
    player_1.load_ulpcss(Sprite::Layer::TORSO, "torso/dress_female/underdress.png")
    player_1.load_ulpcss(Sprite::Layer::HAIR , "hair/female/bangslong.png")
    player_1.load_ulpcss(Sprite::Layer::STAFF, "weapons/steelwand_female.png")
    player_1.load_ulpcss_slash(Sprite::Layer::BLADE, "weapons/oversize/longsword_female.png")
    player_1.load_ulpcss_stab(Sprite::Layer::POLEARM, "weapons/oversize/spear.png")
    player_1.load_ulpcss(Sprite::Layer::BOW, "weapons/greatbow.png")
    player_1.one_shot_default    
    player_1.tint_hair(0, 255, 0)
    player_1.tint_torso(255, 64, 64)
    player_1.direction = Sprite::SOUTH
    player_1.pose      = Sprite::STAND
    player_1.hide_layer(Sprite::Layer::STAFF)
    player_1.group     = Thing::Kind::PLAYER
    
    # hf = Thing[100].hull_flags= Thing::Flag::DISABLED
    # p "set hull flag", hf, Thing[100].hull_flags
    

    Thing.make(:player_2, Thing::Kind::FOE, 400, 400, 1, 32, 32)
    Sprite.make(:s101)
    Sprite[:s101].load_ulpcss(Sprite::Layer::BODY , "body/female/orc.png")
    Sprite[:s101].load_ulpcss(Sprite::Layer::TORSO, "torso/dress_w_sash_female.png")
    # Sprite[:s101].load_ulpcss(Sprite::Layer::HAIR , "hair/female/bangsshort.png")
    Thing[:player_2].sprite     = Sprite[:s101]
    Thing[:player_2].tint_hair(255, 255, 0)
    Thing[:player_2].tint_torso(128,  128, 255)
    Thing[:player_2].pose       = Sprite::STAND
    Thing[:player_2].direction  = Sprite::SOUTH
    player_1.group     = Thing::Kind::FOE

    puts "Things and sprites loaded."

  end


  def start_load_stuff
  end

  def start_load_tilemap
    tilemap_fn = 'map/map_0001_tiled11.tmx'
    tilemap  = Tilemap.load(:map_0001, tilemap_fn)
    State.tilemap_name = :map_0001
    tilemap.activate!()
  end


  def reload_tilemap
    Tilemap.reload
  end


  def do_start_test_map
      start_load_tilemap
      start_load_sprites
      start_load_stuff
    # start_setup_ui
      actor_switch(Thing[:player_1])
  end


  #
  # def load_main_menu
  #   $main_music   = Store.load_audio_stream('/music/hiver_com64.ogg')
  #   $main_back    = Store.load_bitmap('/image/background/eruta_mainmenu.png')
  #   $main_graph   = Graph.make_image(0, 0, $main_back.id)
  #   Eruta::Audio.music_id = $main_music.id
  #   res = Eruta::Audio.play_music
  #   puts "play_music #{res} #{$main_music.id}"
  # end

  POEM_TEXT = "After mankind's summer, winter suddenly came"    +
              "Most reached for the stars, but some remained"   +
              "The earth scarred by the Ancients unhostpitable" +
              "The hopes low, and so much wisdom forgotten"     +
              "Yet when it seemed the last hour struck"         +
              "Our hope returned, a savior arose"               +
              "Lord Kei, who by Creator's grace"                +
              "Restored the Trees that guard us all from harm"  +
              "Thus ushered in a new millennial spring"         +
              "Lord Kei, watch over us and protect us"          +
              "Until the Travellers return with bounty of the stars"

  INTRO_TEXT = "Millennia have passed since mankind first traveled to the moon. "+
               "Civilizations rose as never before, yet to fall again. " +
               "When all hope seemed lost, the 21 trees sprouted from the earth. " +
               "They brought mysterious powers that protected and strengthened mankind. "+
               "Hi!\n\n" +
               "Hello µ world, this is me, 無 life should be\nfun for everyone!"

  INTRO_TEXT2 = "Something happened, and I was changed!"

  def make_sub_menu(parent, x, y, w, h, bh)
    sub_menu = parent.make_menu(x, y, w, h, nil)
    sub_menu.make_button(x, y + 20, w - 20, bh, "Sub choice 1") do
      puts "choice 1"
    end
    sub_menu.make_button(x, y + 30 + bh, w - 20, bh, "Sub choice 2") do
      puts "choice 2"
    end
    sub_menu.make_button(x, y + 40 + 2* bh, w - 20, bh, "Sub choice 3") do
      puts "choice 3"
    end
    sub_menu.fit_children
    sub_menu.hide
    return sub_menu
  end

  def do_main_menu
    main_music    = Music.load(:main, '/music/nethis-the_writer.ogg')
    $lote         = nil
    $lobe         = nil
    if PLAY_MUSIC
      res = main_music.play!
    end
    # res = nil
    # $main_menu = MainMenu.new
    # $main_menu.active = true
    Zori.make_page(:default) do |m|
      State.talk_box            = m.make_longtext(10, 310, 620, 160, "Testing 1 2 3")
      State.talk_box.graph.each { |g| g.font = Eruta::Zori.font.id }
      State.talk_box.delay      = 0.1
      State.talk_box.page_lines = 5
      State.talk_box.page       = 0
      State.talk_box.hide
    end

    
    Zori.make_page(:main_menu) do |m|
      if MAIN_BACKGROUND 
        main_back    = Bitmap.load(:main_back,
                      '/image/background/eruta_mainmenu.png')
        p main_back, main_back.width, main_back.height, main_back.name, main_back.id
                      
        main_back    = Bitmap.load(:main_back,
                      '/image/background/eruta_mainmenu.png')
        p main_back, main_back.width, main_back.height, main_back.name, main_back.id
        p Bitmap[:main_back]
        p Store[:bitmap_main_back]
        m.graph_image(0, 0, main_back.id)
      end

      main_menu     = m.make_menu(250, 190, 120, 440, nil)
      ma            = main_menu

      main_button_1 = ma.make_button(260, 200, 100, 30, "Continue")
      sub_menu = make_sub_menu(main_button_1, 50, 190, 120, 440, 30)
      sub_menu.hide
      
      main_button_2 = ma.make_button(260, 240, 100, 30, "New") do
        do_start_test_map
        Zori.go(:default)
      end
      
      main_button_3 = ma.make_button(260, 280, 100, 30, "Settings") do
        Zori.go(:settings)
      end
      
      main_button_4 = ma.make_button(260, 320, 100, 30, "Instructions")
      main_button_5 = ma.make_button(260, 360, 100, 30, "µ£éè")
      main_button_5 << sub_menu
      
      main_button_5= ma.make_button(260, 400, 100, 30, "Quit") do
        Eruta.quit
      end
      
      main_menu.fit_children
    end

    Zori.make_page(:settings) do |se|
        lote2          = se.make_longtext(100, 10, 160, 100, INTRO_TEXT)
        lote2.delay    = 1
        lote2.page     = 0
        lote2.page_lines = 3
        # $lote2.line_stop = 999990
        
        settings_menu  = se.make_menu(480, 380, 120, 440, nil)
        sm             = settings_menu
        settings_ok_button = sm.make_button(500, 300, 100, 30, "Font 1") do
           if lote2
              lote2.graph.each { |g| g.font = 0 }
           end
        end
        settings_ok_button = sm.make_button(500, 350, 100, 30, "Font 2") do
           if lote2
              lote2.graph.each { |g| g.font = Eruta::Zori.font.id }
           end
           lote2.text = INTRO_TEXT2
        end
        settings_ok_button = sm.make_button(500, 400, 100, 30, "OK") do
           Zori.go(:main_menu)
           if lote
              lote.close
              lote = nil
           end
        end
        sm.fit_children
    end

    Zori[:main_menu].hide
    Zori[:settings].hide

    Zori.go(:main_menu)
  end



  def ok!
    log "OK, it works!"
  end



  def actor_switch(new_actor)
    # Ensure the old actor stops walking.
    new_actor.v = [ 0.0, 0.0 ]
    Thing.actor = new_actor
    new_actor.track
    return new_actor
  end

  def actor_continue_talk
    if State.talk_box.at_end?
      State.talk_box.hide
      State.talk_with    = nil
      p "Talk ended."
    elsif State.talk_box.paused
      res = (State.talk_box.next_page)
      p "Continue_talk", res
    else
      State.talk_box.delay = 0.05
      p "Talking speed up"
      # speed up talk here?
    end
  end

  def actor_start_search
    p "starting search"
    found = Thing.actor.find_in_front(60, 60)
    unless found.empty?
      first                     = found.first
      State.talk_box.delay      = 0.05
      State.talk_box.show
      State.talk_box.text       = "Let's make this text a bit longer\n
  Hi there, I'm #{first.id}!"
      State.talk_with           = first
    end
  end

  # Searches and interacts with things in front of the actor.
  # Or if already talking/reading, continue with it.
  def actor_search_or_talk
    return if !Thing.actor
    if State.talk_with
      actor_continue_talk
    else
      actor_start_search
    end
  end

  # Searches and interacts with things in front of the actor.
  # Or if already talking/reading, continue with it.
  def actor_attack  
    return if !Thing.actor
    Thing.actor.v = [ 0, 0 ]
    pose = Thing.actor.pose
    Thing.actor.one_shot_action(Sprite::SLASH)
    Thing.actor.pose = Sprite::SLASH
    Attack.make(Thing.actor, 64, 64)
  end


  # Show a reminder of the key bindings on stdout
  def show_keybindings
    puts "Keybindings:"
    puts "A: Switch to actor A."
    puts "B: Switch to actor B."
    puts "E: REload currently active tile map."
    puts "F: Toggle the visibility of the FPS counter"
    puts "G: Toggle the visibility of the 2D scene Graph"
    puts "H: Hide 2D scene graph GUI"
    puts "N: Disable tile map."
    puts "P: Toggle the visibility of the area/physics bounds boxes."
    puts "R: Toggle the visibility of the area spRites."
    puts "S: Show 2D scene graph GUI"
    puts "Arrow keys: Move active actor."
    puts "Shift keys: use weapon."
    puts "Space: search in front of active actor or continue talking."
  end

  # Handle key down
  def on_key_down(time, key)

    State.last_key_time = time
    State.last_key      = key
   
    p "on_key_down #{time} #{key}"
    actor         = Thing.actor
    return nil unless actor
    vx, vy        = * actor.v
    case key
      when KEY_A
        actor_switch(Thing[:player_1])
      when KEY_B
        actor_switch(Thing[:player_2])
      when KEY_E
        reload_tilemap()
      when KEY_H
        Eruta::Graph.visible_(52, 0)
      when KEY_M
        active_map_($tilemap_id)
      when KEY_N
        active_map_(-1)
      when KEY_S
        Eruta::Graph.visible_(52, 1)
      when KEY_F
        Eruta.show_fps=     !Eruta.show_fps
      when KEY_R
        Eruta.show_area=    !Eruta.show_area
      when KEY_G
        Eruta.show_graph=   !Eruta.show_graph
      when KEY_P
        Eruta.show_physics= !Eruta.show_physics
      when KEY_UP
        vy -= 100.0
        actor.v = [ vx, vy ]
      when KEY_DOWN
        vy += 100.0
        actor.v = [ vx, vy ]
      when KEY_LEFT
        vx -= 100.0
        actor.v = [ vx, vy ]
      when KEY_RIGHT
        vx += 100.0
        actor.v = [ vx, vy ]
      when KEY_D
        Thing.actor.pose = Sprite::DOWN
      when KEY_SPACE
        puts "Searching..."
        actor_search_or_talk
      when KEY_LSHIFT, KEY_RSHIFT
        puts "attacking"
        actor_attack
        actor.v = [ 0, 0 ]
      when KEY_COMMA
        show_keybindings
      else
    end    
    return nil
  end

  # Handle key up. XXX: maybe refactor this to a game class or module???
  def on_key_up(time, key)
    actor         = Thing.actor
    return nil unless actor
    vx, vy        = * actor.v
    case key
    when KEY_UP
      vy = 0.0
      actor.v = [vx, vy]
    when KEY_DOWN
      vy = 0.0
      actor.v = [vx, vy]
    when KEY_LEFT
      vx = 0.0
      actor.v = [vx, vy]
    when KEY_RIGHT
      vx = 0.0
      actor.v = [vx, vy]
    when KEY_SPACE
      State.talk_box.delay = 0.1 if State.talk_with
    else
    end
    return nil
  end
  
  # Handle events from the C GUI side
  def on_gui(widget_id, kind)
    # 
    puts "Received GUI event: #{widget_id}, #{kind}"
  end 

  # Make all methods and constants are available as Main.XXX
  extend self
end # module Main

####################################
# Below are the entry point functions that will be called by the Eruta engine
# at certain events or times.
####################################


# Called when the main.rb script is loaded for the first time.
def eruta_on_start(*args)
  puts "on_start #{args}"
  State.time_start = Eruta.time
  Zori.open
  Main.do_main_menu()
  return :ok
end


# Called when the main.rb script is reloaded (through the F5 key).
def eruta_on_reload(*args)
  puts "on_reload #{args}"
  puts "load thing ok: #{Thing.methods - Object.methods}"
  puts "load thing ok: #{Eruta::Thing.methods - Object.methods}"
  return :ok
end


# Called on a physics collision.
def eruta_on_bump(t1, t2, h1, h2, kind = nil)
  if kind == 1 # Begin of collision
    # puts "Begin collision!"
  elsif kind == 2 # Collision active
    puts "Colliding! #{t1}<->#{t2} (#{h1}<->#{h2})"
    thing1 = Thing[t1]
    thing2 = Thing[t2]
    if thing1 && thing2
      thing1.on_bump(thing2, h1, h2)
    else
      puts "Colliding! #{t1}<->#{t2} (#{h1}<->#{h2})"
    end
  elsif kind == 3 # Collision done
    puts "Collision done!"
  else
    puts "Unknown collision type shouldn't happen!"
  end
  return true
end

# Called on certain sprite events (end of one shot animation)
def eruta_on_sprite(spriteid, thingid, pose, direction, kind = nil)
  thing = Thing[thingid]
  if thing
    thing.on_sprite(spriteid, pose, direction, kind)
  end
  puts "Sprite event: #{spriteid} #{thingid}  #{pose} #{direction} #{kind}."
end

# Called on an update tick, just before drawing to the screen.
def eruta_on_update(dt)
  # Update the timers
  Timer.update
end

# Called when an input event occurs. 
# Note that the C side GUI will capture input events while it is active.
def eruta_on_poll(*args)
  type = args.shift
  meth = "on_#{type}".to_sym
  if Main.respond_to?(meth)
    Main.send(meth, *args)
  else
    # ignore
    log_to "input", "#{__FILE__.split('/').last}:#{__LINE__}: input: #{type} #{meth} #{args}"
     # puts "input #{type} #{meth} #{args}"
  end  
end

# Called when a GUI event occurs
def eruta_on_gui(*args)
  type = args.shift
  meth = "on_gui".to_sym
  if Main.respond_to?(meth)
    Main.send(meth, *args)
  else
    raise "Main must support on_gui!"
  end  
end