summaryrefslogtreecommitdiffstats
path: root/lib/evendoors/room.rb
blob: be5325ba312d0f24c68a77fdd72541ede614a08b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#! /usr/bin/env ruby
# -*- coding: UTF-8 -*-

#
module EvenDoors
    #
    class Room < Spot
        #
        def initialize n, p=nil
            super n, p
            @spots = {}
            @links = {}
            @cache = {}
            @parent.add_spot self if @parent
        end
        #
        def add_spot s
            raise EvenDoors::Exception.new "Spot #{s.name} already has #{s.parent.name} as parent" if not s.parent.nil? and s.parent!=self
            raise EvenDoors::Exception.new "Spot #{s.name} already exists in #{path}" if @spots.has_key? s.name
            s.parent = self if s.parent.nil?
            @spots[s.name]=s
        end
        #
        def add_link l
            l.door = @spots[l.src]
            raise EvenDoors::Exception.new "Link source #{l.src} does not exist in #{path}" if l.door.nil?
            (@links[l.src] ||= [])<< l
        end
        #
        def start!
            puts " * start #{path}" if EvenDoors::Twirl.debug
            @spots.values.each do |spot| spot.start! if spot.respond_to? :start! end
        end
        #
        def stop!
            puts " * stop #{path}" if EvenDoors::Twirl.debug
            @spots.values.each do |spot| spot.stop! if spot.respond_to? :stop! end
        end
        #
        def space
            ( @parent.nil? ? self : @parent.space )
        end
        #
        def try_links p
            puts " * try_links ..." if EvenDoors::Twirl.debug
            pending_link = nil
            apply_link = false
            links = @links[p.src.name]
            return false if links.nil?
            links.each do |link|
                apply_link = link.cond_fields.nil?  # unconditional link
                p.set_link_fields link.cond_fields if not apply_link
                if apply_link or (p.link_value==link.cond_value)
                    # link matches !
                    if not pending_link.nil?
                        p2 = EvenDoors::Twirl.require_p p.class
                        p2.clone_data p
                        p2.src = link.door
                        p2.clear_dsts!
                        p2.add_dsts link.dsts
                        p2.set_link_fields link.fields
                        send_p p2
                    end
                    pending_link = link
                end
            end
            if pending_link
                p.src = pending_link.door
                p.clear_dsts!
                p.add_dsts pending_link.dsts
                p.set_link_fields pending_link.fields
                send_p p
            end
            (not pending_link.nil?)
        end
        #
        def route_p p
            if p.door.empty?
                p.error! EvenDoors::ERROR_ROUTE_NDN
            elsif p.room.nil? or p.room==path
                if door = @spots[p.door]
                    p.dst_routed! door
                else
                    p.error! EvenDoors::ERROR_ROUTE_RRWD
                end
            elsif @parent
                @parent.route_p p
            else
                p.error! EvenDoors::ERROR_ROUTE_TRWR
            end
        end
        #
        def send_p p
            if p.next_dst
                puts " * send #{p.next_dst.to_str} ..." if EvenDoors::Twirl.debug
                p.split_dst!
                route_p p
                puts "  -> #{p.dst.path}#{EvenDoors::ACT_SEP}#{p.action}" if EvenDoors::Twirl.debug
                EvenDoors::Twirl.send_p p
            elsif p.src.nil?
                p.error! EvenDoors::ERROR_ROUTE_NDNS
            elsif not try_links p
                p.error! EvenDoors::ERROR_ROUTE_NDNL
                puts "  -> #{p.dst.path}#{EvenDoors::ACT_SEP}#{p.action}" if EvenDoors::Twirl.debug
                EvenDoors::Twirl.send_p p
            end
        end
        #
        def send_sys_p p
            if p.next_dst
                puts " * send_sys #{p.next_dst.to_str} ..." if EvenDoors::Twirl.debug
                p.split_dst!
                if p.door.empty?
                    if p.action.nil?
                        p.error! EvenDoors::ERROR_ROUTE_SNDNA
                    else
                        p.dst_routed! space
                    end
                else
                    route_p p
                end
                puts "  -> #{p.dst.path}#{EvenDoors::ACT_SEP}#{p.action}" if EvenDoors::Twirl.debug
                EvenDoors::Twirl.send_sys_p p
            else
                p.error! EvenDoors::ERROR_ROUTE_SND
                puts "  -> #{p.dst.path}#{EvenDoors::ACT_SEP}#{p.action}" if EvenDoors::Twirl.debug
                EvenDoors::Twirl.send_sys_p p
            end
        end
        #
        def process_sys_p p
            if p.action==SYS_ACT_ADD_LINK
                add_link EvenDoors::Link.from_particle_data p
            end
            EvenDoors::Twirl.release_p p
        end
        #
    end
    #
end
#
# EOF