

class GoReplay < GoWin

  include DiagramPrinter
  include Sgf_Info
  include Browser


  def initialize(collection=nil)

    @scrollwidth= Float(Defaults::DEFS['scrollwidth.max'])

    super()


    @top.help_add('command','label'=>'replay a game','command'=>proc { TkHtml.new("file://#{$current_path}/../help/editor.html#replay") })

    @file_menu=Menu.new
    @file_menu.add('command', 'label' => 'Open','command' => proc {open_file})
    @file_menu.add('command', 'label' => 'Open URL','command' => proc {open_url})
    @file_menu.add('command', 'label' => 'Save','state'=>'disabled','command' => proc {save_file})
    @file_menu.add('command', 'label' => 'Save variation','state'=>'disabled','command' => proc {save_var})
    @file_menu.add('separator')
    @file_menu.add('command', 'label' => 'Edit','state'=>'disabled','command' => proc { open_editor})
    @file_menu.add('command', 'label' => 'View sgf','state'=>'disabled','command' => proc { view_sgf})
    @file_menu.add('command','label'=>'Score','state'=>'disabled','command'=>proc { score_game})
    @file_menu.add('separator')
    @file_menu.add('command', 'label' => 'Print','state'=>'disabled','command' => proc { print})
    @file_menu.add('command', 'label' => 'Export','state'=>'disabled','command' => proc { save_ascii})
#@file_menu.add('command', 'label' => 'Save diagram','state'=>'disabled','command' => proc {save_bw_diagram })
    @file_menu.add('separator')
    @file_menu.add('command', 'label' => 'Quit','command' => proc { quit})

    @game_menu=Menu.new
    @game_menu.add('command', 'label' => 'Info','command' => proc {open_sgf_info(@current_node)})

    @collect_menu= Menu.new

    @game_menu.add('cascade','menu'=>@collect_menu, 'label'=>'Collection')


    @vars_menu = Menu.new
    @vars_menu.add('radiobutton', 'label' => 'childrens' , 'variable' => @show_siblings , 'value' => '0' , 'command'=> proc {change_siblings} )
    @vars_menu.add('radiobutton', 'label' => 'siblings','variable' => @show_siblings , 'value' => '1', 'command'=> proc {change_siblings})

    @vars_menu.add('checkbutton', 'label' => 'show letters' , 'variable' => @show_markup , 'offvalue' => '0' , 'onvalue' => '1','command'=>proc {change_markup})
    @game_menu.add('cascade','menu'=>@vars_menu, 'label'=> 'Variations')


    @moves_menu= Menu.new
    @moves_menu.add('command', 'label' => 'Numbering',  'command'=> proc { number_moves })
    @moves_menu.add('separator')
    @moves_menu.add('radiobutton', 'label' => 'Don\'t show',  'variable' =>  @show_move_nb, 'value' => '0' , 'command'=> proc {clear_numbers ; set_show_move_nb('0') } )
    @moves_menu.add('radiobutton', 'label' => 'Show',  'variable' =>  @show_move_nb, 'value' => '1' , 'command'=> proc {set_show_move_nb('1') } )
    @moves_menu.add('radiobutton', 'label' => 'Modulo 100',  'variable' =>  @show_move_nb, 'value' => '2' , 'command'=> proc {set_show_move_nb('2') } )
    @game_menu.add('cascade','menu'=>@moves_menu, 'label'=> 'Moves numbers')

    @figure_menu= Menu.new
#@show_coords= Defaults.get_default_value('show_coordinates')
    @figure_menu.add('checkbutton', 'label' => 'show coordinates' , 'variable' => @show_coords , 'offvalue' => '0' , 'onvalue' => '1','command'=>proc {set_show_coords})
# @show_hoshis= Defaults.get_default_value('show_hoshis')
    @figure_menu.add('checkbutton', 'label' => 'show hoshis' , 'variable' => @show_hoshis , 'offvalue' => '0' , 'onvalue' => '1','command'=>proc {set_show_hoshis})
    @figure_menu.add('checkbutton', 'label' => 'show diagram name' , 'variable' => @show_diagram_name , 'offvalue' => '0' , 'onvalue' => '1','command'=>proc {set_show_diagram_name})
    @figure_menu.add('checkbutton', 'label' => 'remove captured stones' , 'variable' => @remove_captured , 'offvalue' => '0' , 'onvalue' => '1')
    @figure_menu.add('checkbutton', 'label' => 'list hidden moves' , 'variable' => @show_list_moves , 'offvalue' => '0' , 'onvalue' => '1','command'=>proc {set_show_list_moves})

    @game_menu.add('cascade','menu'=>@figure_menu, 'label'=> 'Figure')

    @view_menu = Menu.new

    @view_menu.add('checkbutton',
                   'label' => 'Commands' , 'variable' => @show_right , 'offvalue' => '0' , 'onvalue' => '1',
                   'command'=>proc {
      if @show_right.value == '1'
        @right.pack( 'side'=>'right','fill' => 'both','expand'=>'no')
      else
        @right.unpack
      end })


    @view_menu.add('separator')

    @top.menubar.add('cascade','menu' => @file_menu, 'label' => 'File')
    @top.menubar.add('cascade','menu' => @view_menu, 'label' => 'View')
    @top.menubar.add('cascade','menu' => @game_menu, 'label' => 'Game','state'=>'disabled')


    @timer= TkAfter.new(proc {Defaults.time_interval},-1,proc {set_forward})
    @edit_sgf_info=false

 if collection
    set_collection(collection)
  elsif self.class == GoReplay
# no good when called by go.rb 
    #open_file
  end
    

  end

  def enable_menus


    for i in 0..@top.menubar.index('end').to_i
      @top.menubar.entryconfigure(i,'state'=>'normal')
    end
    for i in 0..@file_menu.index('end').to_i
      @file_menu.entryconfigure(i,'state'=>'normal') if @file_menu.menutype(i) == 'command'
    end


  end

  def clear_numbers
    @goban.clear_move_numbers
  end


  def print
    print_diagram
  end

  def open_win
    open_win_basic
    open_win_info
    open_cmd


   
  end

  def open_cmd
    @cmd= VTexturedPane.new(@f1,Defaults::DEFS['CommonBackground'],10,5,1,6).pack('fill'=> 'both','expand'=>'yes','side'=>'right')

    navpane = VTexturedPane.new(@cmd, Defaults::DEFS['goreplay-bg'], 5,2,1,0).pack('pady'=>10)

    navpane.add_text(TkDefaults::GUI['GoReplay.title.navigate'])

    navigate= TkFrame.new(navpane,TkDefaults::GUI['GoReplay.frame.navigate'])

    opts=TkDefaults::GUI['GoReplay.button.begin'].update( {'command'=> proc {set_begin;@mid.focus}})
    @b_begin = TkButton.new(navigate,opts).pack('side'=>'left')

    opts=TkDefaults::GUI['GoReplay.button.fastb'].update( {'command'=> proc {set_fastb;@mid.focus}})
    @b_fastb = TkButton.new(navigate,opts).pack('side'=>'left')

    opts=TkDefaults::GUI['GoReplay.button.backward'].update( {'command'=> proc {set_backward;@mid.focus}})
    @b_backw = TkButton.new(navigate,opts).pack('side'=>'left')

    opts=TkDefaults::GUI['GoReplay.button.forward'].update( {'command'=> proc {set_forward;@mid.focus}})
    @b_forw = TkButton.new(navigate,opts).pack('side'=>'left')

    opts=TkDefaults::GUI['GoReplay.button.fastf'].update( {'command'=> proc {set_fastf;@mid.focus}})
    @b_fastf = TkButton.new(navigate,opts).pack('side'=>'left')

    opts=TkDefaults::GUI['GoReplay.button.end'].update( {'command'=> proc {set_end;@mid.focus}})
    @b_end = TkButton.new(navigate,opts).pack('side'=>'left')

    navpane.add(navigate)

    @move_counter= navpane.add_text(TkDefaults::GUI['GoReplay.move.navigate'])

    opts= TkDefaults::GUI['GoReplay.scrollbar.navigate'].update( 'command' => proc { |*args| goto( *args) } )

    @scrollbar=TkScrollbar.new(navpane,opts)
    @scrollbar.bind('ButtonRelease',proc { set_scroll_number })


    @scrollw= navpane.add(@scrollbar)
    @scrollw.configure('width'=>Defaults::DEFS['scrollwidth'])

    navpane.configure(TkDefaults::GUI['GoReplay.pane.navigate'])
    navpane.reconfigure


    playpane = VTexturedPane.new(@cmd, Defaults::DEFS['goreplay-bg'], 5,2,1,0).pack('pady'=>10)
    playpane.add_text(TkDefaults::GUI['GoReplay.title.play'])

    play= TkFrame.new(playpane,TkDefaults::GUI['GoReplay.frame.play'])


    opts=TkDefaults::GUI['GoReplay.button.play'].update( {'command'=> proc {start_play}})
    @b_start= TkButton.new(play,opts).pack('side'=>'left')

    opts=TkDefaults::GUI['GoReplay.button.play_fast'].update( {'command'=> proc {play_fast}})
    @b_fast= TkButton.new(play,opts).pack('side'=>'left')

    opts=TkDefaults::GUI['GoReplay.button.stop'].update( {'command'=> proc {stop_play}})
    @b_stop= TkButton.new(play,opts).pack('side'=>'left')

    playpane.add(play)
    playpane.configure(TkDefaults::GUI['GoReplay.pane.play'])
    playpane.reconfigure

    vars = PTexturedPane.new(@cmd, Defaults::DEFS['goreplay-bg'], 5,3,1,1).pack('pady'=>10)
    vars.configure(TkDefaults::GUI['GoReplay.pane.variations'])
    tt=vars.add_text(TkDefaults::GUI['GoReplay.title.variations'])

    opts=TkDefaults::GUI['GoReplay.button.varprev'].update( {'command'=> proc {var_prev}})
    @v_prev= TkButton.new(vars,opts)
    bp = vars.add( @v_prev)

    opts=TkDefaults::GUI['GoReplay.button.varnext'].update( {'command'=> proc {var_next}})
    @v_next= TkButton.new(vars,opts)
    bn = vars.add(@v_next)


    opts=TkDefaults::GUI['GoReplay.frame.variations']
    @v_list = TkListbox.new(vars,opts)
    @v_list.bind_balloon

    @v_list.bind('ButtonRelease-1',proc {set_var})
    vl = vars.add(@v_list)

    vars.place(tt,vars,vars,20,0)

    vars.place(bp,vars,tt,0,5)
    vars.place(bn,vars,bp)
    vars.place(vl,bp,tt,0,5)
    vars.reconfigure

    @mid.bind('Right',proc {set_forward})
    @mid.bind('Shift-Right',proc {set_fastf})
    @mid.bind('Control-Right',proc {set_next_text})
    @mid.bind('Left',proc {set_backward})
    @mid.bind('Shift-Left',proc {set_fastb})
    @mid.bind('Control-Left',proc {set_prev_text})
    @mid.bind('End',proc {set_end})
    @mid.bind('Home',proc {set_begin})
    @mid.bind('Up',proc {var_prev})
    @mid.bind('Down',proc {var_next})
    @mid.bind('Return',proc {start_play})
    @mid.bind('Shift-Return',proc {play_fast})
    @mid.bind('space',proc {stop_play})
    @mid.focus

  end

  def goto(*args)
    return unless args # si, si
    if args[0] == 'scroll'
      @goto_number=@move_nb
      if args[2] == 'units'
        @goto_number += args[1]
      elsif args[2] == 'pages'
        @goto_number += args[1].to_f* Defaults::REPLAY['fast_forward']
      end
    elsif args[0] == 'moveto'
	    v= args[1].to_f
	#    debug "#{v}x#{@scrollwidth}= #{v*@scrollwidth}"
      @goto_number=(v*@scrollwidth).to_i
      @scrollbar.set(v,v)
      @move_counter.configure('text'=> @goto_number.to_s)
    else
      @goto_number=nil
    end
  end

  def set_scroll_number

    return unless  @goto_number

    if @move_nb< @goto_number
      set_gotof(@goto_number)
    elsif @move_nb> @goto_number
      set_gotob(@goto_number)
    end

  end

  def set_gotob(number)

    return if @current_node.prev.nil?
    @top.cursor('watch')
    goban.fast_move= true
    while  @move_nb > number + 1
      break if @current_node.prev.prev.nil?
      undo_fast_node
      @current_node = @current_node.prev

    end

    goban.fast_move=false
    set_backward
    @top.cursor('')
  end

  def set_gotof(number)
    return if @current_node.next.nil?
    @top.cursor('watch')
    goban.fast_move= true
    while  @move_nb < number - 1
      break if @current_node.next.next.nil?
      set_fast_node( @current_node.next)
    end

    goban.fast_move=false
    set_forward
    @top.cursor('')
  end

  def number_moves
    Misc.get_double('first number','start from') { |start,from|  numbering(start.to_i,from.to_i) }
  end

  def numbering(start,from)
   from = 1 if from == 0
    return unless  start>0
    clear_numbers
    node= @current_node
    @goban.unset_mark

    while node.move_nb >= from
      move= node['W'] || node['B']
      @goban.set_numbering(move.col,move.row,node.move_nb-from+start)
      node=node.prev
    end

  end

  def set_move_nb(nb)
    super(nb)
    return unless @move_counter
    @move_counter.configure('text'=> nb.to_s)
    pos=nb/@scrollwidth
    @scrollbar.set(pos,pos)
  end

  def start_play
    Defaults.set_time_interval('normal')
    @timer.start unless @timer.nil? or @timer.running?
    @b_stop.configure('state'=> 'normal')
    @b_fast.configure('state'=> 'normal')
    @b_start.configure('state'=> 'disabled')
  end

  def play_fast
    Defaults.set_time_interval('fast')
    @timer.start unless @timer.nil? or @timer.running?
    @b_stop.configure('state'=> 'normal')
    @b_start.configure('state'=> 'normal')
    @b_fast.configure('state'=> 'disabled')
  end

  def stop_play
    @timer.stop if @timer
    @b_start.configure('state'=> 'normal')
    @b_fast.configure('state'=> 'normal')
    @b_stop.configure('state'=> 'disabled')
  end

  def open_file(file = nil)

    if file and file =~ /^http/
      open_url(file)
    else
      super(file)
    end
  end

  def open_url(adr=nil)

   #   url= JF_URL.new('http://gobase.org/teaching/index.html')
   #  url= JF_URL.new('http://gtl.jeudego.org/reviews/by_strength.php3?pg=4')
   #  url= JF_URL.new('http://gobase.org/analysed/')
   #adr= 'http://gobase.org/analysed/'

    browse_url(adr) { |data|
      collection= SGF.new
      collection.read_data(data)
      set_collection collection
    }
  end

  def set_collection(collect)

    super(collect)
    set_collection_names
    enable_menus
  end

  def set_collection_names
    @collect_menu.delete(0,'end')
    @collect_nb = TkVariable.new(0) if @collect_nb.nil?
    i=0
    @collection.each {|root|
      if root['GN'].nil?
        name = 'no name'
      else
        name = root['GN'].values[0]
        if index= name.index("\n")
          name= name[0,index ]
        end
        if name.length > 40
          name = name[0,40]
        end
      end

      @collect_menu.add('radiobutton', 'label' => name , 'variable' => @collect_nb ,'value'=> i,  'command'=> proc { set_root(root)} )
      i+=1
    }
  end

  def change_markup
    if @show_markup == '0'
      delete_vars
    else
      show_vars
    end
  end

  def change_siblings
    delete_vars
    show_vars
  end

  def set_show_vars(val)
	super(val)    
    if @show_siblings.value == '1'
      @v_next.configure('state'=>'disabled')
      @v_prev.configure('state'=>'disabled')
    end

  end

  def show_vars

    @v_list.delete(0, 'end')

    if @show_siblings.value == '1'
      c_node= @current_node
    else
      c_node= @current_node.next
    end

    return if  @show_siblings.value == '0'  and c_node.nil?
    return if c_node.nil?
    return if  c_node.var_next.nil? and c_node.var_prev.nil?

    node = c_node
    node = node.var_prev while node.var_prev
    until node.nil?
      prop=(node['W'].nil? ? node['B'] : node['W'])
      if prop.nil?
        @v_list.insert('end',"#{node.c_var.chr}: Setup")
      else
        if prop.move_pass
          @v_list.insert('end',"#{node.c_var.chr}: Pass")
        else
          @v_list.insert('end',"#{node.c_var.chr}: "+Grid.to_coords(prop.col,prop.row, @height))
          if @show_markup == '1' and ( @show_siblings.value == '0' or node != c_node)
            @goban.put_char(node.c_var,prop.col,prop.row)
          end
        end
      end
      @v_list.selection_set('end') if node == c_node
      node= node.var_next
    end
    @v_list.see('active')

  end

  def delete_vars
    @goban.remove_class(TextVar)
  end

  def set_turn(color)
    super(color)
    return unless @w_p_inf
    if color == 'W'
      @w_p_inf.highlight
      @b_p_inf.normal
    else
      @b_p_inf.highlight
      @w_p_inf.normal
    end

  end

  def clear_turn(color)
    super(color)
    return unless @w_p_inf
    if color == 'W'
      @w_p_inf.normal
    else
      @b_p_inf.normal
    end
  end

  def set_node(node)

    @goban.remove_tag('Graphics')
	@goban.unset_mark

    clear_msg
    clear_comment
    set_node_name('')
    set_node_annot('')

    super(node)


    if p=(node['W'] or node['B'])
      if p.move_pass
        str =(p.ident== 'W' ? 'white' : 'black') + ' pass'
      else
        str= "(#{p.ident}): #{Grid.to_coords(p.col,p.row,@height)}"
      end
      set_move_label(str)
      set_turn( p.ident == 'W' ? 'B' : 'W')
      @w_p_inf.set_pris(@w_pris) if @w_p_inf
      @b_p_inf.set_pris(@b_pris) if @b_p_inf
    end

    show_vars
    @goban.raise_all
    config_btns
  end

   def var_prev
    node = @current_node
    node = node.next if @show_siblings.value == '0'

    unless node.var_prev.nil?
      undo_node if @show_siblings.value == '1'
      set_node node.var_prev
    end
  end

  def var_next
    node = @current_node
    node = node.next if @show_siblings.value == '0'


    if node.var_next
      undo_node if @show_siblings.value == '1'
      set_node node.var_next
    end
  end

  def set_var
    select= @v_list.curselection[0]
    return if select.nil?
    node = @current_node
    node = node.next if @show_siblings.value == '0'
    node = node.var_prev until node.var_prev.nil?
    i=0
    until i == select
      node = node.var_next
      i += 1
    end
    return if node == @current_node
    undo_node if @show_siblings.value == '1'
    set_node node
  end

  def set_next_text
    while @current_node.next.next and @current_node.next['C'].nil? and @current_node.next['LB'].nil?
      set_fast_node(@current_node.next)
    end
    set_forward
  end

  def set_prev_text
    while @current_node.prev.prev and @current_node.prev['C'].nil? and @current_node.prev['LB'].nil?
      undo_fast_node
      set_fast_node(@current_node.prev)
    end
    set_backward
  end

  def set_root(root)
    super(root)
    set_move_nb(0)
    @goban.set_shift_click { |col,row| choose_var(col,row) }
    @goban.set_ctrl_click { |nb| set_gotob(nb) }
  #	@b_start.configure('state'=>'normal')
  #	@b_fast.configure('state'=>'normal')
  end

  def choose_var(col,row)

    refnode = @current_node
    refnode = refnode.next if @show_siblings.value == '0'
    return false if refnode.nil?

    node= find_var(refnode,col,row)
    return false if node.nil?

    undo_node if @show_siblings.value == '1'
    set_node node
    return true
  end

  def find_var(node,col,row)

     #node = @current_node
     #node = node.next if @show_siblings.value == '0'
    return nil if node.nil?
    node = node.var_prev until node.var_prev.nil?

    while node
      prop=(node['W'].nil? ? node['B'] : node['W'])
      if prop
        break if prop.col == col and prop.row == row
      end
      node = node.var_next
    end

    node

  end
def config_btns
super()

    node = @current_node
    node = node.next if @show_siblings.value == '0'
    
    if node.nil? or node.var_next.nil? or @show_siblings.value == '0'
      @v_next.configure('state'=>'disabled')
    else
      @v_next.configure('state'=>'normal')
    end

    if  node.nil? or node.var_prev.nil? or @show_siblings.value == '0'
      @v_prev.configure('state'=>'disabled')
    else
      @v_prev.configure('state'=>'normal')
    end

end

end
