/*
 * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "CalendarPackets.h"
#include "CalendarMgr.h"
#include "WowTime.hpp"

ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Calendar::CalendarSendCalendarEventInfo const& eventInfo)
{
    data << uint64(eventInfo.EventID);
    data << uint8(eventInfo.EventType);
    data << MS::Utilities::WowTime::Encode(eventInfo.Date);
    data << uint32(eventInfo.Flags);
    data << int32(eventInfo.TextureID);
    data << eventInfo.EventGuildID;
    data << eventInfo.OwnerGuid;

    data.WriteString(eventInfo.EventName, 8);

    return data;
}

ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Calendar::CalendarSendCalendarRaidLockoutInfo const& lockoutInfo)
{
    data << uint64(lockoutInfo.InstanceID);
    data << int32(lockoutInfo.MapID);
    data << uint32(lockoutInfo.DifficultyID);
    data << uint32(lockoutInfo.ExpireTime);

    return data;
}

ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Calendar::CalendarSendCalendarInviteInfo const& inviteInfo)
{
    data << uint64(inviteInfo.EventID);
    data << uint64(inviteInfo.InviteID);
    data << uint8(inviteInfo.Status);
    data << uint8(inviteInfo.Moderator);
    data << uint8(inviteInfo.InviteType);
    data << inviteInfo.InviterGuid;

    return data;
}

ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Calendar::CalendarEventInviteInfo const& inviteInfo)
{
    data << inviteInfo.Guid;
    data << uint64(inviteInfo.InviteID);

    data << uint8(inviteInfo.Level);
    data << uint8(inviteInfo.Status);
    data << uint8(inviteInfo.Moderator);
    data << uint8(inviteInfo.InviteType);

    data << MS::Utilities::WowTime::Encode(inviteInfo.ResponseTime);

    data.WriteBits(inviteInfo.Notes.size(), 8);
    data.WriteString(inviteInfo.Notes);

    return data;
}

void WorldPackets::Calendar::CalendarGetEvent::Read()
{
    _worldPacket >> EventID;
}

void WorldPackets::Calendar::CalendarGuildFilter::Read()
{
    _worldPacket >> MinLevel;
    _worldPacket >> MaxLevel;
    _worldPacket >> MaxRankOrder;
}

ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Calendar::CalendarAddEventInviteInfo& invite)
{
    buffer >> invite.Guid;
    buffer >> invite.Status;
    buffer >> invite.Moderator;

    return buffer;
}

ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Calendar::CalendarAddEventInfo& addEventInfo)
{
    uint8 titleLength = buffer.ReadBits(8);
    uint16 descriptionLength = buffer.ReadBits(11);

    buffer >> addEventInfo.EventType;
    buffer >> addEventInfo.TextureID;
    addEventInfo.Time = buffer.ReadPackedTime();
    buffer >> addEventInfo.Flags;
    addEventInfo.Invites.resize(buffer.read<uint32>());

    addEventInfo.Title = buffer.ReadString(titleLength);
    addEventInfo.Description = buffer.ReadString(descriptionLength);

    for (WorldPackets::Calendar::CalendarAddEventInviteInfo& invite : addEventInfo.Invites)
        buffer >> invite;

    return buffer;
}

void WorldPackets::Calendar::CalendarAddEvent::Read()
{
    _worldPacket >> EventInfo;
    _worldPacket >> MaxSize;
}

void WorldPackets::Calendar::CalendarUpdateEvent::Read()
{
    _worldPacket >> EventInfo.EventID;
    _worldPacket >> EventInfo.ModeratorID;
    _worldPacket >> EventInfo.EventType;
    _worldPacket >> EventInfo.TextureID;
    EventInfo.Time = _worldPacket.ReadPackedTime();
    _worldPacket >> EventInfo.Flags;

    uint8 titleLen = _worldPacket.ReadBits(8);
    uint16 descLen = _worldPacket.ReadBits(11);

    EventInfo.Title = _worldPacket.ReadString(titleLen);
    EventInfo.Description = _worldPacket.ReadString(descLen);
    _worldPacket >> MaxSize;
}

void WorldPackets::Calendar::CalendarRemoveEvent::Read()
{
    _worldPacket >> EventID;
    _worldPacket >> ModeratorID;
    _worldPacket >> Flags;
}

void WorldPackets::Calendar::CalendarCopyEvent::Read()
{
    _worldPacket >> EventID;
    _worldPacket >> ModeratorID;
    Date = _worldPacket.ReadPackedTime();
}

void WorldPackets::Calendar::CalendarEventRSVP::Read()
{
    _worldPacket >> EventID;
    _worldPacket >> InviteID;
    _worldPacket >> Status;
}

void WorldPackets::Calendar::CalendarEventInvite::Read()
{
    _worldPacket >> EventID;
    _worldPacket >> ModeratorID;

    uint16 nameLen = _worldPacket.ReadBits(9);
    Creating = _worldPacket.ReadBit();
    IsSignUp = _worldPacket.ReadBit();

    Name = _worldPacket.ReadString(nameLen);
}

void WorldPackets::Calendar::CalendarEventSignUp::Read()
{
    _worldPacket >> EventID;
    Tentative = _worldPacket.ReadBit();
}

void WorldPackets::Calendar::CalendarRemoveInvite::Read()
{
    _worldPacket >> Guid;
    _worldPacket >> InviteID;
    _worldPacket >> ModeratorID;
    _worldPacket >> EventID;
}

void WorldPackets::Calendar::CalendarEventStatus::Read()
{
    _worldPacket >> Guid;
    _worldPacket >> EventID;
    _worldPacket >> InviteID;
    _worldPacket >> ModeratorID;
    _worldPacket >> Status;
}

void WorldPackets::Calendar::SetSavedInstanceExtend::Read()
{
    _worldPacket >> MapID;
    _worldPacket >> DifficultyID;
    Extend = _worldPacket.ReadBit();
}

void WorldPackets::Calendar::CalendarEventModeratorStatus::Read()
{
    _worldPacket >> Guid;
    _worldPacket >> EventID;
    _worldPacket >> InviteID;
    _worldPacket >> ModeratorID;
    _worldPacket >> Status;
}

WorldPacket const* WorldPackets::Calendar::SCalendarEventInvite::Write()
{
    _worldPacket << InviteGuid;
    _worldPacket << uint64(EventID);
    _worldPacket << uint64(InviteID);
    _worldPacket << uint8(Level);
    _worldPacket << uint8(Status);
    _worldPacket << uint8(Type);
    _worldPacket << MS::Utilities::WowTime::Encode(ResponseTime);

    _worldPacket.WriteBit(ClearPending);
    _worldPacket.FlushBits();

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarSendCalendar::Write()
{
    _worldPacket << MS::Utilities::WowTime::Encode(ServerTime);
    _worldPacket << static_cast<uint32>(Invites.size());
    _worldPacket << static_cast<uint32>(Events.size());
    _worldPacket << static_cast<uint32>(RaidLockouts.size());

    for (auto const& invite : Invites)
        _worldPacket << invite;

    for (auto const& lockout : RaidLockouts)
        _worldPacket << lockout;

    for (auto const& event : Events)
        _worldPacket << event;

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarSendEvent::Write()
{
    _worldPacket << uint8(EventType);
    _worldPacket << OwnerGuid;
    _worldPacket << uint64(EventID);
    _worldPacket << uint8(GetEventType);
    _worldPacket << int32(TextureID);
    _worldPacket << uint32(Flags);
    _worldPacket << MS::Utilities::WowTime::Encode(Date);
    _worldPacket << uint32(LockDate);
    _worldPacket << EventGuildID;

    _worldPacket << static_cast<uint32>(Invites.size());
    _worldPacket.WriteBits(EventName.size(), 8);
    _worldPacket.WriteBits(Description.size(), 11);
    _worldPacket.FlushBits();

    for (auto const& invite : Invites)
        _worldPacket << invite;

    _worldPacket.WriteString(EventName);
    _worldPacket.WriteString(Description);

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarEventInviteAlert::Write()
{
    _worldPacket << uint64(EventID);
    _worldPacket << MS::Utilities::WowTime::Encode(Date);
    _worldPacket << uint32(Flags);
    _worldPacket << uint8(EventType);
    _worldPacket << int32(TextureID);
    _worldPacket << EventGuildID;
    _worldPacket << uint64(InviteID);
    _worldPacket << uint8(Status);
    _worldPacket << uint8(ModeratorStatus);

    _worldPacket << InvitedByGuid;
    _worldPacket << OwnerGuid;

    _worldPacket.WriteBits(EventName.size(), 8);
    _worldPacket.WriteString(EventName);

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarEventInviteStatus::Write()
{
    _worldPacket << InviteGuid;
    _worldPacket << uint64(EventID);
    _worldPacket << MS::Utilities::WowTime::Encode(Date);
    _worldPacket << uint32(Flags);
    _worldPacket << uint8(Status);
    _worldPacket << MS::Utilities::WowTime::Encode(ResponseTime);

    _worldPacket.WriteBit(ClearPending);
    _worldPacket.FlushBits();

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarEventInviteRemoved::Write()
{
    _worldPacket << InviteGuid;
    _worldPacket << uint64(EventID);
    _worldPacket << uint32(Flags);

    _worldPacket.WriteBit(ClearPending);
    _worldPacket.FlushBits();

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarEventInviteModeratorStatus::Write()
{
    _worldPacket << InviteGuid;
    _worldPacket << uint64(EventID);
    _worldPacket << uint8(Status);

    _worldPacket.WriteBit(ClearPending);
    _worldPacket.FlushBits();

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarEventInviteRemovedAlert::Write()
{
    _worldPacket << uint64(EventID);
    _worldPacket << MS::Utilities::WowTime::Encode(Date);
    _worldPacket << uint32(Flags);
    _worldPacket << uint8(Status);

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarEventUpdatedAlert::Write()
{
    _worldPacket << uint64(EventID);

    _worldPacket << MS::Utilities::WowTime::Encode(OriginalDate);
    _worldPacket << MS::Utilities::WowTime::Encode(Date);
    _worldPacket << uint32(LockDate);
    _worldPacket << uint32(Flags);
    _worldPacket << uint32(TextureID);
    _worldPacket << uint8(EventType);

    _worldPacket.WriteBits(EventName.size(), 8);
    _worldPacket.WriteBits(Description.size(), 11);
    _worldPacket.WriteBit(ClearPending);
    _worldPacket.WriteString(EventName);
    _worldPacket.WriteString(Description);

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarEventRemovedAlert::Write()
{
    _worldPacket << uint64(EventID);
    _worldPacket << MS::Utilities::WowTime::Encode(Date);

    _worldPacket.WriteBit(ClearPending);
    _worldPacket.FlushBits();

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarSendNumPending::Write()
{
    _worldPacket << uint32(NumPending);

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarCommandResult::Write()
{
    _worldPacket << uint8(Command);
    _worldPacket << uint8(Result);

    _worldPacket.WriteBits(Name.size(), 9);
    _worldPacket.WriteString(Name);

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarRaidLockoutAdded::Write()
{
    _worldPacket << uint64(InstanceID);
    _worldPacket << MS::Utilities::WowTime::Encode(ServerTime);
    _worldPacket << int32(MapID);
    _worldPacket << uint32(DifficultyID);
    _worldPacket << int32(TimeRemaining);

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarRaidLockoutRemoved::Write()
{
    _worldPacket << uint64(InstanceID);
    _worldPacket << int32(MapID);
    _worldPacket << uint32(DifficultyID);

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarRaidLockoutUpdated::Write()
{
    _worldPacket << uint32(ServerTime);
    _worldPacket << int32(MapID);
    _worldPacket << uint32(DifficultyID);
    _worldPacket << int32(NewTimeRemaining);
    _worldPacket << int32(OldTimeRemaining);

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarEventInitialInvites::Write()
{
    _worldPacket << static_cast<uint32>(Invites.size());
    for (auto const& invite : Invites)
    {
        _worldPacket << invite.InviteGuid;
        _worldPacket << uint8(invite.Level);
    }

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarEventInviteStatusAlert::Write()
{
    _worldPacket << uint64(EventID);
    _worldPacket << MS::Utilities::WowTime::Encode(Date);
    _worldPacket << uint32(Flags);
    _worldPacket << uint8(Status);

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarEventInviteNotesAlert::Write()
{
    _worldPacket << uint64(EventID);

    _worldPacket.WriteBits(Notes.size(), 8);
    _worldPacket.WriteString(Notes);

    return &_worldPacket;
}

WorldPacket const* WorldPackets::Calendar::CalendarEventInviteNotes::Write()
{
    _worldPacket << InviteGuid;
    _worldPacket << uint64(EventID);

    _worldPacket.WriteBits(Notes.size(), 8);
    _worldPacket.WriteBit(ClearPending);
    _worldPacket.WriteString(Notes);

    return &_worldPacket;
}

void WorldPackets::Calendar::CalendarComplain::Read()
{
    _worldPacket >> InvitedByGUID;
    _worldPacket >> EventID;
    _worldPacket >> InviteID;
}
