    package flare.vis.operator
    {
        import flare.animate.FunctionSequence;
        import flare.animate.Transitioner;
        import flare.util.Arrays;

        /**
         * An OperatorSequence maintains a list of operators that are run in
         * sequence with an animated transition in between each. This is in
         * contrast to an OperatorList, which runs all the operators at once
         * and constructs a single animated transition across all sub-operators.
         * Instead, an OperatorSequence runs each operator separately, providing
         * each with a different Transitioner. The result is a multi-stage
         * animation, in which each operator in the seqeunce get its own
         * sub-transition.
         *
         * <p>The <code>add</code> method is not supported by this class. Instead,
         * use the <code>addToSequence</code> method, which includes the operator
         * to add along with a duration value (in seconds) specifying the length
         * of the animated transition for the operator.</p>
         *
         * <p>An OperatorSequence is implemented by creating a
         * <code>flare.animate.FunctionSequence</code> instance and using it to
         * construct the staged animation. The <code>FunctionSequence</code> is
         * then added to the <code>Transitioner</code> passed in to the
         * <code>operate</code> method for this class. As a result, the
         * <code>operate</code> methods for each operator contained in the
         * seqeunce will not be invoked until the top-level
         * <code>Transitioner</code> is played.</p>
         *
         * <p>However, if the input <code>Transitioner</code> is null or in
         * immediate mode, all the operators in the sequence will be run
         * immediately, exactly like a normal <code>OperatorList</code>.</p>
         */
        public class OperatorSequence extends OperatorList
        {
            /** @private */
            protected var _times:/*Number*/Array = [];

            /**
             * Creates a new OperatorSequence.
             */
            public function OperatorSequence()
            {
                super();
            }

            /**
             * Adds an operator and its timing information to this operator
             * sequence. The operator will be invoked with a transitioner
             * configured with the given duration (in seconds).
             * @param op the operator to add to the sequence
             * @param duration the duration of the animated transition to be
             *  used for results of the given operator.
             */
            public function push(op:IOperator, duration:Number):void
            {
                super.add(op);
                _times.push(duration);
            }

            /**
             * Sets the duration in seconds for the animated transition for the
             * operator at the given index.
             * @param i the index at which to set the duration
             * @param duration the desired duration, in seconds
             * @return the previous duration value
             */
            public function setDurationAt(i:uint, duration:Number):Number
            {
                var old:Number = _times[i];
                _times[i] = duration;
                return old;
            }

            /**
             * This method is not supported by this class and will throw an error
             * if invoked.
             * @param op an input operator (ignored)
             */
            public override function add(op:IOperator):void
            {
                throw new Error("Operation not supported. Use push instead.");
            }

            /** @inheritDoc */
            public override function remove(op:IOperator):Boolean
            {
                var idx:int = Arrays.remove(_list, op);
                if (idx >= 0) {
                    _times.splice(idx, 1);
                    return true;
                } else {
                    return false;
                }
            }

            /** @inheritDoc */
            public override function removeOperatorAt(i:uint):IOperator
            {
                var op:IOperator = super.removeOperatorAt(i);
                if (op != null) _times.splice(i, 1);
                return op;
            }

            /** @inheritDoc */
            public override function operate(t:Transitioner=null):void
            {
                if (t==null || t.immediate) {
                    super.operate(t);
                } else {
                    var fs:FunctionSequence = new FunctionSequence();
                    for (var i:int=0; i<_list.length; ++i) {
                        if (_list[i].enabled)
                            fs.push(getFunction(_list[i]), _times[i]);
                    }
                    t.add(fs);
                }
            }

            private function getFunction(op:IOperator):Function {
                return function(t:Transitioner):void {
                    op.operate(t);
                    if (visualization.axes) {
                        visualization.axes.update(t);
                    }
                }
            }

        } // end of class OperatorSequence
    }