void CalendarMgr::SendCalendarEventInvite(CalendarInvite const& invite)
{
    CalendarEvent* calendarEvent = GetEvent(invite.GetEventId());
    time_t statusTime = invite.GetStatusTime();
    bool hasStatusTime = statusTime != 946684800;   // 01/01/2000 00:00:00

    ObjectGuid invitee = invite.GetInviteeGUID();
    Player* player = ObjectAccessor::FindConnectedPlayer(invitee);

    uint8 level = player ? player->getLevel() : sCharacterCache->GetCharacterLevelByGuid(invitee);

    WorldPacket data(SMSG_CALENDAR_EVENT_INVITE, 8 + 8 + 8 + 1 + 1 + 1 + (4) + 1);
    data << invitee.WriteAsPacked();
    data << uint64(invite.GetEventId());
    data << uint64(invite.GetInviteId());
    data << uint8(level);
    data << uint8(invite.GetStatus());
    data << uint8(hasStatusTime);
    if (hasStatusTime)
        data.AppendPackedTime(statusTime);
    data << uint8(invite.GetSenderGUID() != invite.GetInviteeGUID()); // false only if the invite is sign-up

    if (!calendarEvent) // Pre-invite
    {
        if (Player* playerSender = ObjectAccessor::FindConnectedPlayer(invite.GetSenderGUID()))
            playerSender->SendDirectMessage(&data);
    }
    else
    {
        if (calendarEvent->GetCreatorGUID() != invite.GetInviteeGUID()) // correct?
            SendPacketToAllEventRelatives(data, *calendarEvent);
    }
}
void CalendarMgr::SendCalendarEventRemovedAlert(CalendarEvent const& calendarEvent)
{
    WorldPacket data(SMSG_CALENDAR_EVENT_REMOVED_ALERT, 1 + 8 + 1);
    data << uint8(1); // FIXME: If true does not SignalEvent(EVENT_CALENDAR_ACTION_PENDING)
    data << uint64(calendarEvent.GetEventId());
    data.AppendPackedTime(calendarEvent.GetEventTime());

    SendPacketToAllEventRelatives(data, calendarEvent);
}
void CalendarMgr::SendCalendarEventModeratorStatusAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite)
{
    WorldPacket data(SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT, 8 + 8 + 1 + 1);
    data << invite.GetInviteeGUID().WriteAsPacked();
    data << uint64(invite.GetEventId());
    data << uint8(invite.GetRank());
    data << uint8(1); // Unk boolean - Display to client?

    SendPacketToAllEventRelatives(data, calendarEvent);
}
void CalendarMgr::SendCalendarEventInviteRemove(CalendarEvent const& calendarEvent, CalendarInvite const& invite, uint32 flags)
{
    WorldPacket data(SMSG_CALENDAR_EVENT_INVITE_REMOVED, 8 + 4 + 4 + 1);
    data << invite.GetInviteeGUID().WriteAsPacked();
    data << uint64(invite.GetEventId());
    data << uint32(flags);
    data << uint8(1); // FIXME

    SendPacketToAllEventRelatives(data, calendarEvent);
}
void CalendarMgr::SendCalendarEventRemovedAlert(CalendarEvent const* event)
{
    DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "SMSG_CALENDAR_EVENT_REMOVED_ALERT");
    WorldPacket data(SMSG_CALENDAR_EVENT_REMOVED_ALERT, 1 + 8 + 1);
    data << uint8(1);       // show pending alert?
    data << uint64(event->EventId);
    data << secsToTimeBitFields(event->EventTime);
    //data.hexlike();
    SendPacketToAllEventRelatives(data, event);
}
void CalendarMgr::SendCalendarEventModeratorStatusAlert(CalendarInvite const* invite)
{
    DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT");
    CalendarEvent const* event = invite->GetCalendarEvent();
    WorldPacket data(SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT, 8 + 8 + 1 + 1);
    data << invite->InviteeGuid.WriteAsPacked();
    data << uint64(event->EventId);
    data << uint8(invite->Rank);
    data << uint8(1); // Display pending action to client?
    //data.hexlike();
    SendPacketToAllEventRelatives(data, event);
}
void CalendarMgr::SendCalendarEventStatus(CalendarEvent const& calendarEvent, CalendarInvite const& invite)
{
    WorldPacket data(SMSG_CALENDAR_EVENT_STATUS, 8 + 8 + 4 + 4 + 1 + 1 + 4);
    data << invite.GetInviteeGUID().WriteAsPacked();
    data << uint64(calendarEvent.GetEventId());
    data.AppendPackedTime(calendarEvent.GetEventTime());
    data << uint32(calendarEvent.GetFlags());
    data << uint8(invite.GetStatus());
    data << uint8(invite.GetRank());
    data.AppendPackedTime(invite.GetStatusTime());

    SendPacketToAllEventRelatives(data, calendarEvent);
}
void CalendarMgr::SendCalendarEventInviteRemove(CalendarInvite const* invite, uint32 flags)
{
    DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "SMSG_CALENDAR_EVENT_INVITE_REMOVED");

    CalendarEvent const* event = invite->GetCalendarEvent();

    WorldPacket data(SMSG_CALENDAR_EVENT_INVITE_REMOVED, 8 + 4 + 4 + 1);
    data.appendPackGUID(invite->InviteeGuid);
    data << uint64(event->EventId);
    data << uint32(flags);
    data << uint8(1);       // show pending alert?
    //data.hexlike();
    SendPacketToAllEventRelatives(data, event);
}
void CalendarMgr::SendCalendarEventStatus(CalendarInvite const* invite)
{
    DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "SMSG_CALENDAR_EVENT_STATUS");
    WorldPacket data(SMSG_CALENDAR_EVENT_STATUS, 8 + 8 + 4 + 4 + 1 + 1 + 4);
    CalendarEvent const* event = invite->GetCalendarEvent();

    data << invite->InviteeGuid.WriteAsPacked();
    data << uint64(event->EventId);
    data << secsToTimeBitFields(event->EventTime);
    data << uint32(event->Flags);
    data << uint8(invite->Status);
    data << uint8(invite->Rank);
    data << secsToTimeBitFields(invite->LastUpdateTime);
    //data.hexlike();
    SendPacketToAllEventRelatives(data, event);
}
void CalendarMgr::SendCalendarEventUpdateAlert(CalendarEvent const& calendarEvent, time_t oldEventTime)
{
    WorldPacket data(SMSG_CALENDAR_EVENT_UPDATED_ALERT, 1 + 8 + 4 + 4 + 4 + 1 + 4 +
        calendarEvent.GetTitle().size() + calendarEvent.GetDescription().size() + 1 + 4 + 4);
    data << uint8(1);       // unk
    data << uint64(calendarEvent.GetEventId());
    data.AppendPackedTime(oldEventTime);
    data << uint32(calendarEvent.GetFlags());
    data.AppendPackedTime(calendarEvent.GetEventTime());
    data << uint8(calendarEvent.GetType());
    data << int32(calendarEvent.GetDungeonId());
    data << calendarEvent.GetTitle();
    data << calendarEvent.GetDescription();
    data << uint8(CALENDAR_REPEAT_NEVER);   // repeatable
    data << uint32(CALENDAR_MAX_INVITES);
    data << uint32(0);      // unk

    SendPacketToAllEventRelatives(data, calendarEvent);
}
void CalendarMgr::SendCalendarEventUpdateAlert(CalendarEvent const* event, time_t oldEventTime)
{
    DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "SMSG_CALENDAR_EVENT_UPDATED_ALERT");
    WorldPacket data(SMSG_CALENDAR_EVENT_UPDATED_ALERT, 1 + 8 + 4 + 4 + 4 + 1 + 4 +
                     event->Title.size() + event->Description.size() + 1 + 4 + 4);
    data << uint8(1);       // show pending alert?
    data << uint64(event->EventId);
    data << secsToTimeBitFields(oldEventTime);
    data << uint32(event->Flags);
    data << secsToTimeBitFields(event->EventTime);
    data << uint8(event->Type);
    data << int32(event->DungeonId);
    data << event->Title;
    data << event->Description;
    data << uint8(event->Repeatable);
    data << uint32(CALENDAR_MAX_INVITES);
    data << secsToTimeBitFields(event->UnknownTime);
    //data.hexlike();

    SendPacketToAllEventRelatives(data, event);
}
void CalendarMgr::SendCalendarEventInvite(CalendarInvite const* invite)
{
    CalendarEvent const* event = invite->GetCalendarEvent();

    time_t statusTime = invite->LastUpdateTime;
    bool preInvite = true;
    uint64 eventId = 0;
    if (event != nullptr)
    {
        preInvite = false;
        eventId = event->EventId;
    }

    Player* player = sObjectMgr.GetPlayer(invite->InviteeGuid);

    uint8 level = player ? player->getLevel() : Player::GetLevelFromDB(invite->InviteeGuid);
    DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "SMSG_CALENDAR_EVENT_INVITE");
    WorldPacket data(SMSG_CALENDAR_EVENT_INVITE, 8 + 8 + 8 + 1 + 1 + 1 + (preInvite ? 0 : 4) + 1);
    data << invite->InviteeGuid.WriteAsPacked();
    data << uint64(eventId);
    data << uint64(invite->InviteId);
    data << uint8(level);
    data << uint8(invite->Status);
    data << uint8(!preInvite);
    if (!preInvite)
        data << secsToTimeBitFields(statusTime);
    data << uint8(invite->SenderGuid != invite->InviteeGuid); // false only if the invite is sign-up (invitee create himself his invite)

    DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "SendCalendarInvit> %s senderGuid[%s], inviteeGuid[%s], EventId[" UI64FMTD "], Status[%u], InviteId[" UI64FMTD "]",
                     preInvite ? "is PreInvite," : "", invite->SenderGuid.GetString().c_str(), invite->InviteeGuid.GetString().c_str(), eventId, uint32(invite->Status), invite->InviteId);

    //data.hexlike();
    if (preInvite)
    {
        if (Player* sender = sObjectMgr.GetPlayer(invite->SenderGuid))
            sender->SendDirectMessage(&data);
    }
    else
        SendPacketToAllEventRelatives(data, event);
}