// Programmed by William O'Brien <kernel@brunnet.net>. Essentially what
// I've programmed is a class that simplifies reading formatting input
// from files. I've made a main generic Retrieve class, and two others
// that are specializations for int and double. These should make this
// file pretty applicable as is for development.

// To use this you simply pass the file name, format string and pointer
// to buffer to store the value. The type of the buffer is passed to the
// class as a template parameter. For complete examples check the main
// driver program. Hope this could be of some use.

// Note: If you are going to use this I would definately recommend that
// you seperate the declarations and specialization declarations in a
// header file along with their respective definitions. I would have done
// so but I wanted things to be simple.

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;


template <typename tArgumentType>
class Retrieve {
private:
	ifstream ifInput;
	tArgumentType *tExtraction;
	string sSearchString;
	string sCurrentFileName;
public:
	Retrieve(void);
	Retrieve(const char *szFileName);
	Retrieve(const string &sFileName);
	Retrieve(const char *szFileName,
		const char *szReadString,
		tArgumentType *tAddress);
	Retrieve(const string &sFileName,
		const string &sReadString,
		tArgumentType *tAddress);
	~Retrieve(void);
	void CloseFile(void);
	void ClearState(void);
	void OpenFile(const char *szFileName);
	void OpenFile(const string &sFileName);
	void Read(void);
	void ReadSameFile(void);
	void SearchString(const char *szReadString);
	void SearchString(const string &sReadString);
	void ExtractAddress(tArgumentType *tAddress);
};

template <typename tArgumentType>
Retrieve<tArgumentType>::Retrieve(void)
{}

template <typename tArgumentType>
Retrieve<tArgumentType>::Retrieve(const char *szFileName)
: sCurrentFileName(szFileName)
{
	OpenFile(szFileName);
}

template <typename tArgumentType>
Retrieve<tArgumentType>::Retrieve(const string &sFileName)
: sCurrentFileName(sFileName)
{
	OpenFile(sFileName);
}

template <typename tArgumentType>
Retrieve<tArgumentType>::Retrieve(const char *szFileName,
								  const char *szReadString,
								  tArgumentType *tAddress)
: sCurrentFileName(szFileName)
{
	sSearchString = string(szReadString);
	OpenFile(szFileName);
	ExtractAddress(tAddress);
}

template <typename tArgumentType>
Retrieve<tArgumentType>::Retrieve(const string &sFileName,
								  const string &sReadString,
								  tArgumentType *tAddress)
: sCurrentFileName(sFileName)
{
	sSearchString = sReadString;
	OpenFile(sFileName);
	ExtractAddress(tAddress);
}

template <typename tArgumentType>
Retrieve<tArgumentType>::~Retrieve(void)
{
	CloseFile();
}

template <typename tArgumentType> 
void Retrieve<tArgumentType>::CloseFile(void)
{
	ifInput.close();
}

template <typename tArgumentType> 
void Retrieve<tArgumentType>::ClearState(void)
{
	ifInput.clear();
}

template <typename tArgumentType> 
void Retrieve<tArgumentType>::OpenFile(const char *szFileName)
{
	sCurrentFileName = string(szFileName);
	if (ifInput.is_open())
	{
		ifInput.close();
	}
	ifInput.open(szFileName);
}

template <typename tArgumentType> 
void Retrieve<tArgumentType>::OpenFile(const string &sFileName)
{
	sCurrentFileName = string(sFileName);
	if (ifInput.is_open())
	{
		ifInput.close();
	}
	ifInput.open(sFileName.c_str());
}

template <typename tArgumentType>
void Retrieve<tArgumentType>::ExtractAddress(tArgumentType *tAddress)
{
	tExtraction = tAddress;
}

template <typename tArgumentType>
void Retrieve<tArgumentType>::Read(void)
{
	string sLineBuffer;
	string sExtraction;
	ClearState();
	if (ifInput)
	{
		getline(ifInput, sLineBuffer);
	}
	string::size_type stPosition = sLineBuffer.find(sSearchString);
	while (ifInput && stPosition == string::npos)
	{
		getline(ifInput, sLineBuffer);
		stPosition = sLineBuffer.find(sSearchString);
	}
	if (ifInput && stPosition != string::npos)
	{
		stPosition += sSearchString.size();
	}
	sExtraction = sLineBuffer.substr(stPosition, string::npos);
	*tExtraction = sExtraction;
}

template <typename tArgumentType>
void Retrieve<tArgumentType>::ReadSameFile(void)
{
	CloseFile();
	OpenFile(sCurrentFileName);
	Read();
}

template <typename tArgumentType>
void Retrieve<tArgumentType>::SearchString(const char *szReadString)
{
	sSearchString = string(szReadString);
}

template <typename tArgumentType>
void Retrieve<tArgumentType>::SearchString(const string &sReadString)
{
	sSearchString = string(sReadString);
}














template <>
class Retrieve<int> {
private:
	ifstream ifInput;
	tArgumentType *tExtraction;
	string sSearchString;
	string sCurrentFileName;
public:
	Retrieve(void);
	Retrieve(const char *szFileName);
	Retrieve(const string &sFileName);
	Retrieve(const char *szFileName,
		const char *szReadString,
		tArgumentType *tAddress);
	Retrieve(const string &sFileName,
		const string &sReadString,
		tArgumentType *tAddress);
	~Retrieve(void);
	void CloseFile(void);
	void ClearState(void);
	void OpenFile(const char *szFileName);
	void OpenFile(const string &sFileName);
	void Read(void);
	void ReadSameFile(void);
	void SearchString(const char *szReadString);
	void SearchString(const string &sReadString);
	void ExtractAddress(tArgumentType *tAddress);
};

template <>
Retrieve<int>::Retrieve(void)
{}

template <>
Retrieve<int>::Retrieve(const char *szFileName)
: sCurrentFileName(szFileName)
{
	OpenFile(szFileName);
}

template <>
Retrieve<int>::Retrieve(const string &sFileName)
: sCurrentFileName(sFileName)
{
	OpenFile(sFileName);
}

template <>
Retrieve<int>::Retrieve(const char *szFileName,
								  const char *szReadString,
								  tArgumentType *tAddress)
: sCurrentFileName(szFileName)
{
	sSearchString = string(szReadString);
	OpenFile(szFileName);
	ExtractAddress(tAddress);
}

template <>
Retrieve<int>::Retrieve(const string &sFileName,
								  const string &sReadString,
								  tArgumentType *tAddress)
: sCurrentFileName(sFileName)
{
	sSearchString = sReadString;
	OpenFile(sFileName);
	ExtractAddress(tAddress);
}

template <>
Retrieve<int>::~Retrieve(void)
{
	CloseFile();
}

template <>
void Retrieve<int>::CloseFile(void)
{
	ifInput.close();
}

template <>
void Retrieve<int>::ClearState(void)
{
	ifInput.clear();
}

template <>
void Retrieve<int>::OpenFile(const char *szFileName)
{
	sCurrentFileName = string(szFileName);
	if (ifInput.is_open())
	{
		ifInput.close();
	}
	ifInput.open(szFileName);
}

template <>
void Retrieve<int>::OpenFile(const string &sFileName)
{
	sCurrentFileName = string(sFileName);
	if (ifInput.is_open())
	{
		ifInput.close();
	}
	ifInput.open(sFileName.c_str());
}

template <>
void Retrieve<int>::ExtractAddress(tArgumentType *tAddress)
{
	tExtraction = tAddress;
}

template <>
void Retrieve<int>::Read(void)
{
	string sLineBuffer;
	string sExtraction;
	ClearState();
	if (ifInput)
	{
		getline(ifInput, sLineBuffer);
	}
	string::size_type stPosition = sLineBuffer.find(sSearchString);
	while (ifInput && stPosition == string::npos)
	{
		getline(ifInput, sLineBuffer);
		stPosition = sLineBuffer.find(sSearchString);
	}
	if (ifInput && stPosition != string::npos)
	{
		stPosition += sSearchString.size();
	}
	sExtraction = sLineBuffer.substr(stPosition, string::npos);
	*tExtraction = atoi(sExtraction.c_str());
}

template <>
void Retrieve<int>::ReadSameFile(void)
{
	CloseFile();
	OpenFile(sCurrentFileName);
	Read();
}

template <>
void Retrieve<int>::SearchString(const char *szReadString)
{
	sSearchString = string(szReadString);
}

template <>
void Retrieve<int>::SearchString(const string &sReadString)
{
	sSearchString = string(sReadString);
}

template <>
class Retrieve<double> {
private:
	ifstream ifInput;
	tArgumentType *tExtraction;
	string sSearchString;
	string sCurrentFileName;
public:
	Retrieve(void);
	Retrieve(const char *szFileName);
	Retrieve(const string &sFileName);
	Retrieve(const char *szFileName,
		const char *szReadString,
		tArgumentType *tAddress);
	Retrieve(const string &sFileName,
		const string &sReadString,
		tArgumentType *tAddress);
	~Retrieve(void);
	void CloseFile(void);
	void ClearState(void);
	void OpenFile(const char *szFileName);
	void OpenFile(const string &sFileName);
	void Read(void);
	void ReadSameFile(void);
	void SearchString(const char *szReadString);
	void SearchString(const string &sReadString);
	void ExtractAddress(tArgumentType *tAddress);
};

template <>
Retrieve<double>::Retrieve(void)
{}

template <>
Retrieve<double>::Retrieve(const char *szFileName)
: sCurrentFileName(szFileName)
{
	OpenFile(szFileName);
}

template <>
Retrieve<double>::Retrieve(const string &sFileName)
: sCurrentFileName(sFileName)
{
	OpenFile(sFileName);
}

template <>
Retrieve<double>::Retrieve(const char *szFileName,
								  const char *szReadString,
								  tArgumentType *tAddress)
: sCurrentFileName(szFileName)
{
	sSearchString = string(szReadString);
	OpenFile(szFileName);
	ExtractAddress(tAddress);
}

template <>
Retrieve<double>::Retrieve(const string &sFileName,
								  const string &sReadString,
								  tArgumentType *tAddress)
: sCurrentFileName(sFileName)
{
	sSearchString = sReadString;
	OpenFile(sFileName);
	ExtractAddress(tAddress);
}

template <>
Retrieve<double>::~Retrieve(void)
{
	CloseFile();
}

template <>
void Retrieve<double>::CloseFile(void)
{
	ifInput.close();
}

template <>
void Retrieve<double>::ClearState(void)
{
	ifInput.clear();
}

template <>
void Retrieve<double>::OpenFile(const char *szFileName)
{
	sCurrentFileName = string(szFileName);
	if (ifInput.is_open())
	{
		ifInput.close();
	}
	ifInput.open(szFileName);
}

template <>
void Retrieve<double>::OpenFile(const string &sFileName)
{
	sCurrentFileName = string(sFileName);
	if (ifInput.is_open())
	{
		ifInput.close();
	}
	ifInput.open(sFileName.c_str());
}

template <>
void Retrieve<double>::ExtractAddress(tArgumentType *tAddress)
{
	tExtraction = tAddress;
}

template <>
void Retrieve<double>::Read(void)
{
	string sLineBuffer;
	string sExtraction;
	ClearState();
	if (ifInput)
	{
		getline(ifInput, sLineBuffer);
	}
	string::size_type stPosition = sLineBuffer.find(sSearchString);
	while (ifInput && stPosition == string::npos)
	{
		getline(ifInput, sLineBuffer);
		stPosition = sLineBuffer.find(sSearchString);
	}
	if (ifInput && stPosition != string::npos)
	{
		stPosition += sSearchString.size();
	}
	sExtraction = sLineBuffer.substr(stPosition, string::npos);
	*tExtraction = atof(sExtraction.c_str());
}

template <>
void Retrieve<double>::ReadSameFile(void)
{
	CloseFile();
	OpenFile(sCurrentFileName);
	Read();
}

template <>
void Retrieve<double>::SearchString(const char *szReadString)
{
	sSearchString = string(szReadString);
}

template <>
void Retrieve<double>::SearchString(const string &sReadString)
{
	sSearchString = string(sReadString);
}

// Data.dat contents:

// Programmer: William O'Brien
// Age: 17
// Language: C, C++, STL
// Dream: Game Programmer

int main(void)
{
	string sProgrammerAge;
	Retrieve<string> rAge("Data.dat", "Age: ", &sProgrammerAge);
	rAge.Read();
	cout << sProgrammerAge << endl;
	rAge.SearchString("Programmer: ");
	rAge.ReadSameFile();
	cout << sProgrammerAge << endl;
	rAge.CloseFile();
	int iProgrammerAge;
	Retrieve<int> rAgeAgain("Data.dat", "Age: ", &iProgrammerAge);
	rAgeAgain.Read();
	cout << iProgrammerAge << endl;
	return 0;
}