// =================================================================
//	Performs semantic analysis on this node.
// =================================================================
CASTNode* CNewExpressionASTNode::Semant(CSemanter* semanter)
{
	SEMANT_TRACE("CNewExpressionASTNode");

	// Semant data types.
	DataType = DataType->Semant(semanter, this);

	// Semant arguments.
	std::vector<CDataType*> argument_datatypes;
	for (auto iter = ArgumentExpressions.begin(); iter != ArgumentExpressions.end(); iter++)
	{
		CExpressionBaseASTNode* node = dynamic_cast<CExpressionBaseASTNode*>(*iter);
		node = dynamic_cast<CExpressionBaseASTNode*>(node->Semant(semanter));
		argument_datatypes.push_back(node->ExpressionResultType);
		(*iter) = node;
	}

	// Semant array initializer.
	if (ArrayInitializer != NULL)
	{
		ArrayInitializer->Semant(semanter);
	}

	// Create new array of objects.
	if (IsArray == true)
	{
		// Cast all arguments to correct data types.
		int index = 0;
		for (auto iter = ArgumentExpressions.begin(); iter != ArgumentExpressions.end(); iter++)
		{
			CExpressionBaseASTNode* subnode = dynamic_cast<CExpressionBaseASTNode*>(*iter);
			subnode->Parent->ReplaceChild(subnode, subnode = dynamic_cast<CExpressionBaseASTNode*>(subnode->CastTo(semanter, new CIntDataType(Token), Token)));
			(*iter) = subnode;
		}

		ExpressionResultType = DataType;
	}

	// Create a new object!
	else
	{		
		// Make sure DT is a class.
		if (dynamic_cast<CObjectDataType*>(DataType) == NULL)
		{
			semanter->GetContext()->FatalError(CStringHelper::FormatString("Cannot instantiate primitive data type '%s'.", DataType->ToString().c_str()), Token);
		}

		// Check class is valid.
		CClassASTNode* classNode = DataType->GetClass(semanter);
		if (classNode->IsInterface == true)
		{
			semanter->GetContext()->FatalError(CStringHelper::FormatString("Cannot instantiate interface '%s'.", DataType->ToString().c_str()), Token);
		}
		if (classNode->IsAbstract == true)
		{
			semanter->GetContext()->FatalError(CStringHelper::FormatString("Cannot instantiate abstract class '%s'.", DataType->ToString().c_str()), Token);
		}
		if (classNode->IsStatic == true)
		{
			semanter->GetContext()->FatalError(CStringHelper::FormatString("Cannot instantiate static class '%s'.", DataType->ToString().c_str()), Token);
		}
		if (classNode->IsNative == true)
		{
			semanter->GetContext()->FatalError(CStringHelper::FormatString("Cannot instantiate native class '%s'.", DataType->ToString().c_str()), Token);
		}

		classNode->IsInstanced = true;
		classNode->InstancedBy = this;

		// Check we can find a constructor.
		CClassMemberASTNode* node = classNode->FindClassMethod(semanter, classNode->Identifier, argument_datatypes, false);
		if (node == NULL)
		{
			semanter->GetContext()->FatalError(CStringHelper::FormatString("No suitable constructor to instantiate class '%s'.", DataType->ToString().c_str()), Token);
		}

	//	if (classNode->Identifier == "MapPair")
	//	{
	//		printf("WUT");
	//	}

		ResolvedConstructor = node;

		// Cast all arguments to correct data types.
		int index = 0;
		for (auto iter = ArgumentExpressions.begin(); iter != ArgumentExpressions.end(); iter++)
		{
			CDataType* dataType = node->Arguments.at(index++)->Type;

			CExpressionBaseASTNode* subnode = dynamic_cast<CExpressionBaseASTNode*>(*iter);
			CExpressionBaseASTNode* subnode_casted = dynamic_cast<CExpressionBaseASTNode*>(subnode->CastTo(semanter, dataType, Token));
			this->ReplaceChild(subnode, subnode_casted);

			(*iter) = subnode_casted;
		}

		ExpressionResultType = DataType;
	}

	// Check we can create new object.
	if (dynamic_cast<CArrayDataType*>(DataType) == NULL)
	{		
		// Check class is valid.
		CClassASTNode* classNode = DataType->GetClass(semanter);

		// Check we can find a constructor.
		CClassMemberASTNode* node = classNode->FindClassMethod(semanter, classNode->Identifier, argument_datatypes, false);
		if (node == NULL)
		{
			semanter->GetContext()->FatalError(CStringHelper::FormatString("Could not find suitable constructor to instantiate class '%s'.", DataType->ToString().c_str()), Token);
		}
	}

	return this;
}