#include "io.h"
#include <stdlib.h>

void saveInt(std::ofstream &ofs, const int &i) {
	ofs.write((char*) &i, sizeof(int));
}

void saveDouble(std::ofstream& ofs, const double& d) {
	ofs.write((char*)&d, sizeof(double));
}

void saveChar(std::ofstream &ofs, const char &c)
{
	//char cc = c^0x55;	// don't print chars in clear text
	char cc = c;
	ofs.write((char*) &cc, sizeof(char));
}

void saveString(std::ofstream &ofs, const std::string &s)
{
	int length = s.length();

	saveInt(ofs, length);

	for(int i=0; i<length; i++)
	{
		saveChar(ofs, s[i]);
	}
}

int readInt(std::ifstream &ifs)
{
	int i;
	ifs.read((char*) &i, sizeof(int));
	return i;
}

double readDouble(std::ifstream& ifs) {
	double d;
	ifs.read((char*)&d, sizeof(double));
	return d;
}

char readChar(std::ifstream &ifs)
{
	char c;
	ifs.read((char*) &c, sizeof(char));
	return c;
}

std::string readString(std::ifstream &ifs)
{
	int			length;
	std::string str = "";
	char		c;

	length = readInt(ifs);

	for(int i=0; i<length; i++)
	{
		c = readChar(ifs);
		str+=c;
	}

	return str;
}



void saveVariable(std::ofstream &ofs, const std::string &s, int i)
{
	saveVariable(ofs, s, i, "binary");
}

void saveVariable(std::ofstream &ofs, const std::string &s, long i)
{
	saveVariable(ofs, s, i, "binary");
}

void saveVariable(std::ofstream &ofs, const std::string &s, float i)
{
	saveVariable(ofs, s, i, "binary");
}

void saveVariable(std::ofstream &ofs, const std::string &s, double i)
{
	saveVariable(ofs, s, i, "binary");
}

void saveVariable(std::ofstream &ofs, const std::string &s, const std::string &i)
{
	saveVariable(ofs, s, i, "binary");
}

void saveVariable(std::ofstream &ofs, const std::string &s, int i, std::string output)
{
	if (output.compare("binary")==0)
	{
		int type = 1;
		ofs.write((char*) &type, sizeof(type));
		saveString(ofs, s);
		ofs.write((char*) &i, sizeof(i));
	}

	if (output.compare("ascii")==0)
	{
		ofs << s << ": " << i << std::endl;
	}
}

void saveVariable(std::ofstream &ofs, const std::string &s, long i, std::string output)
{
	if (output.compare("binary")==0)
	{
		int type = 2;
		ofs.write((char*) &type, sizeof(type));
		saveString(ofs, s);
		ofs.write((char*) &i, sizeof(i));
	}

	if (output.compare("ascii")==0)
	{
		ofs << s << ": " << i << std::endl;
	}
}

void saveVariable(std::ofstream &ofs, const std::string &s, float i, std::string output)
{
	if (output.compare("binary")==0)
	{
		int type = 3;
		ofs.write((char*) &type, sizeof(type));
		saveString(ofs, s);
		ofs.write((char*) &i, sizeof(i));
	}

	if (output.compare("ascii")==0)
	{
		ofs << s << ": " << i << std::endl;
	}
}

void saveVariable(std::ofstream &ofs, const std::string &s, double i, std::string output)
{
	if (output.compare("binary")==0)
	{
		int type = 4;
		ofs.write((char*) &type, sizeof(type));
		saveString(ofs, s);
		ofs.write((char*) &i, sizeof(i));
	}

	if (output.compare("ascii")==0)
	{
		ofs << s << ": " << i << std::endl;
	}
}

void saveVariable(std::ofstream &ofs, const std::string &s, const std::string &i, std::string output)
{
	if (output.compare("binary")==0)
	{
		int type = 5;
		ofs.write((char*) &type, sizeof(type));
		saveString(ofs, s);
		saveString(ofs, i);
	}

	if (output.compare("ascii")==0)
	{
		ofs << s << ": " << i << std::endl;
	}
}




void saveEndian(std::ofstream &ofs)
{
	int i = 1234;
	ofs.write((char*)&i, sizeof(i));
}

void readEndian(std::ifstream &ifs)
{
	int i = 0;
	ifs.read((char*)&i, sizeof(i));

	if (i == 1234)
	{

	}
	else
	{
		std::cout << "ERROR: Endian integer check failed!";
		exit(0);
	}
}

void saveSystem(std::ofstream &ofs)
{
	int i;

#ifdef _WIN32
	i = 0;
#else
	i = 1;
#endif

	ofs.write((char*)&i, sizeof(i));
}

void readSystem(std::ifstream &ifs)
{
	int i = 0;
	ifs.read((char*)&i, sizeof(i));

	if (i == 0)
	{
		
	}
	else
	{
		std::cout << "ERROR: System integer check failed!";
		exit(0);
	}
}

void saveVersion(std::ofstream &ofs, std::string version)
{
	saveString(ofs, version);
}

void readVersion(std::ifstream &ifs, std::string version)
{
	if (readString(ifs).compare(version) == 0)
	{

	}
	else
	{
		std::cout << "ERROR: Wrong version in read routine!";
		exit(0);
	}
}

void saveHeader(std::ofstream &ofs, std::string version)
{
	saveEndian(ofs);
	saveSystem(ofs);
	saveVersion(ofs, version);
}

void readHeader(std::ifstream &ifs, std::string version)
{
	readEndian(ifs);
	readSystem(ifs);
	readVersion(ifs, version);
}