const
    ion = import '../'
    {DynamicExpression,Factory} = import './'

export class MemberExpression extends DynamicExpression
    properties:
        activate: ->
            super
            @objectExpression ?= @context.createRuntime(@object)
            @propertyExpression ?= @context.createRuntime(@computed ? @property : @property.name)

            # observe the property first so it is available when we get the object
            @unobserveProperty = @propertyExpression.observe(
                @propertyWatcher ?= (propertyValue) =>
                    # we convert to string since property indexers must always be treated as strings anyways in javascript
                    propertyValue = propertyValue?.toString()
                    if @propertyValue isnt propertyValue
                        @propertyValue = propertyValue
                        @queueUpdate("propertyChanged")
            )

            @unobserveObject = @objectExpression.observe(
                @objectWatcher ?= (objectValue) =>
                    if @objectValue isnt objectValue
                        @objectValue = objectValue
                        @queueUpdate("objectChanged")
            )

            @updateValue()

        deactivate: ->
            super
            @unobserveObject?()
            @unobserveObject = null
            @unobserveProperty?()
            @unobserveProperty = null
            @unobserveObjectValue?()
            @unobserveObjectValue = null
        queueUpdate: (reason) ->
            ion.nextCheck(@boundUpdate ?= this.updateValue.bind(this))
        updateValue: ->
            let value = undefined
            if @objectValue?
                if @propertyValue?
                    value = @objectValue[@propertyValue]
            else if @isActive and not @existential and @loc?.start?.source? and @hasOwnProperty('objectValue') and @hasOwnProperty('propertyValue')
                # we need to throw an exception here with location info
                console.warn("Cannot read {{Factory.toCode(@property)}} property of {{@objectValue}} ({{Factory.toCode(@object)}}) ({{@loc.start.source}}:{{@loc.start.line}}:{{@loc.start.column + 1}})")
            @setValue(value)

            # also observe the objectValue for changes
            if @objectExpression.mutable and (@observedObject isnt @objectValue or @observedProperty isnt @propertyValue)
                @observedObject = @objectValue
                @observedProperty = @propertyValue
                # do NOT unobserve the old property until the new one has been observed.
                # this will prevent unnecessary re-quering in the event that the observed item is the same.
                let oldUnobserveObjectValue = @unobserveObjectValue
                @unobserveObjectValue = null
                if @objectValue?
                    @unobserveObjectValue = ion.observe(
                        @objectValue
                        (changes) =>
                            @queueUpdate("objectValueChanged")
                        {property:@propertyValue}
                    )
                # now we can release any previous observation.
                oldUnobserveObjectValue?()

        # # sets the underlying property value.  This may be used for two way binding.
        # setMemberValue: (value) ->
        #     console.log('setMemberValue BITCHES!', @objectValue, @propertyValue, value)
        #     if @objectValue? and @propertyValue?
        #         @objectValue[@propertyValue] = value
    test: ->
