/
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.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using Arthea.Connections.Players;
using Arthea.Creation;
using Arthea.Interfaces;

namespace Arthea
{
    /// <summary>
    /// Implements a flag
    /// </summary>
    public abstract class Flag : CustomEditType, IXmlSerializable, IEquatable<Flag>
    {
        #region [rgn] Fields (2)

        private ulong bits;

        #endregion [rgn]

        #region [rgn] Constructors (4)

        /// <summary>
        /// Initializes a new instance of the <see cref="Flag"/> class.
        /// </summary>
        /// <param name="value">The value.</param>
        public Flag(ulong value)
        {
            bits = value;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Flag"/> class.
        /// </summary>
        /// <param name="flag">The bit bits.</param>
        public Flag(Flag flag)
        {
            bits = flag.bits;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Flag"/> class.
        /// </summary>
        /// <param name="value">The value.</param>
        public Flag(string value)
        {
            Parse(value);
        }

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

        #endregion [rgn]

        #region [rgn] Properties (1)

        /// <summary>
        /// Gets or sets the bits.
        /// </summary>
        /// <value>The bits.</value>
        public ulong Bits
        {
            get { return bits; }
            set { bits = value; }
        }

        #endregion [rgn]

        #region [rgn] Methods (13)

        // [rgn] Public Methods (13)

        /// <summary>
        /// Equalses the specified flag.
        /// </summary>
        /// <param name="flag">The flag.</param>
        /// <returns></returns>
        public bool Equals(Flag flag)
        {
            if (flag == null) return false;
            return bits == flag.bits;
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"></see> is equal to the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"></see> to compare with the current <see cref="T:System.Object"></see>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"></see> is equal to the current <see cref="T:System.Object"></see>; otherwise, false.
        /// </returns>
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(this, obj)) return true;
            return Equals(obj as Flag);
        }

        /// <summary>
        /// Return a comma delimited string of names for each bit
        /// that is set.
        /// </summary>
        /// <returns>names of each set bit</returns>
        public string GetBitNames()
        {
            if (Bits == 0)
                return string.Empty;

            StringBuilder buf = new StringBuilder();

            foreach (FieldInfo field in GetType().GetFields())
            {
                if (field.FieldType != typeof (ulong))
                    continue;

                if (Has((ulong) field.GetValue(this)))
                {
                    buf.Append(",");
                    buf.Append(field.Name);
                }
            }

            if (buf.Length > 0)
                buf.Remove(0, 1);

            return buf.ToString();
        }

        /// <summary>
        /// Serves as a hash function for a particular type. <see cref="M:System.Object.GetHashCode"></see> is suitable for use in hashing algorithms and data structures like a hash table.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override int GetHashCode()
        {
            return (int) bits;
        }

        /// <summary>
        /// Determines whether [has] [the specified mask].
        /// </summary>
        /// <param name="mask">The mask.</param>
        /// <returns>
        /// 	<c>true</c> if [has] [the specified mask]; otherwise, <c>false</c>.
        /// </returns>
        public bool Has(ulong mask)
        {
            return (bits & mask) != 0;
        }

        /// <summary>
        /// Determines whether [has] [the specified flag].
        /// </summary>
        /// <param name="flag">The flag.</param>
        /// <returns>
        /// 	<c>true</c> if [has] [the specified flag]; otherwise, <c>false</c>.
        /// </returns>
        public bool Has(Flag flag)
        {
            return (bits & flag.bits) != 0;
        }

        /// <summary>
        /// Converts a comma-delimited string into bit values
        /// </summary>
        /// <param name="value">the string with bit names</param>
        public Flag Parse(string value)
        {
            if (string.IsNullOrEmpty(value))
                return this;

            string[] names = value.Split(',');

            foreach (string name in names)
            {
                FieldInfo flag =
                    GetType().GetField(name, BindingFlags.Static | BindingFlags.IgnoreCase | BindingFlags.Public);

                if (flag != null)
                    Set((ulong) flag.GetValue(this));
            }

            return this;
        }

        /// <summary>
        /// Removes the specified mask.
        /// </summary>
        /// <param name="mask">The mask.</param>
        public void Remove(ulong mask)
        {
            bits &= ~mask;
        }

        /// <summary>
        /// Sets the specified mask.
        /// </summary>
        /// <param name="mask">The mask.</param>
        public void Set(ulong mask)
        {
            bits |= mask;
        }

        /// <summary>
        /// Sets the specified bit bits.
        /// </summary>
        /// <param name="flag">The bit bits.</param>
        public void Set(Flag flag)
        {
            bits |= flag.bits;
        }

        /// <summary>
        /// Toggles the specified mask.
        /// </summary>
        /// <param name="mask">The mask.</param>
        public void Toggle(ulong mask)
        {
            bits ^= mask;
        }

        /// <summary>
        /// Toggles the specified bit bits.
        /// </summary>
        /// <param name="flag">The bit bits.</param>
        public void Toggle(Flag flag)
        {
            bits ^= flag.bits;
        }

        /// <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 GetBitNames();
        }

        #endregion [rgn]

        #region CustomEditType Members

        /// <summary>
        /// Allows custom editing of this type by player.
        /// </summary>
        /// <param name="player">The player.</param>
        /// <param name="editor">The editor values.</param>
        /// <param name="argument">The argument.</param>
        public void CustomEdit(Player player, OlcField editor, String argument)
        {
            if (string.IsNullOrEmpty(argument))
            {
                player.WriteLine("Set {0} to what?", editor.Name);
                return;
            }

            String[] names = argument.GetArgs();
            FieldInfo flag = null;

            foreach (String name in names)
            {
                flag = GetType().GetField(name, BindingFlags.Static | BindingFlags.IgnoreCase | BindingFlags.Public);

                if (flag != null)
                    Toggle((ulong) flag.GetValue(this));
                else
                    player.WriteLine("Could not find flag '{0}'.", name);
            }
            if (flag != null)
                player.WriteLine("{0}: flag(s) toggled.", editor.Name);
        }

        #endregion

        #region IXmlSerializable Members

        ///<summary>
        ///This property is reserved, apply the <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"></see> to the class instead.
        ///</summary>
        ///
        ///<returns>
        ///An <see cref="T:System.Xml.Schema.XmlSchema"></see> that describes the XML representation of the object that is produced by the <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"></see> method and consumed by the <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"></see> method.
        ///</returns>
        ///
        public XmlSchema GetSchema()
        {
            return null;
        }

        ///<summary>
        ///Generates an object from its XML representation.
        ///</summary>
        ///
        ///<param name="reader">The <see cref="T:System.Xml.XmlReader"></see> stream from which the object is deserialized. </param>
        public void ReadXml(XmlReader reader)
        {
            if (reader.IsEmptyElement)
                return;

            Parse(reader.ReadElementString());
        }

        ///<summary>
        ///Converts an object into its XML representation.
        ///</summary>
        ///
        ///<param name="writer">The <see cref="T:System.Xml.XmlWriter"></see> stream to which the object is serialized. </param>
        public void WriteXml(XmlWriter writer)
        {
            if (Bits == 0)
                return;

            writer.WriteString(GetBitNames());
        }

        #region Operators

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="flag1">The flag1.</param>
        /// <param name="flag2">The flag2.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator !=(Flag flag1, Flag flag2)
        {
            return !Equals(flag1, flag2);
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="flag1">The flag1.</param>
        /// <param name="flag2">The flag2.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator ==(Flag flag1, Flag flag2)
        {
            return Equals(flag1, flag2);
        }

        #endregion

        #endregion
    }
}