using System;
using System.Collections;
using System.Xml.Serialization;

using Icarus.Logic.GameEngine;
using Icarus.Logic.Physics;

namespace Icarus.Logic
{
	/// <summary>
	/// The World is composed of me.
	/// 
	/// All gameplay entities are derived from me and contain
	///  this set of standard features. 
	/// </summary>
	[XmlInclude(typeof(Physics.PhysicsMerc))]
    [XmlInclude(typeof(Physics.MovingPlatform))]
    [XmlInclude(typeof(Physics.MovingPlatformHorizontal))]
    [XmlInclude(typeof(Physics.MovingPlatformVertical))]
    [XmlInclude(typeof(Physics.PhysicsTuxHand))]
    [XmlInclude(typeof(Physics.PhysicsTuxRobot))]
    [XmlInclude(typeof(Physics.PhysicsGeek))]
    [XmlInclude(typeof(Physics.PhysicsGNURobot))]
    [XmlInclude(typeof(Physics.PhysicsTuxHead))]
    [XmlInclude(typeof(Physics.ZoomTrigger))]
	public class WorldObject : PhysicsObject { //, IViewable {

        #region Declarations

        private GameProperties gpGameStats = null;
        private GameFaction facFaction = null;
		private ArrayList mChildren = new ArrayList();
        
        #endregion

        #region Fields

        /// <summary>
        /// The WorldObject's Game properties
        /// </summary>
        public GameProperties GameStats {
            get { return this.gpGameStats; }
            set { this.gpGameStats = value;}
        }

        /// <summary>
        /// The WorldObject's Faction
        /// </summary>
        public GameFaction Faction {
            get { return this.facFaction; }
            set { this.facFaction = value;}
        }

		/// <summary>
		/// Gets or sets the array of children. This is for serialization purposes only. Use the appropriate methods for other stuff.
		/// </summary>
		public ChildObject[] Children
		{
			get { return mChildren.ToArray(typeof(ChildObject)) as ChildObject[]; }
			set
			{
				mChildren.Clear();

				foreach (ChildObject obj in value)
				{
					this.AddChildObject(obj);
				}
			}
		}

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes all WorldObject structures to
        /// default values
        /// </summary>
        public WorldObject() {
            gpGameStats = new GameProperties();
            Faction = new GameFaction();
            GameStats = new GameProperties();
        }

        #endregion

        #region Methods

        /// <summary>
        /// This function destroys me 
        /// (actually, I'm not even sure what this does to me yet)
        /// </summary>
        public void destroy() {
            return ;
        }

        /// <summary>
        /// This prints the World Object
        /// </summary>
        public void PrintWorldObject() {
            Console.WriteLine(this.ToString());
        }

        /// <summary>
        /// Converts the World Object data into a string
        /// </summary>
        /// <returns></returns>
        public override string ToString() {
            return ("WorldObject:" + 
                "\n GameStats: " + this.gpGameStats + 
                "\n Location:     " + this.Location +
                "\n Velocity:     " + this.Velocity +
                "\n Acceleration: " + this.Acceleration +
                "\n AngularAccel: " + this.AngularAcceleration +
                "\n AngularVel:   " + this.AngularVelocity +
                "\n Inertia:      " + this.Inertia +
                "\n");
        }

		/// <summary>
		/// Adds the child object to the list of children of this world object.
		/// </summary>
		/// <param name="obj">The child to be added</param>
		public void AddChildObject(ChildObject obj)
		{
			obj.Parent = this;
			this.mChildren.Add(obj);
		}

        /// <summary>
        /// Remoes the child object from the list of children of this world object.
        /// </summary>
        /// <param name="obj">The child to be removed</param>
        public void RemoveChildObject(ChildObject obj)
        {
            this.mChildren.Remove(obj);
        }

		/// <summary>
		/// Returns the number of children of this world object.
		/// </summary>
		/// <returns></returns>
		public int GetChildCount() { return this.mChildren.Count; }

		/// <summary>
		/// Returns the index-th child object.
		/// </summary>
		/// <param name="index"></param>
		/// <returns></returns>
		public ChildObject GetChildAt(int index) { return mChildren[index] as ChildObject; }

        #endregion
    }
}
