/
etc/
lib/
src/Abilities/
src/Abilities/Skills/
src/Abilities/Spells/
src/Abilities/Spells/Enums/
src/Affects/
src/ArtheaConsole/
src/ArtheaConsole/Properties/
src/ArtheaGUI/Properties/
src/Clans/Enums/
src/Commands/Communication/
src/Commands/ItemCommands/
src/Connections/
src/Connections/Colors/
src/Connections/Enums/
src/Connections/Players/
src/Connections/Players/Enums/
src/Continents/
src/Continents/Areas/
src/Continents/Areas/Characters/
src/Continents/Areas/Characters/Enums/
src/Continents/Areas/Items/
src/Continents/Areas/Items/Enums/
src/Continents/Areas/Rooms/
src/Continents/Areas/Rooms/Enums/
src/Continents/Areas/Rooms/Exits/
src/Creation/
src/Creation/Attributes/
src/Creation/Interfaces/
src/Database/
src/Database/Interfaces/
src/Environment/
src/Properties/
src/Scripts/Enums/
src/Scripts/Interfaces/
#region Arthea License

/***********************************************************************
*  Arthea MUD by R. Jennings (2007)      http://arthea.googlecode.com/ *
*  By using this code you comply with the Artistic and GPLv2 Licenses. *
***********************************************************************/

#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using Arthea.Clans;
using Arthea.Connections.Players;
using Arthea.Continents.Areas.Characters;
using Arthea.Continents.Areas.Items;
using Arthea.Continents.Areas.Items.Enums;
using Arthea.Continents.Areas.Resets;
using Arthea.Continents.Areas.Rooms;
using Arthea.Continents.Areas.Rooms.Enums;
using Arthea.Creation;
using Arthea.Creation.Attributes;
using Arthea.Database.Interfaces;
using Arthea.Environment;

namespace Arthea.Continents.Areas
{
    /// <summary>
    /// Implementation of an area.
    /// </summary>
    public class Area : Indexed
    {
        #region [rgn] Fields (17)

        private short age;
        private uint baseId;
        [EditIgnore] private CharIndexList characters = new CharIndexList();
        [CustomEdit("EditClan")] private Clan clan;
        [CustomEdit("EditContinent")] private Continent continent;
        private string credits;
        private RoomType defaultRoomType = RoomType.Inside;
        private string description;
        private string fileName;
        private AreaFlags flags = new AreaFlags();
        [EditIgnore] private ItemIndexList items = new ItemIndexList();
        private uint maxId;
        private string name;
        private short players;
        private ResetList resets = new ResetList();
        private short resetTime = 30;
        [EditIgnore] private RoomList rooms = new RoomList();

        #endregion [rgn]

        #region [rgn] Constructors (2)

        /// <summary>
        /// Initializes a new instance of the <see cref="Area"/> class.
        /// </summary>
        /// <param name="continent">The continent.</param>
        /// <param name="name">The name.</param>
        public Area(Continent continent, string name)
        {
            Continent = continent;
            this.name = name;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Area"/> class.
        /// </summary>
        public Area()
        {
        }

        #endregion [rgn]

        #region [rgn] Properties (19)

        /// <summary>
        /// Gets or sets the age.
        /// </summary>
        /// <value>The age.</value>
        [XmlIgnore]
        public short Age
        {
            get { return age; }
            set { age = value; }
        }

        /// <summary>
        /// Gets or sets the base id.
        /// </summary>
        /// <value>The base id.</value>
        public uint BaseId
        {
            get { return baseId; }
            set { baseId = value; }
        }

        /// <summary>
        /// Gets or sets the characters.
        /// </summary>
        /// <value>The characters.</value>
        public CharIndexList Characters
        {
            get { return characters; }
            set { characters = value; }
        }

        /// <summary>
        /// Gets or sets the clan.
        /// </summary>
        /// <value>The clan.</value>
        [XmlIgnore]
        public Clan Clan
        {
            get { return clan; }
            set { clan = value; }
        }

        /// <summary>
        /// Gets or sets the continent.
        /// </summary>
        /// <value>The continent.</value>
        [XmlIgnore]
        public Continent Continent
        {
            get { return continent; }
            set
            {
                continent = value;
                if (continent != null)
                    defaultRoomType = continent.DefaultAreaType;
            }
        }

        /// <summary>
        /// Gets or sets the credits.
        /// </summary>
        /// <value>The credits.</value>
        public string Credits
        {
            get { return credits; }
            set { credits = value; }
        }

        /// <summary>
        /// Gets or sets the default room type.
        /// </summary>
        /// <value>The default room type.</value>
        public RoomType DefaultRoomType
        {
            get { return defaultRoomType; }
            set { defaultRoomType = value; }
        }

        /// <summary>
        /// Gets or sets the description.
        /// </summary>
        /// <value>The description.</value>
        public string Description
        {
            get { return description; }
            set { description = value; }
        }

        /// <summary>
        /// Gets or sets the name of the file.
        /// </summary>
        /// <value>The name of the file.</value>
        [XmlIgnore]
        public string FileName
        {
            get { return Paths.AreaDir + fileName; }
            set
            {
                if (string.IsNullOrEmpty(value))
                    throw new Exception("File name cannot be empty.");

                if (Persistance.XmlFileExists(FileName)
                    && fileName != value)
                {
                    File.Move(Persistance.XmlFileName(FileName),
                              Persistance.XmlFileName(Paths.AreaDir + value));
                }
                fileName = value;
            }
        }

        /// <summary>
        /// Gets or sets the flags.
        /// </summary>
        /// <value>The flags.</value>
        public AreaFlags Flags
        {
            get { return flags; }
            set { flags = value; }
        }

        /// <summary>
        /// Gets or sets the items.
        /// </summary>
        /// <value>The items.</value>
        public ItemIndexList Items
        {
            get { return items; }
            set { items = value; }
        }

        /// <summary>
        /// Gets or sets the max id.
        /// </summary>
        /// <value>The max id.</value>
        public uint MaxId
        {
            get { return maxId; }
            set { maxId = value; }
        }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        /// <summary>
        /// Gets or sets the players.
        /// </summary>
        /// <value>The players.</value>
        [XmlIgnore]
        public short Players
        {
            get { return players; }
            set { players = value; }
        }

        /// <summary>
        /// Gets or sets the resets.
        /// </summary>
        /// <value>The resets.</value>
        public ResetList Resets
        {
            get { return resets; }
            set { resets = value; }
        }

        /// <summary>
        /// Gets or sets the reset time.
        /// </summary>
        /// <value>The reset time.</value>
        public short ResetTime
        {
            get { return resetTime; }
            set { resetTime = value; }
        }

        /// <summary>
        /// Gets or sets the rooms.
        /// </summary>
        /// <value>The rooms.</value>
        public RoomList Rooms
        {
            get { return rooms; }
            set { rooms = value; }
        }

        /// <summary>
        /// Gets or set the clan as a string
        /// </summary>
        /// <value>The clan name</value>
        [XmlElement("Clan")]
        public string XmlClan
        {
            get { return clan != null ? clan.Name : string.Empty; }
            set { clan = Lists.Clans.FindName(value); }
        }

        /// <summary>
        /// Gets or sets the continent name.
        /// </summary>
        /// <value>The continent name.</value>
        [XmlElement("Continent")]
        public string XmlContinent
        {
            get
            {
                if (continent != null)
                    return continent.Name;
                else
                    return string.Empty;
            }
            set { continent = Lists.Continents.FindName(value); }
        }

        /// <summary>
        /// Gets the id.
        /// </summary>
        /// <value>The id.</value>
        public uint Id
        {
            get { return baseId; }
        }

        #endregion [rgn]

        #region [rgn] Methods (12)

        // [rgn] Public Methods (12)

        /// <summary>
        /// Attaches this instance to applicable lists.
        /// </summary>
        public void Attach()
        {
            if (continent != null)
                continent.Areas.Add(this);
            Lists.Areas.Add(this);
        }

        /// <summary>
        /// Creates an instance for editing by a player.
        /// </summary>
        /// <param name="player">The player.</param>
        /// <param name="argument">The argument.</param>
        public static void Create(Player player, String argument)
        {
            Area area = new Area(player.Room.Area.Continent, argument);

            area.FileName = string.Format("area{0}", Lists.Areas.Count);

            area.Credits = player.Name;

            KeyValuePair<uint, uint> ids = Lists.Areas.FindFreeIdRange(99);

            area.BaseId = ids.Key;
            area.MaxId = ids.Value;

            if (area.Continent != null)
            {
                area.DefaultRoomType = area.Continent.DefaultAreaType;
            }

            area.Attach();

            Room newRoom = new Room();
            newRoom.Area = area;
            newRoom.Name = area.Name;
            newRoom.Id = area.baseId;
            newRoom.Type = area.defaultRoomType;
            newRoom.Attach();

            player.Room = newRoom;

            player.WriteLine("Area created.");

            player.Connection.Edit(area);
        }

        /// <summary>
        /// Creates the default area.
        /// </summary>
        public static void CreateDefaultArea()
        {
            Area area = new Area(null, "The Void");
            area.Attach();
            area.FileName = "void.xml";

            Room room = new Room(area, Globals.Limbo, "Limbo", "You are floating in darkness.");
            room.Attach();

            CharIndex mob = new CharIndex(area, 1, 1, "soul lost", "a lost soul",
                                          "Another soul is here looking lost.");
            mob.Attach();

            ItemIndex item = new ItemIndex(area, 1, "book", "the arthea history book",
                                           "A thick leather book floats here.", ItemType.Trash);
            item.Attach();

            area.Resets.Add(new ItemReset(room, item, 1));
            area.Resets.Add(new CharReset(room, mob, 1));
        }

        /// <summary>
        /// Edits the clan.
        /// </summary>
        /// <param name="player">The player.</param>
        /// <param name="editor">The field editor.</param>
        /// <param name="argument">The argument.</param>
        public static void EditClan(Player player, OlcField editor, String argument)
        {
            Clan clan = Lists.Clans.FindName(argument);

            if (clan == null)
            {
                player.WriteLine("No such clan.");
                return;
            }

            editor.Set(clan);
            player.WriteLine("Clan set to {0}.", clan.Name);
        }

        /// <summary>
        /// Edits the continent.
        /// </summary>
        /// <param name="player">The player.</param>
        /// <param name="editor">The field editor.</param>
        /// <param name="argument">The argument.</param>
        public static void EditContinent(Player player, OlcField editor, String argument)
        {
            Continent c = Lists.Continents.FindName(argument);

            if (c == null)
            {
                player.WriteLine("No such continent.");
                return;
            }

            editor.Set(c);
            player.WriteLine("Continent set to {0}.", c.Name);
        }

        /// <summary>
        /// Gets the next char id.
        /// </summary>
        /// <returns></returns>
        public uint GetNextCharId()
        {
            if (characters.Count == maxId)
            {
                return 0;
            }
            else
            {
                return baseId + (uint) characters.Count;
            }
        }

        /// <summary>
        /// Gets the next item id.
        /// </summary>
        /// <returns></returns>
        public uint GetNextItemId()
        {
            if (items.Count == maxId)
            {
                return 0;
            }
            else
            {
                return baseId + (uint) items.Count;
            }
        }

        /// <summary>
        /// Gets the next room id.
        /// </summary>
        /// <returns></returns>
        public uint GetNextRoomId()
        {
            if (rooms.Count == maxId)
            {
                return 0;
            }
            else
            {
                return baseId + (uint) rooms.Count;
            }
        }

        /// <summary>
        /// Releases this instance from applicable lists.
        /// </summary>
        public void Release()
        {
            if (continent != null)
                continent.Areas.Remove(this);
            Lists.Areas.Remove(this);
        }

        /// <summary>
        /// Saves this instance.
        /// </summary>
        public void Save()
        {
            Persistance.Save(FileName, this);
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override string ToString()
        {
            return name;
        }

        /// <summary>
        /// Updates this instance.
        /// </summary>
        public void Update()
        {
            if (Server.Instance.State == ServerState.Booting ||
                (players > 0 && ++age >= resetTime/2) ||
                age >= resetTime)
            {
                resets.Update();
                age = 0;
            }
        }

        #endregion [rgn]
    }
}