void XMeansClustering::Cluster()
{
  if(this->Points.size() < this->MaxK)
  {
    std::stringstream ss;
    ss << "The number of points (" << this->Points.size()
       << " must be larger than the maximum number of clusters (" << this->MaxK << ")";
    throw std::runtime_error(ss.str());
  }

  // We must store the labels at the previous iteration to determine whether any labels changed at each iteration.
  std::vector<unsigned int> oldLabels(this->Points.size(), 0); // initialize to all zeros

  // Initialize the labels array
  this->Labels.resize(this->Points.size());

  do
  {
    
    // Save the old labels
    oldLabels = this->Labels;

  }while(this->ClusterCenters.size() < this->MaxK);

}
void CIRBuilder::visit( CExpID *n ) {
	if (n == nullptr)
	{
		std::cout << "in wisit CExpID is null";
		return;
	}
	LabelsSaver oldLabels(this);
	acceptIdAsTemp(n->id);
};
void CIRBuilder::visit( CExpINTEGER_LITERAL *n ){
	if (n == nullptr)
	{
		std::cout << "in wisit CExpINTEGER_LITERAL is null";
		return;
	}
	LabelsSaver oldLabels(this);
	lastNode = new IRExpCONST( n->integer_literal );
	lastType = "int";
};
void CIRBuilder::visit( CExpSingleOp *n ){
	if (n == nullptr)
	{
		std::cout << "in wisit CExpSingleOp is null";
		return;
	}
	LabelsSaver oldLabels(this);
	lastNode = new IRExpCONST( (n->val) ? 1 : 0 );
	lastType = "int";
};
void CIRBuilder::visit(CStatementPRINTLN* n) {
	if (n == nullptr)
	{
		std::cout << "in wisit CStatementPRINTLN is null";
		return;
	}
	LabelsSaver oldLabels(this);
	n->exp->accept(this);
	lastNode = new IRStmEXP(new IRExpCALL(new IRExpNAME(new CLabel("printLn")), new IRExpList(LastNodeAsIRExp())));
}
void CIRBuilder::visit( CExpTHIS *n ) {
	if (n == nullptr)
	{
		std::cout << "in wisit CExpTHIS is null";
		return;
	}
	LabelsSaver oldLabels(this);
	lastNode = new IRExpTEMP(frame->getThis());
	lastType = className;
};
void CIRBuilder::visit( CExpRests *n ) {
	if (n == nullptr)
	{
		std::cout << "in wisit CExpRests is null";
		return;
	}
	LabelsSaver oldLabels( this );
	for( size_t i = 0; i < n->expressions.size(); i++ ) {
		n->expressions[i]->accept( this );
	}
}
void CIRBuilder::visit( CExpUnaryMinus *n ) {
	if (n == nullptr)
	{
		std::cout << "in wisit CExpUnaryMinus is null";
		return;
	}
	LabelsSaver oldLabels( this );
	IRExpCONST * constNull = new IRExpCONST( 0 );
	n->exp->accept( this );
	lastNode = dynamic_cast<IRNode*>(new IRExpBINOP( '-', (IRExp*)constNull, (IRExp*)lastNode ));
	
}
void CIRBuilder::visit(CStatementASSIGNMENT* n) {
	if (n == nullptr)
	{
		std::cout << "in wisit CStatementASIGNMENT is null";
		return;
	}
	LabelsSaver oldLabels(this);
	acceptIdAsTemp(n->id);
	auto id_temp = LastNodeAsIRExp();
	n->exp->accept(this);
	lastNode = new IRStmMOVE(id_temp, LastNodeAsIRExp());
}
void CIRBuilder::visit(CExpNEWID *n) {
	if (n == nullptr)
	{
		std::cout << "in wisit CExpNEWID is null";
		return;
	}
	LabelsSaver oldLabels(this);
	lastNode = new IRExpCALL(
							 new IRExpNAME(new CLabel("malloc")), 
							 new IRExpList(new IRExpCONST(SymbolTable->classInfo[SymbolTable->getClassIndex(n->id)].vars.size())));
	lastType = n->id;
}
void CIRBuilder::visit(CExpNEWINT *n) {
	if (n == nullptr)
	{
		std::cout << "in wisit CExpNEWINT is null";
		return;
	}
	LabelsSaver oldLabels(this);
	n->exp->accept(this);
	lastNode = new IRExpCALL(new IRExpNAME(new CLabel("malloc")), new IRExpList(LastNodeAsIRExp()));

	lastType = "int";
}
void CIRBuilder::visit(CStatementSQUAREASSIGNMENT* n) {
	if (n == nullptr)
	{
		std::cout << "in wisit CStatementSQUEREASIGNMENT is null";
		return;
	}
	LabelsSaver oldLabels(this);
	n->expAssigned->accept(this);
	IRExp* Val = LastNodeAsIRExp();
	acceptIdAsTemp(n->id);
	auto id_temp = LastNodeAsIRExp();
	n->expInSquareBrackets->accept(this);
	lastNode = new IRStmMOVE(new IRExpMEM(new IRExpBINOP('+', id_temp, LastNodeAsIRExp())), Val);
}
void CIRBuilder::visit(CStatementBRACKETS* n) {
	if (n == nullptr)
	{
		std::cout << "in wisit CStatementBRACKETS is null";
		return;
	}
	LabelsSaver oldLabels(this);
	if (n->statements != nullptr)
	{
		n->statements->accept(this);
	}
	else
	{
		lastNode = nullptr;
	}
}
void CIRBuilder::visit(CExpExclamationMark *n) {
	if (n == nullptr)
	{
		std::cout << "in wisit CExpExclamationMark is null";
		return;
	}
	LabelsSaver oldLabels(this);
	auto t = ifTrueLabel;
	auto f = ifFalseLabel;
	ifFalseLabel = t;
	ifTrueLabel = f;
	n->exp->accept(this);
	//lastNode = new IRExpBINOP('^', LastNodeAsIRExp(), new IRExpCONST(1));
	ifFalseLabel = f;
	ifTrueLabel = t;

}
void CIRBuilder::visit(CStatementIF* ASTnode) {
	LabelsSaver oldLabels(this);
	/*
	SEQList
		cjump
		label iftrue
		stmiftrue?
		jump -> end
		label iffalse
		stmelse
		label_end

	*/
	auto stmList = new IRStmLIST();
	ifTrueLabel = new CLabel();
	ifFalseLabel = new CLabel();
	auto end = new CLabel();
	ASTnode->exp->accept(this);
	stmList->add(LastNodeAsIRStm());
	stmList->add(new IRStmLABEL(ifTrueLabel));
	if (ASTnode->statementIf != nullptr)
	{
		ASTnode->statementIf->accept(this);
		if (lastNode != nullptr)
		{
			stmList->add(LastNodeAsIRStm());
		}
	}
	stmList->add(new IRStmJUMP(end));
	stmList->add(new IRStmLABEL(ifFalseLabel));
	if (ASTnode->statementElse != nullptr)
	{
		ASTnode->statementElse->accept(this);
		if (lastNode != nullptr)
		{
			stmList->add(LastNodeAsIRStm());
		}
	}
	stmList->add(new IRStmLABEL(end));
	lastNode = stmList;
}
void CIRBuilder::visit(CStatementWHILE* n) {
	if (n == nullptr)
	{
		std::cout << "in wisit CStatementWHILE is null";
		return;
	}
	LabelsSaver oldLabels(this);
	/*
		label startLabel
		CJump
		label iftrue
		stm
		Jump -> startLabel
		label iffalse

	*/
	IRStmLIST* stmList = new IRStmLIST();
	CLabel* startLabel = new CLabel();
	ifTrueLabel = new CLabel();
	breakLabel = ifFalseLabel = new CLabel();
	stmList->add(new IRStmLABEL(startLabel));

	//exp
	n->exp->accept(this);
	if (dynamic_cast<IRExp*>(lastNode))
	{
		lastNode = new IRStmCJUMP('=', LastNodeAsIRExp(), new IRExpCONST(0), ifFalseLabel, ifTrueLabel);
	}
	stmList->add(LastNodeAsIRStm());

	stmList->add(new IRStmLABEL(ifTrueLabel));
	n->statementWhile->accept(this);
	if (lastNode != nullptr)
	{
		stmList->add(LastNodeAsIRStm());
	}
	stmList->add(new IRStmJUMP(startLabel));
	stmList->add(new IRStmLABEL(ifFalseLabel));
	lastNode = stmList;
}
int vtkKMeansClustering::RequestData(vtkInformation *vtkNotUsed(request),
                                     vtkInformationVector **inputVector,
                                     vtkInformationVector *outputVector)
{
    // Get the info objects
    vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
    vtkInformation *outInfoColoredPoints = outputVector->GetInformationObject(0);
    vtkInformation *outInfoClusterCenters = outputVector->GetInformationObject(1);

    // Get the input and ouptut
    vtkPolyData *input = vtkPolyData::SafeDownCast(
                             inInfo->Get(vtkDataObject::DATA_OBJECT()));

    this->Points->ShallowCopy(input->GetPoints());

    vtkPolyData *outputColoredPoints = vtkPolyData::SafeDownCast(
                                           outInfoColoredPoints->Get(vtkDataObject::DATA_OBJECT()));

    vtkPolyData *outputClusterCenters = vtkPolyData::SafeDownCast(
                                            outInfoClusterCenters->Get(vtkDataObject::DATA_OBJECT()));

    // Create a KDTree of the points
    this->KDTree->SetDataSet(input);
    this->KDTree->BuildLocator();

    // Seed a random number generator
    if(this->Random)
    {
        vtkMath::RandomSeed(time(NULL));
    }
    else
    {
        vtkMath::RandomSeed(0);
    }

    // Initialize the structure in which to store the cluster centers
    vtkSmartPointer<vtkPoints> clusterCenters =
        vtkSmartPointer<vtkPoints>::New();
    clusterCenters->SetNumberOfPoints(this->K);

    if(this->InitMethod == RANDOM)
    {
        RandomInit(clusterCenters);
    }
    else if(this->InitMethod == KMEANSPP) // http://en.wikipedia.org/wiki/K-means%2B%2B
    {
        MeansPPInit(clusterCenters);
    }
    else
    {
        std::cerr << "An invalid initialization method has been specified!" << std::endl;
        exit(-1);
    }

    /*
    // Output cluster centers
    std::cout << "Initial cluster centers: " << std::endl;
    for(unsigned int i = 0; i < clusterCenters->GetNumberOfPoints(); i++)
    {
    double p[3];
    clusterCenters->GetPoint(i, p);
    std::cout << "Cluster center " << i << " : " << p[0] << " " << p[1] << " " << p[2] << std::endl;
    }
    */

    // We must store the labels at the previous iteration to determine whether any labels changed at each iteration.
    std::vector<unsigned int> oldLabels(input->GetNumberOfPoints(), 0); // initialize to all zeros

    // Initialize the labels array
    this->Labels.resize(input->GetNumberOfPoints());

    // The current iteration number
    int iter = 0;

    // Track whether any labels changed in the last iteration
    bool changed = true;
    do
    {
        AssignLabels(input->GetPoints(), clusterCenters);

        EstimateClusterCenters(input->GetPoints(), clusterCenters);

        changed = CheckChanged(this->Labels, oldLabels);

        // Save the old labels
        oldLabels = this->Labels;
        iter++;
    } while(changed);
    //}while(iter < 100); // You could use this stopping criteria to make kmeans run for a specified number of iterations

    std::cout << "KMeans finished in " << iter << " iterations." << std::endl;

    // Create the color map
    this->ColorLookupTable->SetTableRange(0, this->K);
    this->ColorLookupTable->Build();

    CreateCentersPolyData(clusterCenters, outputClusterCenters);
    CreateOutputPointsPolyData(outputColoredPoints);

    return 1;
}
void CIRBuilder::visit(CExpBinary* n) {
	LabelsSaver oldLabels(this);
	int relop;
	if (n == nullptr)
	{
		std::cout << "in wisit CExBinary is null";
		return;
	}
	if (n->op == '<')
	{
		n->exp1->accept(this);
		IRExp* expLeft = LastNodeAsIRExp();
		n->exp2->accept(this);
		IRExp* expRigth = LastNodeAsIRExp();
		relop = IRStmCJUMP::LE;
		lastNode = new IRStmCJUMP(relop, expLeft, expRigth, ifTrueLabel, ifFalseLabel);
		lastType = "boolean";
		return;
	};

	/*
	IRStmSEQ:
		cjump(exp1,ifFalseLabel, iftrue)
		IRStmSEQ
			label iftrue
			cjump(exp2,ifFalseLabel, ifTrueLabel)
	*/
	if (n->op == '&')
	{
		const CLabel* ifExp1True = new CLabel();//this label is iftrue for exp1
		n->exp2->accept(this);
		IRStmSEQ* stmSEQ = new IRStmSEQ(new IRStmLABEL(ifExp1True),LastNodeAsIRStm());//label goes before exp2
		const CLabel* iftrue = ifTrueLabel;
		ifTrueLabel = ifExp1True;
		n->exp1->accept(this);
		lastNode = new IRStmSEQ(LastNodeAsIRStm(), stmSEQ);///first goes exp1(with falseCIRBuilder::val
		ifTrueLabel = iftrue;
		lastType = "boolean";
		return;
	};
	if (n->op == '+')
	{
		n->exp1->accept(this);
		IRExp* left = LastNodeAsIRExp();
		n->exp2->accept(this);
		IRExp* right = LastNodeAsIRExp();
		lastNode = new IRExpBINOP('+', left, right);
		lastType = "int";
		return;
	};
	if (n->op == '*')
	{
		n->exp1->accept(this);
		IRExp* left = LastNodeAsIRExp();
		n->exp2->accept(this);
		IRExp* right = LastNodeAsIRExp();
		lastNode = new IRExpBINOP('*', left, right);
		lastType = "int";
		return;
	};
	if (n->op == '-')
	{
		n->exp1->accept(this);
		IRExp* left = LastNodeAsIRExp();
		n->exp2->accept(this);
		IRExp* right = LastNodeAsIRExp();
		lastNode = new IRExpBINOP('-', left, right);
		lastType = "int";
		return;
	};
}