int main(int argc, const char* argv[]) {
    // set floating-point output formatting
    std::cout << std::fixed << std::setprecision(2);

    // create derived-class objects
    SalariedEmployee salariedEmployee("John", "Smi.hpp", "111-11-1111", 800);
    CommissionEmployee commissionEmployee("Sue", "Jones", "333-33-3333", 10000,
                                          .06);
    BasePlusCommissionEmployee basePlusCommissionEmployee(
        "Bob", "Lewis", "444-44-4444", 5000, .04, 300);

    std::cout << "Employees processed individually using static binding:\n\n";

    // output each Employee's information and earnings using static binding
    salariedEmployee.print();
    std::cout << "\nearned $" << salariedEmployee.earnings() << "\n\n";
    commissionEmployee.print();
    std::cout << "\nearned $" << commissionEmployee.earnings() << "\n\n";
    basePlusCommissionEmployee.print();
    std::cout << "\n\nearned $" << basePlusCommissionEmployee.earnings()
              << "\n\n";

    // create vector of three base-class pointers
    std::vector<Employee*> employees(3);

    // initialise vector with Employees
    employees[0] = &salariedEmployee;
    employees[1] = &commissionEmployee;
    employees[2] = &basePlusCommissionEmployee;

    std::cout << "Employees processed polymorphically via dynamic binding:\n\n";

    // call virtualViaPointer to print each Employee's information
    // and earnings using dynamic binding
    std::cout << "Virtual function call made off base-class pointers:\n\n";

    for (size_t i = 0; i < employees.size(); ++i) {
        virtualViaPointer(employees[i]);
    }

    // call virtualViaReference to print each Employee's information
    // and earnings using dynamic binding
    std::cout << "Virtual function calls made off base-class references:\n\n";

    for (size_t i = 0; i < employees.size(); ++i) {
        virtualViaReference(*employees[i]);  // not dereferencing
    }

    return 0;
}
int main()
{
	// set floating-point output formatting
	cout << fixed << setprecision(2);

	// create vector of base-class pointers
	vector < Employee * > employees(3);

	// initialize vector with Employees
	employees[0] = new SalariedEmployee("John", "Smith", "111-11-1111", 7, 10, 1957, 800);
	employees[1] = new CommissionEmployee("Sue", "Jones", "333-33-3333", 3, 8, 1971, 10000, .06); // brithday month so should get bonus
	employees[2] = new BasePlusCommissionEmployee("Bob", "Lewis", "444-44-4444", 9, 25, 1968, 5000, .04, 300);

	int month = determineMonth();
	
	cout << "Employees processed polymorphically using dynamic binding" << "\n\n";
	
	cout << "Virtual function calls made off base-class pointers: \n\n";
	
	// polymorphically process each element in vector employees
	for (size_t i = 0; i < employees.size(); ++i)
	{
		virtualViaPointer(employees[i]); // output employee information
		
		// get current employee's birthday
		Date birthday = employees[i]->getBirthDate();

		// if current month is employee's birthday month, add $100 bonus to payroll amount
		if (birthday.getMonth() == month)
			cout << "\nHappy Birthday!\nYou recieved an extra $100 bonus \nearned with bonus $"
			<< (employees[i]->earnings() + 100.0) << endl << endl;
		else
			cout << endl << endl;

	}
	
	cout << "Virtual function calls made off base-class references: \n\n";
	
	for (size_t i = 0; i < employees.size(); ++i)
	{
		virtualViaReference(*employees[i]); // output employee information

		// get current employee's birthday
		Date birthday = employees[i]->getBirthDate();

		// if current month is employee's birthday month, add $100 bonus to payroll amount
		if (birthday.getMonth() == month)
			cout << "\nHappy Birthday!\nYou recieved an extra $100 bonus \nearned with bonus $"
			<< (employees[i]->earnings() + 100.0) << endl << endl;
		else
			cout << endl << endl;

	}
	
	cout << endl;

	// release objects pointed to by vector’s elements
	for (size_t j = 0; j < employees.size(); ++j)
	{
		// output class name
		cout << "deleting object of " << typeid(*employees[j]).name() << endl;

		delete employees[j];
	}
	
	getch();

	return 0;
} 
    void processingAsteriskTest()
    {
        csvsqldb::FunctionRegistry functions;
        csvsqldb::SQLParser parser(functions);

        csvsqldb::ASTNodePtr node = parser.parse(
        "CREATE TABLE employees(emp_no INTEGER,birth_date DATE NOT NULL,first_name VARCHAR(25) NOT NULL,last_name VARCHAR(50) "
        "NOT NULL,gender CHAR,hire_date DATE,PRIMARY KEY(emp_no))");
        MPF_TEST_ASSERT(node);
        MPF_TEST_ASSERT(std::dynamic_pointer_cast<csvsqldb::ASTCreateTableNode>(node));
        csvsqldb::ASTCreateTableNodePtr createNode = std::dynamic_pointer_cast<csvsqldb::ASTCreateTableNode>(node);

        csvsqldb::TableData tabledata = csvsqldb::TableData::fromCreateAST(createNode);
        csvsqldb::FileMapping mapping;

        csvsqldb::Database database("/tmp", mapping);
        database.addTable(tabledata);

        node =
        parser.parse("SELECT * FROM employees emp WHERE emp_no BETWEEN 100 AND 9999 AND emp.birth_date > DATE'1960-01-01'");

        csvsqldb::SymbolTablePtr symbolTable = node->symbolTable();
        //        symbolTable->dump();
        //        std::cout << std::endl;

        symbolTable->typeSymbolTable(database);

        //        symbolTable->dump();
        //        std::cout << std::endl;

        csvsqldb::ASTQueryNodePtr query = std::dynamic_pointer_cast<csvsqldb::ASTQueryNode>(node);
        csvsqldb::ASTExprNodePtr exp =
        std::dynamic_pointer_cast<csvsqldb::ASTQuerySpecificationNode>(query->_query)->_tableExpression->_where->_exp;
        csvsqldb::Expressions& selectList = std::dynamic_pointer_cast<csvsqldb::ASTQuerySpecificationNode>(query->_query)->_nodes;
        csvsqldb::SymbolInfoPtr tableInfo =
        std::dynamic_pointer_cast<csvsqldb::ASTTableIdentifierNode>(
        std::dynamic_pointer_cast<csvsqldb::ASTQuerySpecificationNode>(query->_query)->_tableExpression->_from->_tableReferences[0])
        ->_factor->_info;

        csvsqldb::BlockManager blockManager;
        csvsqldb::StringVector files;
        csvsqldb::OperatorContext context(database, functions, blockManager, files);

        std::stringstream ss;
        csvsqldb::RootOperatorNodePtr output = std::make_shared<csvsqldb::OutputRowOperatorNode>(context, symbolTable, ss);
        csvsqldb::RowOperatorNodePtr projection = std::make_shared<csvsqldb::ExtendedProjectionOperatorNode>(context, symbolTable, selectList);
        csvsqldb::RowOperatorNodePtr select = std::make_shared<csvsqldb::SelectOperatorNode>(context, symbolTable, exp);
        csvsqldb::RowOperatorNodePtr scan = std::make_shared<DummyScanOperatorNode>(context, symbolTable, *tableInfo);

        select->connect(scan);
        projection->connect(select);
        output->connect(projection);

        MPF_TEST_ASSERTEQUAL(3, output->process());

        std::string expected = R"(#EMP_NO,EMP.BIRTH_DATE,EMP.FIRST_NAME,EMP.LAST_NAME,EMP.GENDER,EMP.HIRE_DATE
4711,1970-09-23,'Lars','Fürstenberg','M',2012-02-01
815,1969-05-17,'Mark','Fürstenberg','M',2003-04-15
9227,1963-03-06,'Angelica','Tello de Fürstenberg','F',2003-06-15
)";
        MPF_TEST_ASSERTEQUAL(expected, ss.str());
    }

    void processingAggregationTest()
    {
        csvsqldb::FunctionRegistry functions;
        csvsqldb::SQLParser parser(functions);

        csvsqldb::ASTNodePtr node = parser.parse(
        "CREATE TABLE employees(emp_no INTEGER,birth_date DATE NOT NULL,first_name VARCHAR(25) NOT NULL,last_name VARCHAR(50) "
        "NOT NULL,gender CHAR,hire_date DATE,PRIMARY KEY(emp_no))");
        MPF_TEST_ASSERT(node);
        MPF_TEST_ASSERT(std::dynamic_pointer_cast<csvsqldb::ASTCreateTableNode>(node));
        csvsqldb::ASTCreateTableNodePtr createNode = std::dynamic_pointer_cast<csvsqldb::ASTCreateTableNode>(node);

        csvsqldb::TableData tabledata = csvsqldb::TableData::fromCreateAST(createNode);
        csvsqldb::FileMapping mapping;

        csvsqldb::Database database("/tmp", mapping);
        database.addTable(tabledata);

        node = parser.parse("SELECT count(*) FROM employees");

        //        csvsqldb::ASTNodeDumpVisitor visitor;
        //        std::cout << std::endl;
        //        node->accept(visitor);

        csvsqldb::SymbolTablePtr symbolTable = node->symbolTable();
        symbolTable->typeSymbolTable(database);

        //        symbolTable->dump();
        //        std::cout << std::endl;

        csvsqldb::ASTQueryNodePtr query = std::dynamic_pointer_cast<csvsqldb::ASTQueryNode>(node);
        csvsqldb::Expressions& selectList = std::dynamic_pointer_cast<csvsqldb::ASTQuerySpecificationNode>(query->_query)->_nodes;
        csvsqldb::SymbolInfoPtr tableInfo =
        std::dynamic_pointer_cast<csvsqldb::ASTTableIdentifierNode>(
        std::dynamic_pointer_cast<csvsqldb::ASTQuerySpecificationNode>(query->_query)->_tableExpression->_from->_tableReferences[0])
        ->_factor->_info;

        csvsqldb::BlockManager manager;
        csvsqldb::StringVector files;
        csvsqldb::OperatorContext context(database, functions, manager, files);

        std::stringstream ss;
        csvsqldb::RootOperatorNodePtr output = std::make_shared<csvsqldb::OutputRowOperatorNode>(context, symbolTable, ss);
        csvsqldb::RowOperatorNodePtr projection = std::make_shared<csvsqldb::AggregationOperatorNode>(context, symbolTable, selectList);
        csvsqldb::RowOperatorNodePtr scan = std::make_shared<DummyScanOperatorNode>(context, symbolTable, *tableInfo);

        projection->connect(scan);
        output->connect(projection);

        MPF_TEST_ASSERTEQUAL(1, output->process());
        MPF_TEST_ASSERTEQUAL("#$alias_1\n3\n", ss.str());
    }