using System;
using System.Collections.Generic;
using System.Text;

namespace Administration
{
    enum MessageTargets
    {
        GAME, 
        MAIL,
    }

    enum ItemOrigins
    {
        BASE,
        SHIP,
    }

    /// <summary>
    /// Požadavek na určitou operaci od uživatele
    /// </summary>
    abstract class Request
    {
        protected ProtocolWriter protocolWriter;

        /// <summary>
        /// Vytvoří řetězcovou reprezentaci požadavku podle platného protokolu
        /// </summary>
        /// <returns>Řetězcová reprezentace požadavku</returns>
        public abstract string ToMessageString();

        /// <summary>
        /// Druh požadavku zprávy
        /// </summary>
        public enum RequestNames
        {
            UNDEFINED,
            BAN_PLAYER,
            GET_PLAYER_DETAILS,
            GET_PLAYERS_LIST,
            GENERATE_PASSWORD,
            SEND_MESSAGE,
            GET_SHIP_DETAILS, 
            GET_BASE_DETAILS,
            DELETE_SHIP_FROM_PLAYER,
            DELETE_BASE_FROM_PLAYER,
            DELETE_ITEM_FROM_SHIP,
            DELETE_ITEM_FROM_BASE,
        }

        /// <summary>
        /// Druh požadavku zprávy
        /// </summary>
        public abstract RequestNames Name
        {
            get;
        }

        /// <summary>
        /// Vytvoří novou instanci třídy <c>Request</c>
        /// </summary>
        public Request()
        {
            protocolWriter = new ProtocolWriter();
        }
    }

    /// <summary>
    /// Požadavek na zabanování hráče
    /// </summary>
    class BanPlayerRequest : Request
    {
        /// <summary>
        /// ID zabanovaného hráče
        /// </summary>
        private ulong playerID;

        /// <summary>
        /// Počet dní, na které hráč dostane ban
        /// </summary>
        private int days;

        /// <summary>
        /// Úroveň uděleného banu
        /// </summary>
        private int level;

        /// <summary>
        /// Důvod pro zabanování hráče
        /// </summary>
        private string reason;

        /// <summary>
        /// Vytvoří novou instanci třídy <c>BanPlayerRequest</c>
        /// </summary>
        /// <param name="playerID">ID zabanovaného hráče</param>
        /// <param name="days">Počet dní, na které hráč dostane ban</param>
        /// <param name="level">Úroveň uděleného banu</param>
        /// <param name="reason">Důvod pro zabanování hráče</param>
        public BanPlayerRequest(ulong playerID, int days, int level, string reason)
        {
            this.playerID = playerID;
            this.days = days;
            this.level = level;
            this.reason = reason;
        }

        public override string ToMessageString()
        {
            protocolWriter.beginMessage(MessageType.MT_REQUEST, Name.ToString());

            protocolWriter.writeValue("PLAYER_ID", playerID);
            protocolWriter.writeValue("DAYS", days);
            protocolWriter.writeValue("LEVEL", level);

            if (reason != null)
            {
                protocolWriter.writeValue("REASON", reason);
            }
            else
            {
                protocolWriter.writeValue("REASON", "");
            }

            protocolWriter.endMessage(true);
            return protocolWriter.copyMessage();
        }

        public override RequestNames Name
        {
            get
            {
                return RequestNames.BAN_PLAYER;
            }
        }
    }

    /// <summary>
    /// Požadavek na získání podrobností o konkrétním hráči
    /// </summary>
    class GetPlayerDetailsRequest : Request
    {
        /// <summary>
        /// ID hráče, pro kterého chceme získat podrobnosti
        /// </summary>
        private ulong playerID;

        public override RequestNames Name
        {
            get
            {
                return RequestNames.GET_PLAYER_DETAILS;
            }
        }

        /// <summary>
        /// Vytvoří novou instanci třídy <c>GetPlayerDetailsRequest</c>
        /// </summary>
        /// <param name="playerID">ID hráče, pro kterého chceme získat podrobnosti</param>
        public GetPlayerDetailsRequest(ulong playerID)
        {
            this.playerID = playerID;
        }

        public override string ToMessageString()
        {
            protocolWriter.beginMessage(MessageType.MT_REQUEST, Name.ToString());
            protocolWriter.writeValue("PLAYER_ID", playerID);

            protocolWriter.endMessage(true);
            return protocolWriter.copyMessage();
        }
    }

    /// <summary>
    /// Požadavek na získání seznamu hráčů s odpovídajícím jménem
    /// </summary>
    class GetPlayersListRequest : Request
    {
        /// <summary>
        /// Jméno hráče, nebo část jména těch hráčů, které chceme v seznamu získat
        /// </summary>
        private string playerName;

        public override RequestNames Name
        {
            get
            {
                return RequestNames.GET_PLAYERS_LIST;
            }
        }

        /// <summary>
        /// Vytvoří novou instanci třídy <c>GetPlayersListRequest</c>
        /// </summary>
        /// <param name="playerName">Jméno hráče, nebo část jména těch hráčů, které chceme v seznamu získat</param>
        public GetPlayersListRequest(string playerName)
        {
            this.playerName = playerName;
        }

        public override string ToMessageString()
        {
            protocolWriter.beginMessage(MessageType.MT_REQUEST, Name.ToString());
            protocolWriter.writeValue("PLAYER_NAME", playerName);

            protocolWriter.endMessage(true);
            return protocolWriter.copyMessage();
        }
    }

    /// <summary>
    /// Požadavek na generování nového hesla pro hráče
    /// </summary>
    class GeneratePasswordRequest : Request
    {
        /// <summary>
        /// ID hráče, pro kterého se má generovat nové heslo
        /// </summary>
        private ulong playerID;

        public override RequestNames Name
        {
            get
            {
                return RequestNames.GENERATE_PASSWORD;
            }
        }

        /// <summary>
        /// Vytvoří novou instanci třídy <c>GeneratePasswordRequest</c>
        /// </summary>
        /// <param name="playerID">ID hráče, pro kterého se má generovat nové heslo</param>
        public GeneratePasswordRequest(ulong playerID)
        {
            this.playerID = playerID;
        }

        public override string ToMessageString()
        {
            protocolWriter.beginMessage(MessageType.MT_REQUEST, Name.ToString());
            protocolWriter.writeValue("PLAYER_ID", playerID);

            protocolWriter.endMessage(true);
            return protocolWriter.copyMessage();
        }
    }

    /// <summary>
    /// Požadavek na zaslání zprávy pro hráče
    /// </summary>
    class SendMessageRequest : Request
    {
        /// <summary>
        /// ID hráče, kterému se má zaslat zpráva
        /// </summary>
        private ulong playerID;

        /// <summary>
        /// Cílové prostředí, do kterého se má zaslat zpráva
        /// </summary>
        private MessageTargets target;

        /// <summary>
        /// Skutečné tělo zasílané zprávy
        /// </summary>
        private string message;

        /// <summary>
        /// Předmět zasílané zprávy
        /// </summary>
        private string subject;

        public override RequestNames Name
        {
            get
            {
                return RequestNames.SEND_MESSAGE;
            }
        }

        /// <summary>
        /// Vytvoří novou instanci třídy <c>SendMessageRequest</c>
        /// </summary>
        /// <param name="playerID">ID hráče, kterému se má zaslat zpráva</param>
        /// <param name="subject">Předmět zasílané zprávy</param>
        /// <param name="message">Skutečné tělo zasílané zprávy</param>
        /// <param name="target">Cílové prostředí, do kterého se má zaslat zpráva</param>
        public SendMessageRequest(ulong playerID, string subject, string message, MessageTargets target)
        {
            this.playerID = playerID;
            this.subject = subject;
            this.message = message;
            this.target = target;
        }

        public override string ToMessageString()
        {
            protocolWriter.beginMessage(MessageType.MT_REQUEST, Name.ToString());
            protocolWriter.writeValue("PLAYER_ID", playerID);

            protocolWriter.endMessage(true);
            return protocolWriter.copyMessage();
        }
    }

    /// <summary>
    /// Požadavek na získání podrobností o konkrétní lodi
    /// </summary>
    class GetShipDetailsRequest : Request
    {
        /// <summary>
        /// ID lodě, pro kterou chceme získat podrobnosti
        /// </summary>
        private int shipID;

        public override RequestNames Name
        {
            get
            {
                return RequestNames.GET_SHIP_DETAILS;
            }
        }

        /// <summary>
        /// Vytvoří novou instanci třídy <c>GetShipDetailsRequest</c>
        /// </summary>
        /// <param name="shipID">ID lodě, pro kterou chceme získat podrobnosti</param>
        public GetShipDetailsRequest(int shipID)
        {
            this.shipID = shipID;
        }

        public override string ToMessageString()
        {
            protocolWriter.beginMessage(MessageType.MT_REQUEST, Name.ToString());
            protocolWriter.writeValue("SHIP_ID", shipID);

            protocolWriter.endMessage(true);
            return protocolWriter.copyMessage();
        }
    }

    /// <summary>
    /// Požadavek na získání podrobností o konkrétní základně
    /// </summary>
    class GetBaseDetailsRequest : Request
    {
        /// <summary>
        /// ID základny, pro kterou chceme získat podrobnosti
        /// </summary>
        private int baseID;

        public override RequestNames Name
        {
            get
            {
                return RequestNames.GET_SHIP_DETAILS;
            }
        }

        /// <summary>
        /// Vytvoří novou instanci třídy <c>GetBaseDetailsRequest</c>
        /// </summary>
        /// <param name="baseID">ID základny, pro kterou chceme získat podrobnosti</param>
        public GetBaseDetailsRequest(int baseID)
        {
            this.baseID = baseID;
        }

        public override string ToMessageString()
        {
            protocolWriter.beginMessage(MessageType.MT_REQUEST, Name.ToString());
            protocolWriter.writeValue("BASE_ID", baseID);

            protocolWriter.endMessage(true);
            return protocolWriter.copyMessage();
        }
    }

    /// <summary>
    /// Požadavek na odstranění lodi ze seznamu hráčových lodí
    /// </summary>
    class DeleteShipRequest : Request
    {
        /// <summary>
        /// ID lodě, kterou chceme odstranit
        /// </summary>
        private int shipID;

        public override RequestNames Name
        {
            get
            {
                return RequestNames.DELETE_SHIP_FROM_PLAYER;
            }
        }

        /// <summary>
        /// Vytvoří novou instanci třídy <c>DeleteShipRequest</c>
        /// </summary>
        /// <param name="shipID">ID lodě, kterou chceme odstranit</param>
        public DeleteShipRequest(int shipID)
        {
            this.shipID = shipID;
        }

        public override string ToMessageString()
        {
            protocolWriter.beginMessage(MessageType.MT_REQUEST, Name.ToString());
            protocolWriter.writeValue("SHIP_ID", shipID);

            protocolWriter.endMessage(true);
            return protocolWriter.copyMessage();
        }
    }

    /// <summary>
    /// Požadavek na odstranění základny ze seznamu hráčových základen
    /// </summary>
    class DeleteBaseRequest : Request
    {
        /// <summary>
        /// ID základny, kterou chceme odstranit
        /// </summary>
        private int baseID;

        public override RequestNames Name
        {
            get
            {
                return RequestNames.DELETE_BASE_FROM_PLAYER;
            }
        }

        /// <summary>
        /// Vytvoří novou instanci třídy <c>DeleteBaseRequest</c>
        /// </summary>
        /// <param name="shipID">ID základny, kterou chceme odstranit</param>
        public DeleteBaseRequest(int baseID)
        {
            this.baseID = baseID;
        }

        public override string ToMessageString()
        {
            protocolWriter.beginMessage(MessageType.MT_REQUEST, Name.ToString());
            protocolWriter.writeValue("BASE_ID", baseID);

            protocolWriter.endMessage(true);
            return protocolWriter.copyMessage();
        }
    }

    /// <summary>
    /// Požadavek na odstranění základny ze seznamu hráčových základen
    /// </summary>
    class DeleteItemRequest : Request
    {
        /// <summary>
        /// ID předmětu, který chceme odstranit
        /// </summary>
        private int itemID;

        /// <summary>
        /// Původ předmětu, odkud se má odstranit
        /// </summary>
        private ItemOrigins origin;

        public override RequestNames Name
        {
            get
            {
                if (origin == ItemOrigins.BASE)
                {
                    return RequestNames.DELETE_ITEM_FROM_BASE;
                }
                else if (origin == ItemOrigins.SHIP)
                {
                    return RequestNames.DELETE_ITEM_FROM_SHIP;
                }
                else
                {
                    return RequestNames.UNDEFINED;
                }
            }
        }

        /// <summary>
        /// Vytvoří novou instanci třídy <c>DeleteItemRequest</c>
        /// </summary>
        /// <param name="shipID">ID předmětu, který chceme odstranit</param>
        /// /// <param name="origin">Původ předmětu, odkud se má odstranit</param>
        public DeleteItemRequest(int itemID, ItemOrigins origin)
        {
            this.itemID = itemID;
        }

        public override string ToMessageString()
        {
            protocolWriter.beginMessage(MessageType.MT_REQUEST, Name.ToString());
            protocolWriter.writeValue("ITEM_ID", itemID);

            protocolWriter.endMessage(true);
            return protocolWriter.copyMessage();
        }
    }

    [System.AttributeUsage(
        AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Struct)
    ]
    public class ProtocolMapping : System.Attribute
    {
        private string name;

        public ProtocolMapping(string name)
        {
            this.name = name;
        }

        public String Name
        {
            get
            {
                return name;
            }
        }
    }

    [ProtocolMapping("ping")]
    class PingRequest
    {        
    }

    [ProtocolMapping("big")]
    class BigRequest
    {
        public class InnerClass
        {
            public int ahoj;
            public string nazdar;
        }

        public InnerClass[] inner = new InnerClass[2];
    }

    [ProtocolMapping("big")]
    class BigRequest2
    {
        public class InnerClass
        {
            public int ahoj;
            public string nazdar;
        }

        public InnerClass inner = new InnerClass();
    }

    [ProtocolMapping("ping")]
    public struct PingAnswer
    {
    }

    [ProtocolMapping("login")]
    public struct LoginRequest
    {
        [ProtocolMapping("loginname")]
        public string loginName;

        [ProtocolMapping("password")]
        public string password;
    }

    public struct PlayerInformation
    {
        [ProtocolMapping(Constants.REQUEST_ADMIN_PLAYERS_PLAYER_ITEM_ID)]
        public ulong id;

        [ProtocolMapping(Constants.REQUEST_ADMIN_PLAYERS_PLAYER_ITEM_LOGIN)]
        public string login;
    };

    [ProtocolMapping(Constants.REQUEST_ADMIN_PLAYERS)]
    public struct PlayersRequest
    {
    };

    [ProtocolMapping(Constants.REQUEST_ADMIN_PLAYERS)]
    public struct PlayersAnswer
    {
        [ProtocolMapping(Constants.REQUEST_ADMIN_PLAYERS_PLAYER_PREFIX)]
        public PlayerInformation[] players;
    };
}
