public virtual SpriterKeyFrame getNextFrameFor(
			SpriterAbstractObject @object, SpriterKeyFrame
			 currentFrame, int direction)
        {
            SpriterKeyFrame nextFrame = null;
            int cnt = 0;
            bool isBone = @object is SpriterBone;
            for (int j = (currentFrame.getId() + direction + this.keyframes()) % this.keyframes();
                nextFrame == null && cnt < this.keyframes(); j = (j + direction + this.keyframes()) %
                this.keyframes(), cnt++)
            {
                SpriterKeyFrame frame = this.frames[j];
                bool contains = (isBone) ? frame.containsBone((SpriterBone
                    )@object) : frame.containsObject((SpriterObject)
                    @object);
                if (contains)
                {
                    SpriterAbstractObject objectInFrame;
                    if (isBone) objectInFrame = frame.getBoneFor((SpriterBone)@object);
                    else objectInFrame = frame.getObjectFor((SpriterObject)@object);
                    if (@object.equals(objectInFrame))
                    {
                        nextFrame = frame;
                    }
                }
            }
            return nextFrame;
        }
        public virtual SpriterKeyFrame getNextFrameFor(
            SpriterAbstractObject @object, SpriterKeyFrame
            currentFrame, int direction)
        {
            SpriterKeyFrame nextFrame = null;
            int             cnt       = 0;
            bool            isBone    = @object is SpriterBone;

            for (int j = (currentFrame.getId() + direction + this.keyframes()) % this.keyframes();
                 nextFrame == null && cnt < this.keyframes(); j = (j + direction + this.keyframes()) %
                                                                  this.keyframes(), cnt++)
            {
                SpriterKeyFrame frame    = this.frames[j];
                bool            contains = (isBone) ? frame.containsBone((SpriterBone
                                                                          )@object) : frame.containsObject((SpriterObject)
                                                                                                           @object);
                if (contains)
                {
                    SpriterAbstractObject objectInFrame;
                    if (isBone)
                    {
                        objectInFrame = frame.getBoneFor((SpriterBone)@object);
                    }
                    else
                    {
                        objectInFrame = frame.getObjectFor((SpriterObject)@object);
                    }
                    if (@object.equals(objectInFrame))
                    {
                        nextFrame = frame;
                    }
                }
            }
            return(nextFrame);
        }
        /// <summary>Searches for a keyframe in this animation which has a smaller or equal starting time as the given time.
        ///     </summary>
        /// <remarks>Searches for a keyframe in this animation which has a smaller or equal starting time as the given time.
        ///     </remarks>
        /// <param name="time"></param>
        /// <returns>A keyframe object which has a smaller or equal starting time than the given time.
        ///     </returns>
        public virtual SpriterKeyFrame getPreviousFrame
            (long time)
        {
            SpriterKeyFrame frame = null;

            foreach (SpriterKeyFrame key in this.frames)
            {
                if (key.getTime() <= time)
                {
                    frame = key;
                }
                else
                {
                    break;
                }
            }
            return(frame);
        }
        /// <summary>Searches for a keyframe in this animation which has a smaller or equal starting time as the given time and contains the given bone.
        ///     </summary>
        /// <remarks>Searches for a keyframe in this animation which has a smaller or equal starting time as the given time and contains the given bone.
        ///     </remarks>
        /// <param name="bone"></param>
        /// <param name="time"></param>
        /// <returns>A keyframe object which has a smaller or equal starting time than the given time and contains the given bone.
        ///     </returns>
        public virtual SpriterKeyFrame getPreviousFrameForBone
            (SpriterBone bone, long time)
        {
            SpriterKeyFrame frame = null;

            foreach (SpriterKeyFrame key in this.frames)
            {
                if (!key.containsBone(bone))
                {
                    continue;
                }
                if (key.getTime() <= time)
                {
                    frame = key;
                }
                else
                {
                    break;
                }
            }
            return(frame);
        }
        /// <summary>Searches for a keyframe in this animation which has a smaller or equal starting time as the given time and contains the given object.
        ///     </summary>
        /// <remarks>Searches for a keyframe in this animation which has a smaller or equal starting time as the given time and contains the given object.
        ///     </remarks>
        /// <param name="object"></param>
        /// <param name="time"></param>
        /// <returns>A keyframe object which has a smaller or equal starting time than the given time and contains the given object.
        ///     </returns>
        public virtual SpriterKeyFrame getPreviousFrameForObject
            (SpriterObject @object, long time)
        {
            SpriterKeyFrame frame = null;

            foreach (SpriterKeyFrame key in this.frames)
            {
                if (!key.containsObject(@object))
                {
                    continue;
                }
                if (key.getTime() <= time)
                {
                    frame = key;
                }
                else
                {
                    break;
                }
            }
            return(frame);
        }
 //import Com.Brashmonkey.Spriter.converters.SpriterObjectConverter;
 //import AnimationObject;
 //final private SpriterObjectConverter objectConverter = new SpriterObjectConverter();
 public virtual SpriterAnimation buildAnimation(
     Animation animation)
 {
     MainLine mainline = animation.getMainline();
     IList<TimeLine> timeLines =
         animation.getTimeline();
     IList<Key> keyFrames = mainline
         .getKey();
     bonesToTween = new Dictionary<SpriterBone
         , int>();
     objectsToTween = new Dictionary<SpriterObject
         , int>();
     SpriterAnimation spriterAnimation = new SpriterAnimation(animation.getId(), animation.getName(), animation.getLength());
     for (int k = 0; k < keyFrames.Count; k++)
     {
         Key mainlineKey = keyFrames[k];
         IList<SpriterObject> tempObjects
              = new List<SpriterObject
             >();
         IList<SpriterBone> tempBones
              = new List<SpriterBone
             >();
         SpriterKeyFrame frame = new SpriterKeyFrame
             ();
         frame.setTime(mainlineKey.getTime());
         frame.setId(mainlineKey.getId());
         foreach (BoneRef boneRef in mainlineKey.getBoneRef())
         {
             TimeLine timeline = timeLines[boneRef.getTimeline()];
             Key timelineKey = timeline.getKey()[boneRef.getKey()];
             SpriterBone bone = boneMerger.merge(boneRef, timelineKey
                 );
             bone.setName(timeline.getName());
             if (mainlineKey.getTime() != timelineKey.getTime())
             {
                 bonesToTween.Add(bone, k);
             }
             else
             {
                 tempBones.Add(bone);
             }
         }
         //}
         foreach (AnimationObjectRef objectRef in mainlineKey.getObjectRef
             ())
         {
             TimeLine timeline = timeLines[objectRef.getTimeline()];
             Key timelineKey = timeline.getKey()[objectRef.getKey()
                 ];
             SpriterObject @object = objectMerger.merge(objectRef
                 , timelineKey);
             @object.setName(timeline.getName());
             if (mainlineKey.getTime() != timelineKey.getTime())
             {
                 objectsToTween.Add(@object, k);
             }
             else
             {
                 tempObjects.Add(@object);
             }
         }
         //}
         SpriterObject[] objArray = new SpriterObject[tempObjects.Count];
         tempObjects.CopyTo(objArray,0);
         frame.setObjects(objArray);
         SpriterBone[] boneArray = new SpriterBone[tempBones.Count];
         tempBones.CopyTo(boneArray, 0);
         frame.setBones(boneArray);
         spriterAnimation.frames.Add(frame);
     }
     this.tweenBones(spriterAnimation);
     this.tweenObjects(spriterAnimation);
     return spriterAnimation;
 }
        /// <summary>Interpolates the objects of firstFrame and secondFrame.</summary>
        /// <remarks>Interpolates the objects of firstFrame and secondFrame.</remarks>
        /// <param name="currentFrame"></param>
        /// <param name="nextFrame"></param>
        /// <param name="xOffset"></param>
        /// <param name="yOffset"></param>
        protected internal virtual void transformObjects(SpriterKeyFrame
			 currentFrame, SpriterKeyFrame nextFrame, float
			 xOffset, float yOffset)
        {
            this.rect.set(xOffset, yOffset, xOffset, yOffset);
            if (!this.updateObjects)
            {
                return;
            }
            this.updateTransformedTempObjects(nextFrame.getObjects(), this.tempObjects2);
            this.updateTempObjects(currentFrame.getObjects(), this.nonTransformedTempObjects);
            for (int i = 0; i < this.currenObjectsToDraw; i++)
            {
                if (this.tempObjects[i].active)
                {
                    this.tweenObject(this.nonTransformedTempObjects[i], nextFrame.getObjectFor(this.nonTransformedTempObjects
                        [i]), i, currentFrame.getTime(), nextFrame.getTime());
                }
            }
        }
        /// <summary>Interpolates the bones for this animation.</summary>
        /// <remarks>Interpolates the bones for this animation.</remarks>
        /// <param name="currentFrame">first keyframe</param>
        /// <param name="nextFrame">second keyframe</param>
        /// <param name="currentAnimationTime"></param>
        /// <param name="key2StartTime"></param>
        /// <returns>interpolated SpriterBone array</returns>
        protected internal virtual void transformBones(SpriterKeyFrame
			 currentFrame, SpriterKeyFrame nextFrame, float
			 xOffset, float yOffset)
        {
            if (this.rootParent.getParent() != null)
            {
                this.translateRoot();
            }
            else
            {
                this.tempParent.setX(xOffset);
                this.tempParent.setY(yOffset);
                this.tempParent.setAngle(this.angle);
                this.tempParent.setScaleX(this.flippedX);
                this.tempParent.setScaleY(this.flippedY);
            }
            this.setScale(this.scale);
            if (!this.updateBones)
            {
                return;
            }
            this.updateTransformedTempObjects(nextFrame.getBones(), this.tempBones2);
            this.updateTempObjects(currentFrame.getBones(), this.nonTransformedTempBones);
            for (int i = 0; i < this.nonTransformedTempBones.Length; i++)
            {
                if (this.tempBones[i].active)
                {
                    this.tweenBone(this.nonTransformedTempBones[i], nextFrame.getBoneFor(this.nonTransformedTempBones
                        [i]), i, currentFrame.getTime(), nextFrame.getTime());
                }
            }
        }
 /// <summary>Constructs a new SpriterAbstractPlayer object which is able to animate SpriterBone instances and SpriterObject instances.
 /// 	</summary>
 /// <remarks>Constructs a new SpriterAbstractPlayer object which is able to animate SpriterBone instances and SpriterObject instances.
 /// 	</remarks>
 /// <param name="loader">
 /// 
 /// <see cref="FileLoader{I}">FileLoader&lt;I&gt;
 /// 	</see>
 /// which you have to implement on your own.
 /// </param>
 /// <param name="keyframes">
 /// A list of SpriterKeyFrame arrays. See
 /// <see cref="SpriterKeyFrameProvider.generateKeyFramePool(com.discobeard.spriter.dom.SpriterData, com.discobeard.spriter.dom.Entity)
 /// 	">SpriterKeyFrameProvider.generateKeyFramePool(com.discobeard.spriter.dom.SpriterData, com.discobeard.spriter.dom.Entity)
 /// 	</see>
 /// to get the list.
 /// Generate these keyframes once to save memory.
 /// </param>
 public SpriterAbstractPlayer(FileLoader loader, IList<SpriterAnimation> animations)
 {
     this.loader = loader;
     this.animations = animations;
     this.rootParent = new SpriterBone();
     this.tempParent = new SpriterBone();
     this.rootParent.setName("playerRoot");
     this.tempParent.setName("playerRoot");
     this.lastFrame = new SpriterKeyFrame();
     this.lastTempFrame = new SpriterKeyFrame();
     this.interpolator = SpriterLinearInterpolator
         .interpolator;
     this.players = new List<SpriterAbstractPlayer>();
     rect = new SpriterRectangle(0, 0, 0, 0);
 }
        /// <summary>Generates all needed keyframes from the given spriter data.</summary>
        /// <remarks>Generates all needed keyframes from the given spriter data. This method sorts all objects by its z_index value to draw them in a proper way.
        /// 	</remarks>
        /// <param name="spriterData">SpriterData to generate from.</param>
        /// <returns>generated keyframe list.</returns>
        public static IList<SpriterAnimation> generateKeyFramePool(com.discobeard.spriter.dom.SpriterData data, com.discobeard.spriter.dom.Entity
			 entity)
        {
            IList<SpriterAnimation
                > spriterAnimations = new List<SpriterAnimation
                >();
            IList<com.discobeard.spriter.dom.Animation> animations
                 = entity.getAnimation();
            Com.Brashmonkey.Spriter.mergers.SpriterAnimationBuilder frameBuilder = new Com.Brashmonkey.Spriter.mergers.SpriterAnimationBuilder
                ();
            foreach (com.discobeard.spriter.dom.Animation anim in animations)
            {
                SpriterAnimation spriterAnimation = frameBuilder
                    .buildAnimation(anim);
                bool found = false;
                foreach (SpriterKeyFrame key in spriterAnimation
                    .frames)
                {
                    if (!found)
                    {
                        found = key.getTime() == anim.getLength();
                    }
                    sort(key.getObjects());
                    foreach (SpriterBone bone in key.getBones())
                    {
                        foreach (SpriterBone bone2 in key.getBones())
                        {
                            if (bone2.hasParent())
                            {
                                if (!bone2.equals(bone) && bone2.getParentId() == bone.getId())
                                {
                                    bone.addChildBone(bone2);
                                }
                            }
                        }
                        foreach (SpriterObject @object in key.getObjects(
                            ))
                        {
                            Com.Brashmonkey.Spriter.file.Reference @ref = @object.getRef();
                            com.discobeard.spriter.dom.File f = data.getFolder()[@ref.folder].getFile()[@ref.
                                file];
                            @ref.dimensions = new Com.Brashmonkey.Spriter.SpriterRectangle(0, f.getHeight(),
                                f.getWidth(), 0f);
                            if (bone.getId() == @object.getParentId())
                            {
                                bone.addChildObject(@object);
                            }
                        }
                    }
                }
                if (!found)
                {
                    SpriterKeyFrame firstFrame = spriterAnimation.frames
                        [0];
                    SpriterKeyFrame lastFrame = new SpriterKeyFrame
                        ();
                    lastFrame.setId(spriterAnimation.keyframes());
                    lastFrame.setBones(new SpriterBone[firstFrame.getBones
                        ().Length]);
                    lastFrame.setObjects(new SpriterObject[firstFrame
                        .getObjects().Length]);
                    for (int j = 0; j < lastFrame.getBones().Length; j++)
                    {
                        SpriterBone bone = new SpriterBone
                            ();
                        firstFrame.getBones()[j].copyValuesTo(bone);
                        lastFrame.getBones()[j] = bone;
                    }
                    for (int j_1 = 0; j_1 < lastFrame.getObjects().Length; j_1++)
                    {
                        SpriterObject @object = new SpriterObject
                            ();
                        firstFrame.getObjects()[j_1].copyValuesTo(@object);
                        lastFrame.getObjects()[j_1] = @object;
                    }
                    lastFrame.setTime(anim.getLength());
                    spriterAnimation.frames.Add(lastFrame);
                }
                spriterAnimations.Add(spriterAnimation);
            }
            return spriterAnimations;
        }