#include "IRCMemberEntry.h"
#include "IRCBase.h"
#include <algorithm>

IRCMemberEntry::IRCMemberEntry(std::shared_ptr<IRCMember> member, IRCBase& owner)
	: m_member(member)
	, m_owner(&owner)
{}

std::shared_ptr<IRCMember> IRCMemberEntry::member() const
{
	return m_member;
}

const std::string& IRCMemberEntry::modes() const
{
	return m_modes;
}

void IRCMemberEntry::addMode(char m)
{
	// Note: "PREFIX" is always present.
	// Value example: (ohv)@%+
	// Value is ordered with most significant first.
	const std::string& prefix = m_owner->isupport().find("PREFIX")->second;

	// Just interested in the mode letters (ie. ohv)
	const std::string validModes(prefix.begin() + 1, std::find(prefix.begin(), prefix.end(), ')'));
	auto order = [validModes](const char m) -> int {
		auto ret = validModes.find(m);
		return ret != std::string::npos ? static_cast<int>(ret)
										: -1;
	};

	auto mOrd = order(m);
	if (mOrd < 0)
		return;

	auto it = m_modes.begin();
	for (auto& mode : m_modes) {
		if (mode == m)
			return;
		else if (order(mode) >= mOrd)
			break;
		else
			++it;
	}
	m_modes.insert(it, m);
}

void IRCMemberEntry::delMode(char m)
{
	auto pos = m_modes.find_first_of(m);

    /*
     * Out-of-bounds can happen due to an IRC protocol bug. For example, where you join a channel which has
     * members that got both op (@) and voice (+) but only one of the symbols is visible from NAMES message
     * meaning that the client only picks up the "most significant" mode.
     * IRCv3 implements a fix for this which this client support, but not all servers do.
     * When a member then removes the unknown mode, we get this situation below;
    */
	if (pos != std::string::npos)
    	m_modes.erase(pos, 1);
}