// =================================================================
//	Check for duplicate identifier.
// =================================================================
CClassMemberASTNode* CClassASTNode::FindClassMethod(CSemanter*					semanter, 
													std::string					identifier, 
													std::vector<CDataType*>		arguments, 
													bool						explicit_arguments,
													CASTNode*					ignoreNode, 
													CASTNode*					referenceNode)
{
	// Make sure this class is semanted.
	if (!Semanted)
	{
		Semant(semanter);
	}

	// Find all possible methods with the name.
	std::vector<CClassMemberASTNode*> nodes;

	CClassASTNode* scope = this;
	while (scope != NULL)
	{
		if (scope->Body != NULL)
		{
			for (auto iter = scope->Body->Children.begin(); iter != scope->Body->Children.end(); iter++)
			{
				CClassMemberASTNode* member = dynamic_cast<CClassMemberASTNode*>(*iter);
				if (member				!= NULL &&
					member->MemberType	== MemberType::Method && 
					member->Identifier	== identifier &&
					member				!= ignoreNode &&
					arguments.size()	<= member->Arguments.size())
				{

					// Has one of the other members overridcen this method already?
					bool alreadyExists = false;
					for (auto iter2 = nodes.begin(); iter2 != nodes.end(); iter2++)
					{
						CClassMemberASTNode* member2 = *iter2;
						if (member->Identifier == member2->Identifier &&
							member->Arguments.size() == member2->Arguments.size() &&
							member->IsVirtual == true && member2->IsOverride == true)
						{
							bool argsSame = true;

							for (unsigned int i = 0; i < member->Arguments.size(); i++)
							{
								CVariableStatementASTNode* arg = member->Arguments.at(i);
								CVariableStatementASTNode* arg2 = member2->Arguments.at(i);
								if (!arg->Type->IsEqualTo(semanter, arg2->Type))
								{
									argsSame = false;
									break;
								}
							}

							if (argsSame == true)
							{
								alreadyExists = true;
								break;
							}
						}
					}

					if (alreadyExists == false)
					{
						member->Semant(semanter);
						nodes.push_back(member);
					}
				}
			}
		}
		scope = scope->SuperClass;
	}

	// Try and find amatch!
	CClassMemberASTNode* match			= NULL;
	bool				 isExactMatch	= false;
	std::string			 errorMessage	= "";

	// Look for valid nodes.		
	for (auto iter = nodes.begin(); iter != nodes.end(); iter++)
	{
		CClassMemberASTNode* member = *iter;

		bool exact		= true;
		bool possible	= true;

		for (unsigned int i = 0; i < member->Arguments.size(); i++)
		{
			CVariableStatementASTNode* arg = member->Arguments.at(i);

			if (arguments.size() > member->Arguments.size())
			{
				continue;
			}

			if (i < arguments.size())
			{
				if (arguments.at(i)->IsEqualTo(semanter, arg->Type))
				{
					continue;
				}
				exact = false;

				if (!explicit_arguments && CCastExpressionASTNode::IsValidCast(semanter, arguments.at(i), arg->Type, false))// arguments.at(i)->CanCastTo(semanter, arg->Type))
				{
					continue;
				}
			}
			else if (arg->AssignmentExpression != NULL)
			{
				exact = false;
				if (!explicit_arguments)
				{
					continue;
				}
			}

			possible = false;
			break;
		}

		if (!possible)
		{
			continue;
		}

		if (exact == true)
		{
			if (isExactMatch == true)
			{
				semanter->GetContext()->FatalError(CStringHelper::FormatString("Found ambiguous reference to method of class '%s'. Reference could mean either '%s' or '%s'.", Identifier.c_str(), match->ToString().c_str(), member->ToString().c_str()),
													referenceNode == NULL ? Token : referenceNode->Token);
			}
			else
			{
				errorMessage	= "";
				match			= member;
				isExactMatch	= true;
			}
		}
		else
		{
			if (!isExactMatch)
			{
				if (match != NULL)
				{
					errorMessage = CStringHelper::FormatString("Found ambiguous reference to method of class '%s'. Reference could mean either '%s' or '%s'.", Identifier.c_str(), match->ToString().c_str(), member->ToString().c_str());
				}
				else
				{
					match = member;
				}
			}
		}
	}

	// Return?
	if (!isExactMatch)
	{
		if (errorMessage != "")
		{
			semanter->GetContext()->FatalError(errorMessage, referenceNode == NULL ? Token : referenceNode->Token);
		}
		if (explicit_arguments == true)
		{
			return NULL;
		}
	}

	// No match available? :S
	if (match == NULL)
	{
		return NULL;
	}

	// Return matched class.
	return match;
}