Implement ActionList::Entry#clear.
[kaya.git] / lib / interaction / undo_manager.rb
blob7d3c39812740472f4c0c4e7bbddfd60e55e6dc2d
1 # Copyright (c) 2009 Paolo Capriotti <p.capriotti@gmail.com>
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 require 'observer_utils'
10 class UndoManager
11   include Observable
12   DuplicateUndoInformation = Class.new(Exception)
13   NoSuchPlayer = Class.new(Exception)
14   
15   def initialize(players)
16     @players = { }
17     players.each do |player|
18       @players[player] = nil
19     end
20   end
21   
22   def undo(player, moves, opts = { })
23     unless @cancelled
24       raise NoSuchPlayer unless @players.has_key?(player)
25       unless @players[player].nil?
26         raise DuplicateUndoInformation.new(
27           "player #{player.inspect} already specified undo information")
28       end
29       @players[player] = {
30         :moves => moves,
31         :more => opts[:allow_more] }
32       if @players.all?{|p, info| info }
33         common = find_common
34         fire :complete => common
35         fire :execute => common
36       end
37     end
38   end
39   
40   def cancel
41     @cancelled = true
42     fire :complete => nil
43   end
44   
45   private
46   
47   def find_common
48     common = 1
49     common_more = true
50     
51     @players.each do |player, data|
52       if data
53         return nil unless data[:moves]
54         if common.nil? || data[:moves] > common
55           return nil unless common_more
56           common = data[:moves]
57           common_more = data[:more]
58         elsif data[:moves] < common
59           return nil unless data[:more]
60         end
61       end
62     end
63     
64     common
65   end
66 end