#ifndef INCLUDED_ALLNETMESSAGES
#define INCLUDED_ALLNETMESSAGES

#include "ps/CStr.h"
#include "scripting/JSSerialization.h"

enum ENetMessageType
{
    /*
        All Message Types should be put here. Never change the order of this
        list.
        First, all negative types are only for internal/local use and may never
        be sent over the network.
        After that, all "real" network messages are listed, giving them a value
        from 0 and upwards (*unique* value)
    */
    /**
     * A special message that contains a PS_RESULT code, used for delivery of
     * OOB error status messages from a CMessageSocket
     */
    NMT_ERROR=-256,
    /**
     * The message socket connect attempt is complete
     */
    NMT_CONNECT_COMPLETE,
    /**
     * Close the message socket
     */
    NMT_CLOSE_REQUEST,
    /**
     * An invalid message type, representing an uninitialized message.
     */
    NMT_NONE=0,
    
    /* Handshake Stage */
    NMT_ServerHandshake,
    NMT_ClientHandshake,
    NMT_ServerHandshakeResponse,
    /* Authentication Stage */
    NMT_Authenticate,
    NMT_AuthenticationResult,
    /* Common Messages, stage 3-5 */
    NMT_ChatMessage,
    /* Pre-Game Stage */
    NMT_ClientConnect,
    NMT_ClientDisconnect,
    NMT_SetGameConfig,
    NMT_AssignPlayerSlot,
    NMT_SetPlayerConfig,
    NMT_FilesRequired,
    NMT_FileRequest,
    NMT_FileChunk,
    NMT_FileChunkAck,
    NMT_FileProgress,
    NMT_StartGame,
    /* In-Game Stage */
    NMT_EndCommandBatch,
    NMT_Goto, NMT_COMMAND_FIRST=NMT_Goto,
    NMT_Patrol,
    NMT_AddWaypoint,
    NMT_Generic,
    NMT_Produce,
    NMT_PlaceObject,
    NMT_Run,
    NMT_NotifyRequest,
    NMT_FormationGoto,
    NMT_FormationGeneric,

    NMT_COMMAND_LAST,
    /* Post-Game Stage */

    /**
     * One higher than the highest value of any message type
     */
    NMT_LAST // Always put this last in the list
};

/**
    Only applies to NMT_AuthenticationResult (as of now).
*/
enum ENetResultCodes
{
    NRC_OK,
    NRC_PasswordInvalid,
    NRC_NickTaken,
    NRC_NickInvalid,
};

// These constants (magic numbers) are highly arbitrary, but have been chosen
// such that they should be unlikely to stumble across randomly.

// in network byte order: 'P', 's', 0x01, '?'
#define PS_PROTOCOL_MAGIC 0x5073013f
// in network byte order: 'P', 'c', 0x01, '!'
#define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121

// At a later date, there should be a standard for assigning protocol version
// numbers. For now, this also highly arbitrary number will hold its place
// 1.1.2
#define PS_PROTOCOL_VERSION 0x01010002

// 0x5073 = decimal 20595
// The "symbolism" is that the two bytes of the port number in network byte
// order is 'P' 's'
#define PS_DEFAULT_PORT 0x5073

// Chat Recipient Constants
enum
{
    // Any chat recipients lower than this one is an actual session ID
    PS_CHAT_RCP_FIRST_SPECIAL=0xfffd,
    PS_CHAT_RCP_ENEMIES=0xfffd,
    PS_CHAT_RCP_ALLIES=0xfffe,
    PS_CHAT_RCP_ALL=0xFFFF,
};

enum
{
    PS_ASSIGN_OPEN,
    PS_ASSIGN_CLOSED,
    PS_ASSIGN_AI,
    PS_ASSIGN_SESSION
};

#endif // #ifndef _AllNetMessage_H

#ifdef CREATING_NMT

#define ALLNETMSGS_DONT_CREATE_NMTS
#define START_NMT_CLASS_(_nm) START_NMT_CLASS(C ## _nm, NMT_ ## _nm)
#define DERIVE_NMT_CLASS_(_base, _nm) START_NMT_CLASS_DERIVED(C ## _base, C ## _nm, NMT_ ## _nm)

START_NMTS()

START_NMT_CLASS_(ServerHandshake)
    NMT_FIELD_INT(m_Magic, u32, 4)
    NMT_FIELD_INT(m_ProtocolVersion, u32, 4)
    NMT_FIELD_INT(m_SoftwareVersion, u32, 4)
END_NMT_CLASS()

START_NMT_CLASS_(ClientHandshake)
    NMT_FIELD_INT(m_MagicResponse, u32, 4)
    NMT_FIELD_INT(m_ProtocolVersion, u32, 4)
    NMT_FIELD_INT(m_SoftwareVersion, u32, 4)
END_NMT_CLASS()

START_NMT_CLASS_(ServerHandshakeResponse)
    NMT_FIELD_INT(m_UseProtocolVersion, u32, 4)
    NMT_FIELD_INT(m_Flags, u32, 4)
    NMT_FIELD(CStrW, m_Message)
END_NMT_CLASS()

START_NMT_CLASS_(AuthenticationResult)
    NMT_FIELD_INT(m_Code, u32, 4)
    NMT_FIELD_INT(m_SessionID, u32, 2)
    NMT_FIELD(CStrW, m_Message)
END_NMT_CLASS()

START_NMT_CLASS_(Authenticate)
    NMT_FIELD(CStrW, m_Name)
    //NMT_FIELD(CPasswordHash, m_Password)
    NMT_FIELD(CStrW, m_Password)
END_NMT_CLASS()

START_NMT_CLASS_(ChatMessage)
    NMT_FIELD(CStrW, m_Sender)
    NMT_FIELD_INT(m_Recipient, u32, 2)
    NMT_FIELD(CStrW, m_Message)
END_NMT_CLASS()

START_NMT_CLASS_(ClientConnect)
    NMT_START_ARRAY(m_Clients)
        NMT_FIELD_INT(m_SessionID, u32, 2)
        NMT_FIELD(CStrW, m_Name)
    NMT_END_ARRAY()
END_NMT_CLASS()

START_NMT_CLASS_(ClientDisconnect)
    NMT_FIELD_INT(m_SessionID, u32, 2)
END_NMT_CLASS()

START_NMT_CLASS_(SetGameConfig)
    NMT_START_ARRAY(m_Values)
        NMT_FIELD(CStrW, m_Name)
        NMT_FIELD(CStrW, m_Value)
    NMT_END_ARRAY()
END_NMT_CLASS()

START_NMT_CLASS_(AssignPlayerSlot)
    NMT_FIELD_INT(m_SlotID, u32, 2)
    NMT_FIELD_INT(m_Assignment, u32, 1)
    NMT_FIELD_INT(m_SessionID, u32, 2) // Only applicable for PS_ASSIGN_SESSION
END_NMT_CLASS()

START_NMT_CLASS_(SetPlayerConfig)
    NMT_FIELD_INT(m_PlayerID, u32, 2)
    NMT_START_ARRAY(m_Values)
        NMT_FIELD(CStrW, m_Name)
        NMT_FIELD(CStrW, m_Value)
    NMT_END_ARRAY()
END_NMT_CLASS()

START_NMT_CLASS_(StartGame)
END_NMT_CLASS()

START_NMT_CLASS_(EndCommandBatch)
    NMT_FIELD_INT(m_TurnLength, u32, 2)
END_NMT_CLASS()

START_NMT_CLASS(CNetCommand, NMT_NONE)
    NMT_FIELD(CEntityList, m_Entities)
    NMT_FIELD_INT(m_IsQueued, u32, 1)
END_NMT_CLASS()

DERIVE_NMT_CLASS_(NetCommand, Goto)
    NMT_FIELD_INT(m_TargetX, u32, 2)
    NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()

DERIVE_NMT_CLASS_(NetCommand, Run)
    NMT_FIELD_INT(m_TargetX, u32, 2)
    NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()

DERIVE_NMT_CLASS_(NetCommand, Patrol)
    NMT_FIELD_INT(m_TargetX, u32, 2)
    NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()

DERIVE_NMT_CLASS_(NetCommand, AddWaypoint)
    NMT_FIELD_INT(m_TargetX, u32, 2)
    NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()

DERIVE_NMT_CLASS_(NetCommand, Generic)
    NMT_FIELD(HEntity, m_Target)
    NMT_FIELD_INT(m_Action, u32, 4)
END_NMT_CLASS()

DERIVE_NMT_CLASS_(NetCommand, Produce)
    NMT_FIELD_INT(m_Type, u32, 4)
    NMT_FIELD(CStrW, m_Name)
END_NMT_CLASS()

DERIVE_NMT_CLASS_(NetCommand, PlaceObject)
    NMT_FIELD(CStrW, m_Template)
    NMT_FIELD_INT(m_X, u32, 4)
    NMT_FIELD_INT(m_Y, u32, 4)
    NMT_FIELD_INT(m_Z, u32, 4)
    NMT_FIELD_INT(m_Angle, u32, 4)      // Orientation angle
END_NMT_CLASS()

DERIVE_NMT_CLASS_(NetCommand, NotifyRequest)
    NMT_FIELD(HEntity, m_Target)
    NMT_FIELD_INT(m_Action, u32, 4)
END_NMT_CLASS()

DERIVE_NMT_CLASS_(NetCommand, FormationGoto)
    NMT_FIELD_INT(m_TargetX, u32, 2)
    NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()

DERIVE_NMT_CLASS_(NetCommand, FormationGeneric)
    NMT_FIELD(HEntity, m_Target)
    NMT_FIELD_INT(m_Action, u32, 4)
END_NMT_CLASS()

END_NMTS()

#else
#ifndef ALLNETMSGS_DONT_CREATE_NMTS

#ifdef ALLNETMSGS_IMPLEMENT
#define NMT_CREATOR_IMPLEMENT
#endif

#define NMT_CREATE_HEADER_NAME "AllNetMessages.h"
#include "NMTCreator.h"

#endif // #ifndef ALLNETMSGS_DONT_CREATE_NMTS
#endif // #ifdef CREATING_NMT