package mx.controls {
    import flash.events.Event;
    import flash.events.EventDispatcher;

    import mx.collections.ArrayCollection;
    import mx.core.mx_internal;

    import org.flexunit.assertThat;
    import org.flexunit.async.Async;
    import org.fluint.uiImpersonation.UIImpersonator;

    use namespace mx_internal;

    public class Tree_FLEX_18746_Tests
    {
        private static var noEnterFramesToWait:int = NaN;
        private static const _finishNotifier:EventDispatcher = new EventDispatcher();

        private static var _sut:Tree;
        private static var child:Object = {label: "Item"};
        private static var parent0:Object;
        private static var parent1:Object;


        [Before]
        public function setUp():void
        {
            _sut = new Tree();
            _sut.width = 200;
            _sut.height = 200;

            parent0 = {label: "Folder 0", children: new ArrayCollection()};
            parent1 = {label: "Folder 1", children: new ArrayCollection([child])};

            UIImpersonator.addChild(_sut);
        }

        [After]
        public function tearDown():void
        {
            UIImpersonator.removeAllChildren();
            _sut = null;
        }


        //--------------------------------------------------------------------------
        //
        //  Test method
        //
        //--------------------------------------------------------------------------

        [Test(async, timeout=1000)]
        public function test_closing_previously_opened_folder_with_0_children_without_animation_does_not_throw_fatal():void
        {
            //given
            const dataProvider:ArrayCollection = new ArrayCollection();
            dataProvider.addItem(parent0);
            dataProvider.addItem(parent1);

            //when
            _sut.dataProvider = dataProvider;

            //then wait a few frames
            noEnterFramesToWait = 2;
            UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame);
            Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_expand_second_folder, 300, {useAnimation:false});
        }

        [Test(async, timeout=1000)]
        public function test_closing_previously_opened_folder_with_0_children_using_animation_does_not_throw_fatal():void
        {
            //given
            const dataProvider:ArrayCollection = new ArrayCollection();
            dataProvider.addItem(parent0);
            dataProvider.addItem(parent1);

            //when
            _sut.dataProvider = dataProvider;

            //then wait a few frames
            noEnterFramesToWait = 2;
            UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame);
            Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_expand_second_folder, 300, {useAnimation:true});
        }


        private function then_expand_second_folder(event:Event, passThroughData:Object):void
        {
            //when
            _sut.expandItem(parent1, true, passThroughData.useAnimation, true);

            //then wait a bit
            noEnterFramesToWait = 5;
            UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame);
            Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_move_child_to_first_parent_and_expand_it, 500, passThroughData);
        }

        private function then_move_child_to_first_parent_and_expand_it(event:Event, passThroughData:Object):void
        {
            //then
            assertThat(_sut.isItemOpen(parent1));

            //when
            ArrayCollection(parent1.children).removeItemAt(0);
            _sut.expandItem(parent0, true, passThroughData.useAnimation, true);
            ArrayCollection(parent0.children).addItem(child);

            //then wait a bit
            noEnterFramesToWait = 1;
            UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame);
            Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_contract_second_folder, 200, passThroughData);
        }

        private static function then_contract_second_folder(event:Event, passThroughData:Object):void
        {
            //when
            _sut.expandItem(parent1, false, passThroughData.useAnimation, true);

            //then no error was thrown
            assertThat(true);
        }


        private static function onEnterFrame(event:Event):void
        {
            if(!--noEnterFramesToWait)
            {
                UIImpersonator.testDisplay.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
                _finishNotifier.dispatchEvent(new Event(Event.COMPLETE));
            }
        }
    }
}