<commit_before>using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace CocosSharp
{
    internal enum CCNodeTag
    {
        Invalid = -1,
    };

    /** @brief CCNode is the main element. Anything thats gets drawn or contains things that get drawn is a CCNode.
        The most popular CCNodes are: CCScene, CCLayer, CCSprite, CCMenu.

        The main features of a CCNode are:
        - They can contain other CCNode nodes (addChild, getChildByTag, removeChild, etc)
        - They can schedule periodic callback (schedule, unschedule, etc)
        - They can execute actions (runAction, stopAction, etc)

        Some CCNode nodes provide extra functionality for them or their children.

        Subclassing a CCNode usually means (one/all) of:
        - overriding init to initialize resources and schedule callbacks
        - create callbacks to handle the advancement of time
        - overriding draw to render the node

        Features of CCNode:
        - position
        - scale (x, y)
        - rotation (in degrees, clockwise)
        - CCCamera (an interface to gluLookAt )
        - CCGridBase (to do mesh transformations)
        - anchor point
        - size
        - visible
        - z-order
        - openGL z position

        Default values:
        - rotation: 0
        - position: (x=0,y=0)
        - scale: (x=1,y=1)
        - contentSize: (x=0,y=0)
        - anchorPoint: (x=0,y=0)

        Limitations:
        - A CCNode is a "void" object. It doesn't have a texture

        Order in transformations with grid disabled
        -# The node will be translated (position)
        -# The node will be rotated (rotation)
        -# The node will be scaled (scale)
        -# The node will be moved according to the camera values (camera)

        Order in transformations with grid enabled
        -# The node will be translated (position)
        -# The node will be rotated (rotation)
        -# The node will be scaled (scale)
        -# The grid will capture the screen
        -# The node will be moved according to the camera values (camera)
        -# The grid will render the captured screen

        Camera:
        - Each node has a camera. By default it points to the center of the CCNode.
        */

    public class CCNode : ICCUpdatable, ICCFocusable, IComparer<CCNode>, IComparable<CCNode>
    {
        public const int TagInvalid = -1;                               // Use this to determine if a tag has been set on the node.
        static uint globalOrderOfArrival = 1;

        bool ignoreAnchorPointForPosition;
        bool isCleaned = false;
        bool isOpacityCascaded;
        bool isColorCascaded;

        int tag;
        int zOrder;
        int localZOrder;
        float globalZOrder;

        float rotationX;
        float rotationY;
        float scaleX;
        float scaleY;
        float skewX;
        float skewY;

        // opacity controls
        byte displayedOpacity;
        CCColor3B displayedColor;

        CCPoint anchorPoint;
        CCPoint anchorPointInPoints;
        CCPoint position;

        CCSize contentSize;

        CCPoint3 fauxLocalCameraCenter;
        CCPoint3 fauxLocalCameraTarget;
        CCPoint3 fauxLocalCameraUpDirection;

        Dictionary<int, List<CCNode>> childrenByTag;

        CCGridBase grid;

        CCScene scene;
        CCLayer layer;

        Matrix xnaWorldMatrix;
        CCAffineTransform affineLocalTransform;
        CCAffineTransform additionalTransform;

        List<CCEventListener> toBeAddedListeners;                       // The listeners to be added lazily when an EventDispatcher is not yet available

		struct lazyAction
		{
			public CCAction Action;
			public CCNode Target;
			public bool Paused;

			public lazyAction(CCAction action, CCNode target, bool paused = false)
			{
				Action = action;
				Target = target;
				Paused = paused;
			}
		}

		List<lazyAction> toBeAddedActions;                       // The Actions to be added lazily when an ActionManager is not yet available

        #region Properties

        // Auto-implemented properties

        public bool IsRunning { get; protected set; }
        public virtual bool HasFocus { get; set; }
        public virtual bool Visible { get; set; }
        public virtual bool IsSerializable { get; protected set; }      // If this is true, the screen will be recorded into the director's state

        public virtual float VertexZ { get; set; }
        public object UserData { get; set; }
        public object UserObject { get; set; }
        public string Name { get; set; }
        public CCRawList<CCNode> Children { get; protected set; }
        public CCNode Parent { get; internal set; }

        internal protected uint OrderOfArrival { get; internal set; }

        protected bool IsReorderChildDirty { get; set; }
        protected byte RealOpacity { get; set; }
        protected CCColor3B RealColor { get; set; }

        // Manually implemented properties

        public virtual bool CanReceiveFocus
        {
            get { return Visible; }
        }

        public virtual bool IgnoreAnchorPointForPosition
        {
            get { return ignoreAnchorPointForPosition; }
            set
            {
                if (value != ignoreAnchorPointForPosition)
                {
                    ignoreAnchorPointForPosition = value;
                    UpdateTransform();
                }
            }
        }

        public virtual bool IsOpacityCascaded 
        { 
            get { return isOpacityCascaded; }
            set 
            {
                if (isOpacityCascaded == value)
                    return;

                isOpacityCascaded = value;

                if (isOpacityCascaded)
                {
                    UpdateCascadeOpacity();
                }
                else
                {
                    DisableCascadeOpacity();
                }

            }
        }

        public virtual bool IsColorCascaded 
        { 
            get { return isColorCascaded; }
            set 
            {
                if (isColorCascaded == value)
                    return;

                isColorCascaded = value;

                if (isColorCascaded)
                {
                    UpdateCascadeColor();
                }
                else
                {
                    DisableCascadeColor();
                }


            }
        }

        public virtual bool IsColorModifiedByOpacity
        {
            get { return false; }
            set { }
        }

        public virtual byte Opacity
        {
            get { return RealOpacity; }
            set
            {
                displayedOpacity = RealOpacity = value;

                UpdateCascadeOpacity();
            }
        }

        public byte DisplayedOpacity 
        { 
            get { return displayedOpacity; }
            protected set 
            {
                displayedOpacity = value;
            }
        }

        public int Tag
        {
            get { return tag; }
            set
            {
                if (tag != value)
                {
                    if (Parent != null)
                    {
                        Parent.ChangedChildTag(this, tag, value);
                    }
                    tag = value;
                }
            }
        }

        public int ChildrenCount
        {
            get { return Children == null ? 0 : Children.Count; }
        }

        public int ZOrder
        {
            get { return zOrder; }
            set
            {
                zOrder = value;
                if (Parent != null)
                {
                    Parent.ReorderChild(this, value);
                }
            }
        }

        public int LocalZOrder 
        { 
            get { return localZOrder; }

            set 
            {
                if (localZOrder != value)
                {
                    localZOrder = value;
                    if (Parent != null)
                    {
                        Parent.ReorderChild(this, localZOrder);
                    }

                    if(EventDispatcher != null)
                        EventDispatcher.MarkDirty = this;
                }
            }
        }

        public int NumberOfRunningActions
        {
            get { return ActionManager.NumberOfRunningActionsInTarget (this); }
        }

        public float GlobalZOrder 
        { 
            get { return globalZOrder; }
            set
            {
                if (globalZOrder != value)
                {
                    globalZOrder = value;
                    EventDispatcher.MarkDirty = this;
                }

            }
        }

        public virtual float SkewX
        {
            get { return skewX; }
            set
            {
                skewX = value;
                UpdateTransform();
            }
        }

        public virtual float SkewY
        {
            get { return skewY; }
            set
            {
                skewY = value;
                UpdateTransform();
            }
        }

        // 2D rotation of the node relative to the 0,1 vector in a clock-wise orientation.
        public virtual float Rotation
        {
            set
            {
                rotationX = rotationY = value;
                UpdateTransform();
            }
        }

        public virtual float RotationX
        {
            get { return rotationX; }
            set
            {
                rotationX = value;
                UpdateTransform();
            }
        }

        public virtual float RotationY
        {
            get { return rotationY; }
            set
            {
                rotationY = value;
                UpdateTransform();
            }
        }

        // The general scale that applies to both X and Y directions.
        public virtual float Scale
        {
            set
            {
                scaleX = scaleY = value;
                UpdateTransform();
            }
        }

        public virtual float ScaleX
        {
            get { return scaleX; }
            set
            {
                scaleX = value;
                UpdateTransform();
            }
        }

        public virtual float ScaleY
        {
            get { return scaleY; }
            set
            {
                scaleY = value;
                UpdateTransform();
            }
        }

        public float PositionX
        {
            get { return position.X; }
            set { Position = new CCPoint(value, position.Y); }
        }

        public float PositionY
        {
            get { return position.Y; }
            set { Position = new CCPoint(position.X, value); }
        }

        public CCColor3B DisplayedColor 
        { 
            get { return displayedColor; } 
            protected set 
            { 
                displayedColor = value;
            }
        }

        public virtual CCColor3B Color
        {
            get { return RealColor; }
            set
            {
                displayedColor = RealColor = value;

                UpdateCascadeColor();
            }
        }

        public virtual CCPoint Position
        {
            get { return position; }
            set
            {
                if (position != value) 
                {
                    position = value;
                    UpdateTransform();
                }
            }
        }

        public virtual CCPoint PositionWorldspace
        {
            get 
            {
                CCAffineTransform parentWorldTransform 
                = Parent != null ? Parent.AffineWorldTransform : CCAffineTransform.Identity;

                return parentWorldTransform.Transform(Position);
            }
        }

        // Returns the anchor point in pixels, AnchorPoint * ContentSize. This does not use
        // the scale factor of the node.
        public virtual CCPoint AnchorPointInPoints
        {
            get { return anchorPointInPoints; }
        }

        // Returns the Anchor Point of the node as a value [0,1], where 1 is 100% of the dimension and 0 is 0%.
        public virtual CCPoint AnchorPoint
        {
            get { return anchorPoint; }
            set
            {
                if (!value.Equals(anchorPoint))
                {
                    anchorPoint = value;
                    anchorPointInPoints = new CCPoint(contentSize.Width * anchorPoint.X, contentSize.Height * anchorPoint.Y);
                    UpdateTransform();
                }
            }
        }

        public virtual CCSize ScaledContentSize
        {
            get { return new CCSize(ContentSize.Width * ScaleX, ContentSize.Height * ScaleY); }
        }

        public virtual CCSize ContentSize
        {
            get { return contentSize; }
            set
            {
                if (!CCSize.Equal(ref value, ref contentSize))
                {
                    contentSize = value;
                    anchorPointInPoints = new CCPoint(contentSize.Width * anchorPoint.X, contentSize.Height * anchorPoint.Y);

                    UpdateTransform();
                }
            }
        }

        // Returns the bounding box of this node in parent space
        public CCRect BoundingBox
        {
            get
            {
                CCPoint boundingBoxOrigin = Position;

                if(IgnoreAnchorPointForPosition == false) 
                {
                    boundingBoxOrigin -= AnchorPointInPoints;
                }

                return new CCRect(boundingBoxOrigin.X, boundingBoxOrigin.Y, contentSize.Width, contentSize.Height);
            }
        }

        // Bounding box after scale/rotation/skew in parent space
        public CCRect TransformedBoundingBox
        {
            get 
            { 
                CCAffineTransform localTransform = AffineLocalTransform;
                CCRect transformedBounds = localTransform.Transform(new CCRect(0.0f, 0.0f, contentSize.Width, contentSize.Height));
                return transformedBounds; 
            }
        }

        // Bounding box after scale/rotation/skew in world space
        public CCRect TransformedBoundingBoxWorldspace
        {
            get 
            { 
                CCAffineTransform localTransform = AffineWorldTransform;
                CCRect worldtransformedBounds = localTransform.Transform(new CCRect(0.0f, 0.0f, contentSize.Width, contentSize.Height));
                return worldtransformedBounds; 
            }
        }

        public virtual CCAffineTransform AffineLocalTransform
        {
            get { return affineLocalTransform; }
        }

        public CCAffineTransform AffineWorldTransform
        {
            get 
            {
                CCAffineTransform worldTransform = CCAffineTransform.Identity;
                CCNode parent = this.Parent;
                if (parent != null) 
                {
                    worldTransform = CCAffineTransform.Concat(AffineLocalTransform, parent.AffineWorldTransform);
                }

                return worldTransform;
            }
        }

        public CCAffineTransform AdditionalTransform
        {
            get { return additionalTransform; }
            set 
            {
                if (value != additionalTransform) 
                {
                    additionalTransform = value;
                    UpdateTransform();
                }
            }
        }

        public CCNode this[int tag]
        {
            get { return GetChildByTag(tag); }
        }

        public CCGridBase Grid 
        { 
            get { return grid; }
            set 
            {
                grid = value;
                if(value != null && Scene != null) 
                {
                    grid.Scene = Scene;
                }
            }
        }

        public virtual CCScene Scene
        {
            get { return scene; }
            internal set 
            {
                if(scene != value) 
                {
                    if(scene != null) 
                    {
                        scene.SceneViewportChanged -= OnSceneViewportChanged;
                    }

                    scene = value;

                    // All the children should belong to same scene
                    if (Children != null) 
                    {
                        foreach (CCNode child in Children) 
                        {
                            child.Scene = scene;
                        }
                    }

                    if (grid != null)
                        grid.Scene = scene;

                    if (scene != null) 
                    {
                        scene.SceneViewportChanged += OnSceneViewportChanged;

                        AddedToNewScene();

                        OnSceneViewportChanged(this, null);

                        AttachActions();
                    }

                    AttachEvents();
                }
            }
        }

        public virtual CCLayer Layer 
        {
            get { return layer; }
            internal set 
            {
                if (layer != value) 
                {
                    if (layer != null) 
                    {
                        layer.LayerVisibleBoundsChanged -= OnLayerVisibleBoundsChanged;
                    }

                    layer = value;

                    // All the children should belong to same layer
                    if (Children != null) 
                    {
                        foreach (CCNode child in Children) 
                        {
                            child.Layer = layer;
                        }
                    }

                    if (layer != null) 
                    {
                        layer.LayerVisibleBoundsChanged += OnLayerVisibleBoundsChanged;

                        OnLayerVisibleBoundsChanged(this, null);
                    }

                    if (layer.Scene != null)
                        this.Scene = layer.Scene;
                }
            }
        }


        public virtual CCApplication Application
        {
            get { return Window != null ? Window.Application : null; }
        }

        public virtual CCDirector Director
        { 
            get { return Scene.Director; }
            set { Scene.Director = value; }
        }

        public virtual CCCamera Camera
        {
            get { return Layer.Camera; }
            set { Layer.Camera = value; }
        }

        public virtual CCWindow Window 
        { 
            get { return Scene != null ? Scene.Window : null; }
            set { Scene.Window = value; }
        }

        public virtual CCViewport Viewport
        {
            get { return Scene != null ? Scene.Viewport : null; }
            set { Scene.Viewport = value; }
        }

        protected Matrix XnaWorldMatrix 
        { 
            get { return xnaWorldMatrix; }
            private set 
            {
                xnaWorldMatrix = value;
            }
        }

        internal virtual CCEventDispatcher EventDispatcher 
        { 
            get { return Scene != null ? Scene.EventDispatcher : null; }
        }

        internal bool EventDispatcherIsEnabled
        {
            get { return EventDispatcher != null ? EventDispatcher.IsEnabled : false; }
            set
            {
                if (EventDispatcher != null)
                    EventDispatcher.IsEnabled = value;
            }
        }

        internal CCPoint3 FauxLocalCameraCenter 
        { 
            get { return fauxLocalCameraCenter; }
            set 
            {
                if (fauxLocalCameraCenter != value) 
                {
                    fauxLocalCameraCenter = value;
                    UpdateTransform();
                }
            }
        }

        internal CCPoint3 FauxLocalCameraTarget
        { 
            get { return fauxLocalCameraTarget; }
            set 
            {
                if (fauxLocalCameraTarget != value) 
                {
                    fauxLocalCameraTarget = value;
                    UpdateTransform();
                }
            }
        }

        internal CCPoint3 FauxLocalCameraUpDirection
        { 
            get { return fauxLocalCameraUpDirection; }
            set 
            {
                if (fauxLocalCameraUpDirection != value) 
                {
                    fauxLocalCameraUpDirection = value;
                    UpdateTransform();
                }
            }
        }

        CCScheduler Scheduler
        {
            get { return Application != null ? Application.Scheduler : null; }
        }

        CCActionManager ActionManager
        {
            get { return Application != null ? Application.ActionManager : null; }
        }

        #endregion Properties


        #region Constructors

        public CCNode()
        {
            additionalTransform = CCAffineTransform.Identity;
            xnaWorldMatrix = Matrix.Identity;
            scaleX = 1.0f;
            scaleY = 1.0f;
            Visible = true;
            tag = TagInvalid;

            HasFocus = false;
            IsSerializable = true;
            IsColorCascaded = false;
            IsOpacityCascaded = false;

            displayedOpacity = 255;
            RealOpacity = 255;
            displayedColor = CCColor3B.White;
            RealColor = CCColor3B.White;

            FauxLocalCameraUpDirection = new CCPoint3(0.0f, 1.0f, 0.0f);
        }

        #endregion Constructors


        #region Event dispatcher handling

        void AttachEvents()
        {
            if (toBeAddedListeners != null && toBeAddedListeners.Count > 0) 
            {
                var eventDispatcher = EventDispatcher;
                foreach (var listener in toBeAddedListeners) 
                {
                    if (listener.SceneGraphPriority != null)
                        eventDispatcher.AddEventListener (listener, listener.SceneGraphPriority);
                    else
                        eventDispatcher.AddEventListener (listener, listener.FixedPriority);
                }

                toBeAddedListeners.Clear ();
                toBeAddedListeners = null;
            }
        }

        #endregion Event dispatcher handling


        #region Scene callbacks

        // Hidden event handlers

        void OnSceneViewportChanged (object sender, EventArgs e)
        {
            if (Scene != null && Viewport != null && Camera != null) 
            {
                ViewportChanged ();
                VisibleBoundsChanged ();
            }
        }

        void OnLayerVisibleBoundsChanged (object sender, EventArgs e)
        {
            if (Scene != null && Viewport != null && Camera != null)
                VisibleBoundsChanged();
        }

        // Users override methods below to listen to changes to scene

        protected virtual void VisibleBoundsChanged()
        {
        }

        protected virtual void ViewportChanged()
        {
        }

        protected virtual void AddedToNewScene()
        {<commit_msg>Some more safeguarding when updating viewport<commit_after>using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace CocosSharp
{
    internal enum CCNodeTag
    {
        Invalid = -1,
    };

    /** @brief CCNode is the main element. Anything thats gets drawn or contains things that get drawn is a CCNode.
        The most popular CCNodes are: CCScene, CCLayer, CCSprite, CCMenu.

        The main features of a CCNode are:
        - They can contain other CCNode nodes (addChild, getChildByTag, removeChild, etc)
        - They can schedule periodic callback (schedule, unschedule, etc)
        - They can execute actions (runAction, stopAction, etc)

        Some CCNode nodes provide extra functionality for them or their children.

        Subclassing a CCNode usually means (one/all) of:
        - overriding init to initialize resources and schedule callbacks
        - create callbacks to handle the advancement of time
        - overriding draw to render the node

        Features of CCNode:
        - position
        - scale (x, y)
        - rotation (in degrees, clockwise)
        - CCCamera (an interface to gluLookAt )
        - CCGridBase (to do mesh transformations)
        - anchor point
        - size
        - visible
        - z-order
        - openGL z position

        Default values:
        - rotation: 0
        - position: (x=0,y=0)
        - scale: (x=1,y=1)
        - contentSize: (x=0,y=0)
        - anchorPoint: (x=0,y=0)

        Limitations:
        - A CCNode is a "void" object. It doesn't have a texture

        Order in transformations with grid disabled
        -# The node will be translated (position)
        -# The node will be rotated (rotation)
        -# The node will be scaled (scale)
        -# The node will be moved according to the camera values (camera)

        Order in transformations with grid enabled
        -# The node will be translated (position)
        -# The node will be rotated (rotation)
        -# The node will be scaled (scale)
        -# The grid will capture the screen
        -# The node will be moved according to the camera values (camera)
        -# The grid will render the captured screen

        Camera:
        - Each node has a camera. By default it points to the center of the CCNode.
        */

    public class CCNode : ICCUpdatable, ICCFocusable, IComparer<CCNode>, IComparable<CCNode>
    {
        public const int TagInvalid = -1;                               // Use this to determine if a tag has been set on the node.
        static uint globalOrderOfArrival = 1;

        bool ignoreAnchorPointForPosition;
        bool isCleaned = false;
        bool isOpacityCascaded;
        bool isColorCascaded;

        int tag;
        int zOrder;
        int localZOrder;
        float globalZOrder;

        float rotationX;
        float rotationY;
        float scaleX;
        float scaleY;
        float skewX;
        float skewY;

        // opacity controls
        byte displayedOpacity;
        CCColor3B displayedColor;

        CCPoint anchorPoint;
        CCPoint anchorPointInPoints;
        CCPoint position;

        CCSize contentSize;

        CCPoint3 fauxLocalCameraCenter;
        CCPoint3 fauxLocalCameraTarget;
        CCPoint3 fauxLocalCameraUpDirection;

        Dictionary<int, List<CCNode>> childrenByTag;

        CCGridBase grid;

        CCScene scene;
        CCLayer layer;

        Matrix xnaWorldMatrix;
        CCAffineTransform affineLocalTransform;
        CCAffineTransform additionalTransform;

        List<CCEventListener> toBeAddedListeners;                       // The listeners to be added lazily when an EventDispatcher is not yet available

		struct lazyAction
		{
			public CCAction Action;
			public CCNode Target;
			public bool Paused;

			public lazyAction(CCAction action, CCNode target, bool paused = false)
			{
				Action = action;
				Target = target;
				Paused = paused;
			}
		}

		List<lazyAction> toBeAddedActions;                       // The Actions to be added lazily when an ActionManager is not yet available

        #region Properties

        // Auto-implemented properties

        public bool IsRunning { get; protected set; }
        public virtual bool HasFocus { get; set; }
        public virtual bool Visible { get; set; }
        public virtual bool IsSerializable { get; protected set; }      // If this is true, the screen will be recorded into the director's state

        public virtual float VertexZ { get; set; }
        public object UserData { get; set; }
        public object UserObject { get; set; }
        public string Name { get; set; }
        public CCRawList<CCNode> Children { get; protected set; }
        public CCNode Parent { get; internal set; }

        internal protected uint OrderOfArrival { get; internal set; }

        protected bool IsReorderChildDirty { get; set; }
        protected byte RealOpacity { get; set; }
        protected CCColor3B RealColor { get; set; }

        // Manually implemented properties

        public virtual bool CanReceiveFocus
        {
            get { return Visible; }
        }

        public virtual bool IgnoreAnchorPointForPosition
        {
            get { return ignoreAnchorPointForPosition; }
            set
            {
                if (value != ignoreAnchorPointForPosition)
                {
                    ignoreAnchorPointForPosition = value;
                    UpdateTransform();
                }
            }
        }

        public virtual bool IsOpacityCascaded 
        { 
            get { return isOpacityCascaded; }
            set 
            {
                if (isOpacityCascaded == value)
                    return;

                isOpacityCascaded = value;

                if (isOpacityCascaded)
                {
                    UpdateCascadeOpacity();
                }
                else
                {
                    DisableCascadeOpacity();
                }

            }
        }

        public virtual bool IsColorCascaded 
        { 
            get { return isColorCascaded; }
            set 
            {
                if (isColorCascaded == value)
                    return;

                isColorCascaded = value;

                if (isColorCascaded)
                {
                    UpdateCascadeColor();
                }
                else
                {
                    DisableCascadeColor();
                }


            }
        }

        public virtual bool IsColorModifiedByOpacity
        {
            get { return false; }
            set { }
        }

        public virtual byte Opacity
        {
            get { return RealOpacity; }
            set
            {
                displayedOpacity = RealOpacity = value;

                UpdateCascadeOpacity();
            }
        }

        public byte DisplayedOpacity 
        { 
            get { return displayedOpacity; }
            protected set 
            {
                displayedOpacity = value;
            }
        }

        public int Tag
        {
            get { return tag; }
            set
            {
                if (tag != value)
                {
                    if (Parent != null)
                    {
                        Parent.ChangedChildTag(this, tag, value);
                    }
                    tag = value;
                }
            }
        }

        public int ChildrenCount
        {
            get { return Children == null ? 0 : Children.Count; }
        }

        public int ZOrder
        {
            get { return zOrder; }
            set
            {
                zOrder = value;
                if (Parent != null)
                {
                    Parent.ReorderChild(this, value);
                }
            }
        }

        public int LocalZOrder 
        { 
            get { return localZOrder; }

            set 
            {
                if (localZOrder != value)
                {
                    localZOrder = value;
                    if (Parent != null)
                    {
                        Parent.ReorderChild(this, localZOrder);
                    }

                    if(EventDispatcher != null)
                        EventDispatcher.MarkDirty = this;
                }
            }
        }

        public int NumberOfRunningActions
        {
            get { return ActionManager.NumberOfRunningActionsInTarget (this); }
        }

        public float GlobalZOrder 
        { 
            get { return globalZOrder; }
            set
            {
                if (globalZOrder != value)
                {
                    globalZOrder = value;
                    EventDispatcher.MarkDirty = this;
                }

            }
        }

        public virtual float SkewX
        {
            get { return skewX; }
            set
            {
                skewX = value;
                UpdateTransform();
            }
        }

        public virtual float SkewY
        {
            get { return skewY; }
            set
            {
                skewY = value;
                UpdateTransform();
            }
        }

        // 2D rotation of the node relative to the 0,1 vector in a clock-wise orientation.
        public virtual float Rotation
        {
            set
            {
                rotationX = rotationY = value;
                UpdateTransform();
            }
        }

        public virtual float RotationX
        {
            get { return rotationX; }
            set
            {
                rotationX = value;
                UpdateTransform();
            }
        }

        public virtual float RotationY
        {
            get { return rotationY; }
            set
            {
                rotationY = value;
                UpdateTransform();
            }
        }

        // The general scale that applies to both X and Y directions.
        public virtual float Scale
        {
            set
            {
                scaleX = scaleY = value;
                UpdateTransform();
            }
        }

        public virtual float ScaleX
        {
            get { return scaleX; }
            set
            {
                scaleX = value;
                UpdateTransform();
            }
        }

        public virtual float ScaleY
        {
            get { return scaleY; }
            set
            {
                scaleY = value;
                UpdateTransform();
            }
        }

        public float PositionX
        {
            get { return position.X; }
            set { Position = new CCPoint(value, position.Y); }
        }

        public float PositionY
        {
            get { return position.Y; }
            set { Position = new CCPoint(position.X, value); }
        }

        public CCColor3B DisplayedColor 
        { 
            get { return displayedColor; } 
            protected set 
            { 
                displayedColor = value;
            }
        }

        public virtual CCColor3B Color
        {
            get { return RealColor; }
            set
            {
                displayedColor = RealColor = value;

                UpdateCascadeColor();
            }
        }

        public virtual CCPoint Position
        {
            get { return position; }
            set
            {
                if (position != value) 
                {
                    position = value;
                    UpdateTransform();
                }
            }
        }

        public virtual CCPoint PositionWorldspace
        {
            get 
            {
                CCAffineTransform parentWorldTransform 
                = Parent != null ? Parent.AffineWorldTransform : CCAffineTransform.Identity;

                return parentWorldTransform.Transform(Position);
            }
        }

        // Returns the anchor point in pixels, AnchorPoint * ContentSize. This does not use
        // the scale factor of the node.
        public virtual CCPoint AnchorPointInPoints
        {
            get { return anchorPointInPoints; }
        }

        // Returns the Anchor Point of the node as a value [0,1], where 1 is 100% of the dimension and 0 is 0%.
        public virtual CCPoint AnchorPoint
        {
            get { return anchorPoint; }
            set
            {
                if (!value.Equals(anchorPoint))
                {
                    anchorPoint = value;
                    anchorPointInPoints = new CCPoint(contentSize.Width * anchorPoint.X, contentSize.Height * anchorPoint.Y);
                    UpdateTransform();
                }
            }
        }

        public virtual CCSize ScaledContentSize
        {
            get { return new CCSize(ContentSize.Width * ScaleX, ContentSize.Height * ScaleY); }
        }

        public virtual CCSize ContentSize
        {
            get { return contentSize; }
            set
            {
                if (!CCSize.Equal(ref value, ref contentSize))
                {
                    contentSize = value;
                    anchorPointInPoints = new CCPoint(contentSize.Width * anchorPoint.X, contentSize.Height * anchorPoint.Y);

                    UpdateTransform();
                }
            }
        }

        // Returns the bounding box of this node in parent space
        public CCRect BoundingBox
        {
            get
            {
                CCPoint boundingBoxOrigin = Position;

                if(IgnoreAnchorPointForPosition == false) 
                {
                    boundingBoxOrigin -= AnchorPointInPoints;
                }

                return new CCRect(boundingBoxOrigin.X, boundingBoxOrigin.Y, contentSize.Width, contentSize.Height);
            }
        }

        // Bounding box after scale/rotation/skew in parent space
        public CCRect TransformedBoundingBox
        {
            get 
            { 
                CCAffineTransform localTransform = AffineLocalTransform;
                CCRect transformedBounds = localTransform.Transform(new CCRect(0.0f, 0.0f, contentSize.Width, contentSize.Height));
                return transformedBounds; 
            }
        }

        // Bounding box after scale/rotation/skew in world space
        public CCRect TransformedBoundingBoxWorldspace
        {
            get 
            { 
                CCAffineTransform localTransform = AffineWorldTransform;
                CCRect worldtransformedBounds = localTransform.Transform(new CCRect(0.0f, 0.0f, contentSize.Width, contentSize.Height));
                return worldtransformedBounds; 
            }
        }

        public virtual CCAffineTransform AffineLocalTransform
        {
            get { return affineLocalTransform; }
        }

        public CCAffineTransform AffineWorldTransform
        {
            get 
            {
                CCAffineTransform worldTransform = CCAffineTransform.Identity;
                CCNode parent = this.Parent;
                if (parent != null) 
                {
                    worldTransform = CCAffineTransform.Concat(AffineLocalTransform, parent.AffineWorldTransform);
                }

                return worldTransform;
            }
        }

        public CCAffineTransform AdditionalTransform
        {
            get { return additionalTransform; }
            set 
            {
                if (value != additionalTransform) 
                {
                    additionalTransform = value;
                    UpdateTransform();
                }
            }
        }

        public CCNode this[int tag]
        {
            get { return GetChildByTag(tag); }
        }

        public CCGridBase Grid 
        { 
            get { return grid; }
            set 
            {
                grid = value;
                if(value != null && Scene != null) 
                {
                    grid.Scene = Scene;
                }
            }
        }

        public virtual CCScene Scene
        {
            get { return scene; }
            internal set 
            {
                if(scene != value) 
                {
                    if(scene != null) 
                    {
                        scene.SceneViewportChanged -= OnSceneViewportChanged;
                    }

                    scene = value;

                    // All the children should belong to same scene
                    if (Children != null) 
                    {
                        foreach (CCNode child in Children) 
                        {
                            child.Scene = scene;
                        }
                    }

                    if (grid != null)
                        grid.Scene = scene;

                    if (scene != null) 
                    {
                        scene.SceneViewportChanged += OnSceneViewportChanged;

                        AddedToNewScene();

                        OnSceneViewportChanged(this, null);

                        AttachActions();
                    }

                    AttachEvents();
                }
            }
        }

        public virtual CCLayer Layer 
        {
            get { return layer; }
            internal set 
            {
                if (layer != value) 
                {
                    if (layer != null) 
                    {
                        layer.LayerVisibleBoundsChanged -= OnLayerVisibleBoundsChanged;
                    }

                    layer = value;

                    // All the children should belong to same layer
                    if (Children != null) 
                    {
                        foreach (CCNode child in Children) 
                        {
                            child.Layer = layer;
                        }
                    }

                    if (layer != null) 
                    {
                        layer.LayerVisibleBoundsChanged += OnLayerVisibleBoundsChanged;

                        OnLayerVisibleBoundsChanged(this, null);
                    }

                    if (layer.Scene != null)
                        this.Scene = layer.Scene;
                }
            }
        }


        public virtual CCApplication Application
        {
            get { return Window != null ? Window.Application : null; }
        }

        public virtual CCDirector Director
        { 
            get { return Scene.Director; }
            set { Scene.Director = value; }
        }

        public virtual CCCamera Camera
        {
            get { return Layer.Camera; }
            set { Layer.Camera = value; }
        }

        public virtual CCWindow Window 
        { 
            get { return Scene != null ? Scene.Window : null; }
            set { Scene.Window = value; }
        }

        public virtual CCViewport Viewport
        {
            get { return Scene != null ? Scene.Viewport : null; }
            set { Scene.Viewport = value; }
        }

        protected Matrix XnaWorldMatrix 
        { 
            get { return xnaWorldMatrix; }
            private set 
            {
                xnaWorldMatrix = value;
            }
        }

        internal virtual CCEventDispatcher EventDispatcher 
        { 
            get { return Scene != null ? Scene.EventDispatcher : null; }
        }

        internal bool EventDispatcherIsEnabled
        {
            get { return EventDispatcher != null ? EventDispatcher.IsEnabled : false; }
            set
            {
                if (EventDispatcher != null)
                    EventDispatcher.IsEnabled = value;
            }
        }

        internal CCPoint3 FauxLocalCameraCenter 
        { 
            get { return fauxLocalCameraCenter; }
            set 
            {
                if (fauxLocalCameraCenter != value) 
                {
                    fauxLocalCameraCenter = value;
                    UpdateTransform();
                }
            }
        }

        internal CCPoint3 FauxLocalCameraTarget
        { 
            get { return fauxLocalCameraTarget; }
            set 
            {
                if (fauxLocalCameraTarget != value) 
                {
                    fauxLocalCameraTarget = value;
                    UpdateTransform();
                }
            }
        }

        internal CCPoint3 FauxLocalCameraUpDirection
        { 
            get { return fauxLocalCameraUpDirection; }
            set 
            {
                if (fauxLocalCameraUpDirection != value) 
                {
                    fauxLocalCameraUpDirection = value;
                    UpdateTransform();
                }
            }
        }

        CCScheduler Scheduler
        {
            get { return Application != null ? Application.Scheduler : null; }
        }

        CCActionManager ActionManager
        {
            get { return Application != null ? Application.ActionManager : null; }
        }

        #endregion Properties


        #region Constructors

        public CCNode()
        {
            additionalTransform = CCAffineTransform.Identity;
            xnaWorldMatrix = Matrix.Identity;
            scaleX = 1.0f;
            scaleY = 1.0f;
            Visible = true;
            tag = TagInvalid;

            HasFocus = false;
            IsSerializable = true;
            IsColorCascaded = false;
            IsOpacityCascaded = false;

            displayedOpacity = 255;
            RealOpacity = 255;
            displayedColor = CCColor3B.White;
            RealColor = CCColor3B.White;

            FauxLocalCameraUpDirection = new CCPoint3(0.0f, 1.0f, 0.0f);
        }

        #endregion Constructors


        #region Event dispatcher handling

        void AttachEvents()
        {
            if (toBeAddedListeners != null && toBeAddedListeners.Count > 0) 
            {
                var eventDispatcher = EventDispatcher;
                foreach (var listener in toBeAddedListeners) 
                {
                    if (listener.SceneGraphPriority != null)
                        eventDispatcher.AddEventListener (listener, listener.SceneGraphPriority);
                    else
                        eventDispatcher.AddEventListener (listener, listener.FixedPriority);
                }

                toBeAddedListeners.Clear ();
                toBeAddedListeners = null;
            }
        }

        #endregion Event dispatcher handling


        #region Scene callbacks

        // Hidden event handlers

        void OnSceneViewportChanged (object sender, EventArgs e)
        {
            if (Scene != null && Window != null && Viewport != null && Camera != null) 
            {
                ViewportChanged ();
                VisibleBoundsChanged ();
            }
        }

        void OnLayerVisibleBoundsChanged (object sender, EventArgs e)
        {
            if (Scene != null && Viewport != null && Camera != null)
                VisibleBoundsChanged();
        }

        // Users override methods below to listen to changes to scene

        protected virtual void VisibleBoundsChanged()
        {
        }

        protected virtual void ViewportChanged()
        {
        }

        protected virtual void AddedToNewScene()
        {
{'fraction_non_alphanumeric': 0.06114617090226846, 'fraction_numerical': 0.002643697765648985, 'mean_word_length': 1.135928961748634, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5076354', 'n_tokens_mistral': 11541, 'n_tokens_neox': 10398, 'n_words': 2971}