should = require "should"
Yie = require "../lib/l"

describe "StateMachine", ->
  
  describe "States", ->
    
    describe "Entity", ->
      
      describe "Person", ->
        
        it "should have the first state as initial substate as default", (done) ->
          
          class Person extends Yie.Entity
            @states ->
              @state "Life", ->
                @state "Mood", ->
                  @state "Happy", ->
                    @state "Very"
                    @state "Little"
                  @state "Angry"
                  
          person = new Person
          
          person.isIn("Life").should.be.true
          
          person.isIn("Mood").should.be.true
          
          person.isIn("Happy").should.be.true
          person.isCurrentlyIn("Very").should.be.true
          person.isIn("Little").should.be.false
          
          person.isIn("Angry").should.be.false
          
          done()
          
        it "should have concurrent substates when enabled", (done) ->
          
          class Person extends Yie.Entity
            @states ->
              @state "Life", concurrent: yes, ->
                @state "Mood", ->
                @state "Martial", ->
                
          person = new Person
          
          person.isIn("Life").should.be.true
          person.isCurrentlyIn("Mood").should.be.true
          person.isCurrentlyIn("Martial").should.be.true
          
          done()
          
        it "should not have concurrent substates when disabled", (done) ->
          
          class Person extends Yie.Entity
            @states ->
              @state "Life", concurrent: no, ->
                @state "Mood", ->
                @state "Martial", ->
                
          person = new Person
          
          person.isIn("Life").should.be.true
          person.isCurrentlyIn("Mood").should.be.true
          person.isCurrentlyIn("Martial").should.be.false
          
          done()
          
        it "should have both initial substates and concurrent substates", (done) ->
          
          class Person extends Yie.Entity
            @states ->
              @state "Life", concurrent: yes, ->
                @state "Mood", ->
                  @state "Happy", ->
                  @state "Angry", ->
                  @state "Sad", ->
                @state "Martial", ->
                  @state "Single", ->
                  @state "Married", ->
                  @state "Divorced", ->
                
          person = new Person
          
          person.isIn("Life").should.be.true
          
          person.isIn("Mood").should.be.true
          person.isCurrentlyIn("Happy").should.be.true
          person.isIn("Angry").should.be.false
          person.isIn("Sad").should.be.false
          
          person.isIn("Martial").should.be.true
          person.isCurrentlyIn("Single").should.be.true
          person.isIn("Married").should.be.false
          person.isIn("Divorced").should.be.false
          
          done()
          
        it "should respond to an event", (done) ->
          
          class Happy extends Yie.State
            name: "Happy"
            "accident": (done, goto) ->
              @owner().name.should.equal "Johnny Luu"
              done()
              
          class Person extends Yie.Entity
            name: null
            
            @states ->
              @state "Life", ->
                @state "Mood", ->
                  @state Happy, ->
                    @state "Very"
                    @state "Little"
                  @state "Angry"
                  @state "Sad"
                
          person = new Person
          person.set "name", "Johnny Luu"
          
          person.isIn("Life").should.be.true
          
          person.isIn("Mood").should.be.true
          
          person.isIn("Happy").should.be.true
          person.isCurrentlyIn("Very").should.be.true
          person.isIn("Little").should.be.false
          
          person.isIn("Angry").should.be.false
          person.isIn("Sad").should.be.false
          
          person.emit "accident", done
          
        it "should transition to another state on event", (done) ->
          
          class Very extends Yie.State
            name: "Very"
            "accident": ->
              @goto "Sad"
              
          class Person extends Yie.Entity
            name: null
            
            @states ->
              @state "Life", ->
                @state "Mood", ->
                  @state "Happy", ->
                    @state Very, ->
                      @event "accident", goto: "Sad"
                    @state "Little"
                  @state "Angry"
                  @state "Sad"
                  
          person = new Person
          person.set "name", "Johnny Luu"
          
          person.isIn("Life").should.be.true
          
          person.isIn("Mood").should.be.true
          
          person.isIn("Happy").should.be.true
          person.isCurrentlyIn("Very").should.be.true
          person.isIn("Little").should.be.false
          
          person.isIn("Angry").should.be.false
          person.isIn("Sad").should.be.false
          
          person.emit "accident"
          
          person.isIn("Mood").should.be.true
          person.isIn("Happy").should.be.false
          person.isIn("Angry").should.be.false
          person.isCurrentlyIn("Sad").should.be.true
          
          done()