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

	// Only semant once.
	if (Semanted == true)
	{
		return this;
	}
	Semanted = true;
	
	// Semant expressions.
	LeftValue = ReplaceChild(LeftValue, LeftValue->Semant(semanter));
	if (StartExpression != NULL)
	{
		StartExpression  = ReplaceChild(StartExpression, StartExpression->Semant(semanter));
	}
	if (EndExpression != NULL)
	{
		EndExpression    = ReplaceChild(EndExpression, EndExpression->Semant(semanter));
	}

	// Get expression references.
	CExpressionBaseASTNode* lValueBase    = dynamic_cast<CExpressionBaseASTNode*>(LeftValue);
	CExpressionBaseASTNode* startExprBase = dynamic_cast<CExpressionBaseASTNode*>(StartExpression);
	CExpressionBaseASTNode* endExprBase   = dynamic_cast<CExpressionBaseASTNode*>(EndExpression);
	
	// Cast index to integer.
	if (startExprBase != NULL)
	{
		StartExpression = ReplaceChild(startExprBase, startExprBase->CastTo(semanter, new CIntDataType(Token), Token));
	}
	if (endExprBase != NULL)
	{
		EndExpression   = ReplaceChild(endExprBase,   endExprBase->CastTo  (semanter, new CIntDataType(Token), Token));
	}

	// Valid object to slice?
	std::vector<CDataType*> argumentTypes;
	argumentTypes.push_back(new CIntDataType(Token));
	argumentTypes.push_back(new CIntDataType(Token));

	CClassASTNode* classNode = lValueBase->ExpressionResultType->GetClass(semanter);
	CClassMemberASTNode* memberNode = classNode->FindClassMethod(semanter, "GetSlice", argumentTypes, true, NULL, NULL);

	if (memberNode == NULL)
	{
		semanter->GetContext()->FatalError("Data type does not support slicing, no GetSlice method defined.", Token);
	}
	else
	{
		ExpressionResultType = memberNode->ReturnType;
	}

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

	// Only semant once.
	if (Semanted == true)
	{
		return this;
	}
	Semanted = true;

	// Semant expressions.
	LeftValue  = ReplaceChild(LeftValue,   LeftValue->Semant(semanter));
	RightValue = ReplaceChild(RightValue, RightValue->Semant(semanter)); 

	// Get expression references.
	CExpressionBaseASTNode* leftValueBase  = dynamic_cast<CExpressionBaseASTNode*>(LeftValue);
	CExpressionBaseASTNode* rightValueBase = dynamic_cast<CExpressionBaseASTNode*>(RightValue);

	// Balance types.
	ExpressionResultType = semanter->BalanceDataTypes(leftValueBase->ExpressionResultType, 
														rightValueBase->ExpressionResultType);
	
	// Objects only permit equality operations.
	if (dynamic_cast<CObjectDataType*>(ExpressionResultType) != NULL &&
		Token.Type != TokenIdentifier::OP_EQUAL &&
		Token.Type != TokenIdentifier::OP_NOT_EQUAL)
	{
		semanter->GetContext()->FatalError(CStringHelper::FormatString("%s operator cannot be used on objects.", Token.Literal.c_str()), Token);
	}

	// Cast to resulting expression.
	LeftValue  = ReplaceChild(LeftValue,  leftValueBase->CastTo(semanter, ExpressionResultType, Token));
	RightValue = ReplaceChild(RightValue, rightValueBase->CastTo(semanter, ExpressionResultType, Token)); 

	CompareResultType = ExpressionResultType;
	ExpressionResultType = new CBoolDataType(Token);

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

	// Only semant once.
	if (Semanted == true)
	{
		return this;
	}
	Semanted = true;

	// Get expression representations.
	CExpressionBaseASTNode* left_hand_expr	 = dynamic_cast<CExpressionBaseASTNode*>(LeftValue);
	CExpressionBaseASTNode* right_hand_expr  = dynamic_cast<CExpressionBaseASTNode*>(RightValue);

	// Semant left hand node.
	LeftValue  = ReplaceChild(LeftValue,   LeftValue->Semant(semanter));
	
	// Make sure we can access class.
	CClassASTNode* accessClass = left_hand_expr->ExpressionResultType->GetClass(semanter);
	if (accessClass == NULL)
	{
		semanter->GetContext()->FatalError(CStringHelper::FormatString("Invalid use of scoping operator."), Token);		
	}

	// Check we can access this class from here.
	accessClass->CheckAccess(semanter, this);

	// NOTE: Do not r-value semant identifier, we want to process that ourselves.
	CIdentifierExpressionASTNode* identNode = dynamic_cast<CIdentifierExpressionASTNode*>(RightValue);

	// Semant arguments.
	std::vector<CDataType*> argument_types;
	std::string argument_types_string;
	for (std::vector<CASTNode*>::iterator iter = ArgumentExpressions.begin(); iter < ArgumentExpressions.end(); iter++)
	{
		CExpressionBaseASTNode* node = dynamic_cast<CExpressionBaseASTNode*>((*iter)->Semant(semanter));
		argument_types.push_back(node->ExpressionResultType);

		if (iter != ArgumentExpressions.begin())
		{
			argument_types_string += ", ";
		}
		argument_types_string += node->ExpressionResultType->ToString();

		(*iter) = node;
	}

	// Make sure the identifier represents a valid field.
	CClassMemberASTNode* declaration = accessClass->FindClassMethod(semanter, identNode->Token.Literal, argument_types, false, NULL, this);
	if (declaration == NULL)
	{
		semanter->GetContext()->FatalError(CStringHelper::FormatString("Undefined method '%s(%s)' in class '%s'.", identNode->Token.Literal.c_str(), argument_types_string.c_str(), accessClass->ToString().c_str()), Token);		
	}

// UPDATE: Abstract method calling is fine. Remember we won't be able to instantiate classes that do not override all abstract methods.
//	if (declaration->IsAbstract == true)
//	{
//		semanter->GetContext()->FatalError(CStringHelper::FormatString("Cannot call method '%s(%s)' in class '%s', method is abstract.", identNode->Token.Literal.c_str(), argument_types_string.c_str(), accessClass->ToString().c_str()), Token);		
//	}
	
	ResolvedDeclaration = declaration;

	// Check we can access this field from here.
	declaration->CheckAccess(semanter, this);

	// HACK: This is really hackish and needs fixing!
	if (dynamic_cast<CThisExpressionASTNode*>(LeftValue) != NULL &&
		declaration->IsStatic == true)
	{		
		LeftValue = ReplaceChild(LeftValue, new CClassRefExpressionASTNode(NULL, Token));
		LeftValue->Token.Literal = declaration->FindClassScope(semanter)->Identifier;
		LeftValue->Semant(semanter);

		left_hand_expr	 = dynamic_cast<CExpressionBaseASTNode*>(LeftValue);
	}

	// Add default arguments if we do not have enough args to call.
	if (declaration->Arguments.size() > ArgumentExpressions.size())
	{
		for (unsigned int i = ArgumentExpressions.size(); i < declaration->Arguments.size() ; i++)
		{
			CASTNode* expr = declaration->Arguments.at(i)->AssignmentExpression->Clone(semanter);
			AddChild(expr);
			ArgumentExpressions.push_back(expr);

			expr->Semant(semanter);
		}
	}
	
	// Cast all arguments to correct data types.
	int index = 0;
	for (std::vector<CASTNode*>::iterator iter = ArgumentExpressions.begin(); iter != ArgumentExpressions.end(); iter++)
	{
		CDataType* dataType = declaration->Arguments.at(index++)->Type;

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

	// If we are a class reference, we can only access static fields.
	bool isClassReference = (dynamic_cast<CClassReferenceDataType*>(left_hand_expr->ExpressionResultType) != NULL);
	if (isClassReference == true)
	{
		if (declaration->IsStatic == false)
		{
			semanter->GetContext()->FatalError(CStringHelper::FormatString("Cannot access instance method '%s' through class reference '%s'.", declaration->Identifier.c_str(), accessClass->ToString().c_str()), Token);	
		}
	}

	// If this is a constructor we are calling, make sure we are in a constructors scope, or its illegal!
	else
	{
		CClassMemberASTNode* methodScope = FindClassMethodScope(semanter);

		if (methodScope == NULL ||
			methodScope->IsConstructor == false)
		{
			if (declaration->IsConstructor == true)
			{
				semanter->GetContext()->FatalError("Calling constructors manually is only valid inside another constructors scope.", Token);	
			}
		}
	}

	// Resulting type is always our right hand type.
	ExpressionResultType = declaration->ReturnType;

	return this;
}
// =================================================================
//	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;
}