### Root functor: `Main.oz`

Source File

>     functor

>     prepare

>        ArgSpec = record(defaults(rightmost type:bool default:true)
>                         random(rightmost type:bool default:true))

>        %% Default companies and drivers
>        DefaultScenario = d('Disney': ['Mickey'('Düsseldorf') 'Goofy'('Berlin')]
>                            'Oz':     ['Tinman'('München') 'Toto'('Saarbrücken')])

>     import
>        Application Tk TkTools

>        Configure(fonts colors goods)
>        AgentAbstractions(new)
>        Agents(broker)
>        Widgets(entryChooser
>                map)
>        Dialogs(about
>                addCompany remCompany
>                addDriver remDriver)
>        Randomizer('class')

>     define

>        TextBg       = Configure.colors.textBg
>        TextFont     = Configure.fonts.text
>        TextWidth    = 4
>        BigTextWidth = 17

>        class Frontend
>           prop locking

>           feat
>              %% Widget references
>              menu src dst what weight send map randomvar
>              %% Agent components
>              agents broker randomizer
>              %%
>              toplevel

>           attr
>              src:unit dst:unit

>           meth init(toplevel:T)
>              self.toplevel = T

>              ThisRandomizer = {New Randomizer.'class' init(broker:ThisBroker)}

>              RandGo    = {New Tk.variable tkInit(false)}
>              RandSpeed = {New Tk.variable tkInit(1)}

>              Menu = {TkTools.menubar T T
>                      [menubutton(text:    'Transportation'
>                                  feature: transportation
>                                  menu:
>                                     [command(label:   'About...'
>                                              action:  self # about)
>                                      separator
>                                      command(label:   'Quit'
>                                              action:  Application.exit # 0)])
>                       menubutton(text:    'Configure'
>                                  feature: configure
>                                  menu:
>                                     [command(label:   'Add Company...'
>                                              action:  self # addCompany
>                                              feature: addCompany)
>                                      command(label:   'Remove Company...'
>                                              action:  self # remCompany
>                                              state:   disabled
>                                              feature: remCompany)
>                                      separator
>                                      command(label:   'Add Driver...'
>                                              action:  self # addDriver
>                                              state:   disabled
>                                              feature: addDriver)
>                                      command(label:   'Remove Driver...'
>                                              action:  self # remDriver
>                                              state:   disabled
>                                              feature: remDriver)
>                                      separator
>                                      command(label:   'Add Defaults'
>                                              action:  self # addDefaults
>                                              feature: addDefaults)])
>                       menubutton(text:    'Random'
>                                  feature: random
>                                  menu:
>                                     [radiobutton(label:    'Slow'
>                                                  action:   ThisRandomizer # slow
>                                                  variable: RandSpeed
>                                                  value:    0)
>                                      radiobutton(label:    'Medium'
>                                                  action:   ThisRandomizer # medium
>                                                  variable: RandSpeed
>                                                  value:    1)
>                                      radiobutton(label:    'Fast'
>                                                  action:   ThisRandomizer # fast
>                                                  variable: RandSpeed
>                                                  value:    2)
>                                      separator
>                                      checkbutton(label:    'Go'
>                                                  action:   ThisRandomizer # toggle
>                                                  variable: RandGo)])
>                       menubutton(text:    'Windows'
>                                  feature: windows
>                                  menu:    nil)]
>                      nil}

>              CtyMap = {New Widgets.map init(parent:self)}
>              Query  = {New Tk.frame   tkInit(parent:T relief:sunken bd:3)}

>              FromL  = {New Tk.label tkInit(parent:Query text:'From:')}
>              FromT  = {New Tk.label tkInit(parent:Query width:BigTextWidth
>                                            anchor:w
>                                            bg:TextBg font:TextFont)}
>              ToL    = {New Tk.label tkInit(parent:Query text:'To:')}
>              ToT    = {New Tk.label tkInit(parent:Query width:BigTextWidth
>                                            anchor:w
>                                            bg:TextBg font:TextFont)}
>              WhatL  = {New Tk.label tkInit(parent:Query text:'Good:')}
>              WhatT  = {New Widgets.entryChooser
>                        tkInit(parent:Query toplevel:T
>                               entries: {Record.toList Configure.goods})}
>              WhgtL  = {New Tk.label tkInit(parent:Query text:'Weight:')}
>              WhgtT  = {New Tk.entry tkInit(parent:Query width:TextWidth
>                                            bg:TextBg font:TextFont)}

>              Send   = {New Tk.button tkInit(parent:Query text:'Send to Broker'
>                                             action: self # send
>                                             state:  disabled)}
>              {WhgtT tk(insert 0 25)}

>              ThisBroker
>           in
>              {ForAll [transportation configure random windows]
>               proc {$ F}
>                  {Menu.F.menu tk(configure tearoff:false)}
>               end}
>              {Tk.batch [pack(FromL FromT ToL ToT
>                               WhatL WhatT WhgtL WhgtT side:left padx:2)
>                         pack(Send side:left padx:6)
>                         pack(Menu CtyMap Query fill:x)]}

>              self.menu   = Menu
>              self.src    = FromT
>              self.dst    = ToT
>              self.send   = Send
>              self.map    = CtyMap
>              self.weight = WhgtT
>              self.what   = WhatT.entry

>              ThisBroker = {AgentAbstractions.new Agents.broker init(toplevel:self)}

>              self.agents     = {Dictionary.new}
>              self.broker     = ThisBroker
>              self.randomizer = ThisRandomizer
>              self.randomvar  = RandGo
>           end

>           meth random
>              {self.randomvar  tkSet(true)}
>              {self.randomizer toggle}
>           end

>           meth DisableMenus
>              {ForAll [transportation configure random]
>               proc {$ F}
>                  {self.menu.F tk(configure state:disabled)}
>               end}
>           end

>           meth EnableMenus
>              {ForAll [transportation configure random]
>               proc {$ F}
>                  {self.menu.F tk(configure state:normal)}
>               end}
>           end

>           meth CheckSend
>              S=@src D=@dst
>           in
>              {self.send tk(conf state:if S\=D andthen
>                                          {IsAtom S} andthen {IsAtom D}
>                                       then normal
>                                       else disabled
>                                       end)}
>           end

>           meth putSrc(Src)
>              lock
>                 src <- Src   {self.src tk(conf text:Src)}
>                 Frontend, CheckSend
>              end
>           end

>           meth putDst(Dst)
>              lock
>                 dst <- Dst   {self.dst tk(conf text:Dst)}
>                 Frontend, CheckSend
>              end
>           end

>           meth send
>              lock
>                 W = {self.weight tkReturnInt(get $)}
>              in
>                 if {IsInt W} then
>                    {self.broker announce(src:@src dst:@dst weight:W
>                                          what:{self.what tkReturnAtom(get $)})}
>                 end
>              end
>           end

>           meth about
>              lock
>                 Frontend, DisableMenus
>                 {Wait {New Dialogs.about init(master:self.toplevel)}.tkClosed}
>                 Frontend, EnableMenus
>              end
>           end

>           meth addCompany
>              lock Agents=self.agents C in
>                 Frontend, DisableMenus
>                 {Wait {New Dialogs.addCompany init(master: self.toplevel
>                                                    agents: Agents
>                                                    company:C)}.tkClosed}
>                 if {IsDet C} then
>                    Menu = self.menu.configure
>                 in
>                    {Dictionary.put Agents C nil}
>                    {self.broker add(company:C)}
>                    {Menu.remCompany tk(entryconfigure state:normal)}
>                    {Menu.addDriver  tk(entryconfigure state:normal)}
>                    if {Some {Arity DefaultScenario}
>                          fun {$ C}
>                             {Dictionary.member Agents C}
>                          end} then
>                       {Menu.addDefaults tk(entryconfigure state:disabled)}
>                    end
>                 end
>                 Frontend, EnableMenus
>              end
>           end

>           meth remCompany
>              lock Agents=self.agents C in
>                 Frontend, DisableMenus
>                 {Wait {New Dialogs.remCompany init(master: self.toplevel
>                                                    agents: Agents
>                                                    company:C)}.tkClosed}
>                 if {IsDet C} then
>                    Menu = self.menu.configure
>                 in
>                    {Dictionary.remove Agents C}
>                    {self.broker remove(company:C)}
>                    if {Dictionary.entries Agents}==nil then
>                       {Menu.remCompany  tk(entryconf      state:disabled)}
>                       {Menu.addDriver   tk(entryconf      state:disabled)}
>                       {Menu.remDriver   tk(entryconf      state:disabled)}
>                       {Menu.addDefaults tk(entryconfigure state:normal)}
>                    elseif {Not {Some {Arity DefaultScenario}
>                                   fun {$ C}
>                                      {Dictionary.member Agents C}
>                                   end}} then
>                       {Menu.addDefaults  tk(entryconfigure state:enabled)}
>                    end
>                 end
>                 Frontend, EnableMenus
>              end
>           end

>           meth addDriver
>              lock Agents=self.agents C D Y in
>                 Frontend, DisableMenus
>                 {Wait {New Dialogs.addDriver init(master: self.toplevel
>                                                   agents: Agents
>                                                   company:C
>                                                   driver: D
>                                                   city:   Y)}.tkClosed}
>                 if {IsDet C} then
>                    {Dictionary.put Agents C D|{Dictionary.get Agents C}}
>                    {self.menu.configure.remDriver tk(entryconf state:normal)}
>                    {self.broker add(company:C driver:D city:Y)}
>                 end
>                 Frontend, EnableMenus
>              end
>           end

>           meth remDriver
>              lock Agents=self.agents C D in
>                 Frontend, DisableMenus
>                 {Wait {New Dialogs.remDriver init(master:  self.toplevel
>                                                   agents:  Agents
>                                                   company: C
>                                                   driver:  D)}.tkClosed}
>                 if {IsDet C} then
>                    {Dictionary.put Agents C
>                     {List.subtract {Dictionary.get Agents C} D}}
>                    {self.broker remove(company:C driver:D)}
>                    if {All {Dictionary.keys Agents}
>                        fun {$ C}
>                           {Dictionary.get Agents C}==nil
>                        end}
>                    then
>                       {self.menu.configure.remDriver tk(entryconf state:disabled)}
>                    end
>                 end
>                 Frontend, EnableMenus
>              end
>           end

>           meth addDefaults
>              lock Menu=self.menu.configure in
>                 {Record.forAllInd DefaultScenario
>                  proc {$ C Ds}
>                     {Dictionary.put self.agents C {Map Ds Label}}
>                     {self.broker add(company:C)}
>                     {ForAll Ds
>                      proc {$ D}
>                         {self.broker add(driver:{Label D} company:C city:D.1)}
>                      end}
>                  end}
>                 {Menu.addDefaults tk(entryconf state:disabled)}
>                 {Menu.addDriver   tk(entryconf state:normal)}
>                 {Menu.remCompany  tk(entryconf state:normal)}
>                 {Menu.remDriver   tk(entryconf state:normal)}
>              end
>           end

>        end

>        Args = {Application.getCmdArgs ArgSpec}

>        T = {New Tk.toplevel tkInit(title:  'Transportation'
>                                    delete: Application.exit # 0)}

>        F = {New Frontend init(toplevel:T)}

>        if Args.defaults orelse Args.random then
>           {F addDefaults}
>        end

>        if Args.random then
>           {F random}
>        end

>     end