#include <iostream>
#include <cstdlib>
#include "counting.h"
#include "linsearch.h"
#include "seqinfileenumerator.h"

using namespace std;

struct Pair1{
	int previous;
	int current;
};

struct Pair2{
	int cardinality;
	int number;
};

class SpecialEnumerator:public Enumerator<Pair1>{
protected:
	SeqInFileEnumerator<int> *enor;
	Pair1 current;
	bool end;

	virtual bool SpecialCond(const int&,const int&) const{return false;}
public:
	SpecialEnumerator(const string &input){
		try{
			enor=new SeqInFileEnumerator<int>(input);
		}catch(SeqInFileEnumerator<int>::Exceptions){
			exit(1);
		}
	}
	virtual ~SpecialEnumerator(){
		delete enor;
	}
	void First(){
		enor->First();
		Next();
	}
	void Next();
	Pair1 Current() const{return current;}
	bool End() const{return end;}
};
void SpecialEnumerator::Next(){
	end=enor->End();
	if(!end){
		current.previous=enor->Current();
		enor->Next();
		end=enor->End() || SpecialCond(current.previous,enor->Current());
		if(!end)
			current.current=enor->Current();
	}
}

class SpecialLinSearch:public LinSearch<Pair1,true>{
private:
	bool Cond(const Pair1 &pair1) const{return pair1.previous+1!=pair1.current;}
};

class EspecialEnumerator:public SpecialEnumerator{
private:
	bool SpecialCond(const int &a,const int &b) const{return a>b;}
public:
	EspecialEnumerator(const string &input):SpecialEnumerator(input){}
};

/***************************/

class SpecialCounting:public Counting<int>{
private:
	const int number;
	void First(){}
	bool WhileCond(const int &szam) const{return szam==number;}
public:
	SpecialCounting(const int &szam):number(szam),Counting<int>(){}
};

class InterestingEnumerator:public Enumerator<Pair2>{
private:
	SeqInFileEnumerator<int> *enor;
	Pair2 current;
	bool end;
public:
	InterestingEnumerator(const string &input){
		try{
			enor=new SeqInFileEnumerator<int>(input);
		}catch(SeqInFileEnumerator<int>::Exceptions){
			exit(2);
		}
	}
	~InterestingEnumerator(){
		delete enor;
	}
	void First(){
		enor->First();
		Next();
	}
	void Next();
	Pair2 Current() const{return current;}
	bool End() const{return end;}
};
void InterestingEnumerator::Next(){
	end=enor->End();
	if(!end){
		current.number=enor->Current();
		SpecialCounting sc(enor->Current());
		sc.AddEnumerator(enor);

		sc.Run();

		current.cardinality=sc.Answer();
	}
}

class EspecialLinSearch:public LinSearch<Pair2,true>{
private:
	bool Cond(const Pair2 &pair2) const{return pair2.cardinality>=5;}
};

/***************************/

class CombineInterestingEnumerator:public Enumerator<Pair2>{
private:
	InterestingEnumerator *input1;
	InterestingEnumerator *input2;
	Pair2 current;
	bool end;
public:
	CombineInterestingEnumerator(const string &sz,const string &zs){
		input1=new InterestingEnumerator(sz);
		input2=new InterestingEnumerator(zs);
	}
	~CombineInterestingEnumerator(){
		delete input1;
		delete input2;
	}
	void First(){
		input1->First();
		input2->First();
		Next();
	}
	void Next();
	Pair2 Current() const{return current;}
	bool End() const{return end;}
};
void CombineInterestingEnumerator::Next(){
	end=input1->End() && input2->End();
	if(!end){
		if(input2->End() || (!input1->End() && input1->Current().number<input2->Current().number)){
			current=input1->Current();
			input1->Next();
		}
		else if(input1->End() || (!input2->End() && input2->Current().number<input1->Current().number)){
			current=input2->Current();
			input2->Next();
		}
		else if(!input1->End() && !input2->End() && input1->Current().number==input2->Current().number){
			current.number=input1->Current().number;
			current.cardinality=input1->Current().cardinality+input2->Current().cardinality;
			input1->Next();
			input2->Next();
		}
	}
}

int main(int argc,char** argv,char** envp){
	SpecialEnumerator *se=new SpecialEnumerator("input1.txt");
	SpecialLinSearch sls1;
	sls1.AddEnumerator(se);

	sls1.Run();

	if(sls1.Found())
		cout<<"Igaz, hogy nem szerepel olyan szam, amely elott eppen eggyel kisebb szam all!"<<endl;
	else
		cout<<"Van olyan szam, amely elott eppen eggyel kisebb szam all!"<<endl;

	delete se;

	/***************************/
	EspecialEnumerator *ee=new EspecialEnumerator("input1.txt");
	SpecialLinSearch sls2;
	sls2.AddEnumerator(ee);

	sls2.Run();

	if(sls2.Found())
		cout<<"Igaz, hogy nem szerepel olyan szam, amely elott eppen eggyel kisebb szam all!"<<endl;
	else
		cout<<"Van olyan szam, amely elott eppen eggyel kisebb szam all!"<<endl;

	delete ee;

	/***************************/
	InterestingEnumerator *ie=new InterestingEnumerator("input1.txt");
	EspecialLinSearch el1;
	el1.AddEnumerator(ie);

	el1.Run();

	if(el1.Found())
		cout<<"Igaz, hogy az allomanyban minden szambol legalabb ot van!"<<endl;
	else
		cout<<"Nem igaz, hogy az allomanyban minden szambol legalabb ot van!"<<endl;

	delete ie;

	/***************************/
	CombineInterestingEnumerator *cie=new CombineInterestingEnumerator("input1.txt","input2.txt");
	EspecialLinSearch el2;
	el2.AddEnumerator(cie);

	el2.Run();

	if(el2.Found())
		cout<<"Igaz, hogy a ket allomanyban egyuttesen minden szambol legalabb ot van!"<<endl;
	else
		cout<<"Nem igaz, hogy a ket allomanyban egyuttesen minden szambol legalabb ot van!"<<endl;

	delete cie;


	system("pause");
	return 0;
}