#include <iostream>
#include "polinom.h"

using namespace std;

Polinom::Polinom(): polinom(NULL)
{
	
}

Polinom::~Polinom()
{
	Lista *torlendo;
	while(polinom != NULL)
	{
		torlendo = polinom;
		polinom = polinom->next;
		delete torlendo;
	}
}

Polinom::Polinom(const Polinom &p)
{
	if(p.polinom == NULL)
	{
		polinom = NULL;
	}
	else
	{
		Lista *seged1, *seged2 = p.polinom->next;
		try
		{
			polinom = new Lista(p.polinom->monom);
		}catch(bad_alloc)
		{
			polinom = NULL;
			throw nincsMemoria;
		}
		seged1 = polinom;
		
		while(seged2 != NULL)
		{
			try
			{
				seged1->next = new Lista(seged2->monom);
			}catch(bad_alloc)
			{
				seged1->next = NULL;
				throw nincsMemoria;
			}
			seged1 = seged1->next;
			seged2 = seged2->next;
		}
	}
}

Polinom& Polinom::operator =(const Polinom &p)
{
	if(this == &p)
	{
		return *this;
	}
	
	Lista *torlendo;
	while(polinom != NULL)
	{
		torlendo = polinom;
		polinom = polinom->next;
		delete torlendo;
	}
	
	if(p.polinom == NULL)
	{
		polinom = NULL;
	}
	else
	{
		Lista *seged1, *seged2 = p.polinom->next;
		try
		{
			polinom = new Lista(p.polinom->monom);
		}catch(bad_alloc)
		{
			polinom = NULL;
			throw nincsMemoria;
		}
		seged1 = polinom;
		
		while(seged2 != NULL)
		{
			try
			{
				seged1->next = new Lista(seged2->monom);
			}catch(bad_alloc)
			{
				seged1->next = NULL;
				throw nincsMemoria;
			}
			seged1 = seged1->next;
			seged2 = seged2->next;
		}
	}
	
	return *this;
}

int Polinom::Szam(string szoveg) const
{
	int szam;
	bool helytelen;
	string sz;
	do
	{
		cout << szoveg << endl;
		cin >> szam;
		
		helytelen = cin.fail();
		if(helytelen)
		{
			cin.clear();
		}
		getline(cin, sz);
	}while(helytelen);
	
	return szam;
}

void Polinom::Hozzaad(Monom m)
{
	if(polinom == NULL || polinom->monom.kitevo > m.kitevo)
	{
		try
		{
			Lista *elem = new Lista(m);
			elem->next = polinom;
			polinom = elem;
		}catch(bad_alloc)
		{
			throw nincsMemoria;
		}
	}
	else
	{
		if(polinom->monom.kitevo == m.kitevo)
		{
			polinom->monom.egyutthato += m.egyutthato;
		}
		else
		{
			Lista *mut = polinom;
			while(mut->next != NULL && mut->next->monom.kitevo < m.kitevo)
			{
				mut = mut->next;
			}
			
			if(mut->next != NULL && mut->next->monom.kitevo == m.kitevo)
			{
				mut->next->monom.egyutthato += m.egyutthato;
			}
			else
			{
				try
				{
					Lista *elem = new Lista(m);
					elem->next = mut->next;
					mut->next = elem;
				}catch(bad_alloc)
				{
					throw nincsMemoria;
				}
			}
		}
	}
}

istream& operator >>(istream &is, Polinom &p)
{
	int db = p.Szam("Hány monomból áll a polinom?");
	int egyutthato, kitevo;
	for(int i = 0; i < db; ++i)
	{
		cout << i + 1 << ". monom:" << endl;
		egyutthato = p.Szam("\tegyüttható");
		kitevo = p.Szam("\tkitevő");
		
		p.Hozzaad(Polinom::Monom(egyutthato, kitevo));
	}
	
	return is;
}

ostream& operator <<(ostream &os, const Polinom &p)
{
	bool l = false;
	Polinom::Lista *mut = p.polinom;
	while(mut != NULL)
	{
		if(l)
		{
			if(mut->monom.egyutthato > 0)
			{
				os << '+' << mut->monom.egyutthato << "*x^" << mut->monom.kitevo;
			}
			else
			{
				os << mut->monom.egyutthato << "*x^" << mut->monom.kitevo;
			}
		}
		else
		{
			os << mut->monom.egyutthato << "*x^" << mut->monom.kitevo;
			l = true;
		}
		mut = mut->next;
	}
	os << endl;
	
	return os;
}

Polinom operator +(const Polinom &p1, const Polinom &p2)
{
	Polinom eredmeny;
	try{
		eredmeny.polinom = new Polinom::Lista(Polinom::Monom()); // ~ Ez csak egy trükk, hogy legyen ideiglenesen egy fejelemünk
	}catch(bad_alloc)
	{
		throw Polinom::nincsMemoria;
	}
	
	Polinom::Lista *seged1 = p1.polinom, *seged2 = p2.polinom, *seged3 = eredmeny.polinom; // Ezzel szebb lesz a ciklusunk
	while(seged1 != NULL || seged2 != NULL)
	{
		if(seged2 == NULL || (seged1 != NULL && seged1->monom.kitevo < seged2->monom.kitevo))
		{
			try
			{
				seged3->next = new Polinom::Lista(seged1->monom);
				seged1 = seged1->next;
				seged3 = seged3->next;
			}catch(bad_alloc)
			{
				throw Polinom::nincsMemoria;
			}
		}
		else if(seged1 == NULL || (seged2 != NULL && seged2->monom.kitevo < seged1->monom.kitevo))
		{
			try
			{
				seged3->next = new Polinom::Lista(seged2->monom);
				seged2 = seged2->next;
				seged3 = seged3->next;
			}catch(bad_alloc)
			{
				throw Polinom::nincsMemoria;
			}
		}
		else if(seged1 != NULL && seged2 != NULL && seged1->monom.kitevo == seged2->monom.kitevo)
		{
			try
			{
				seged3->next = new Polinom::Lista(Polinom::Monom(seged1->monom.egyutthato + seged2->monom.egyutthato, seged1->monom.kitevo));
				seged1 = seged1->next;
				seged2 = seged2->next;
				seged3 = seged3->next;
			}catch(bad_alloc)
			{
				throw Polinom::nincsMemoria;
			}
		}
	}
	
	Polinom::Lista *torlendo = eredmeny.polinom;
	eredmeny.polinom = eredmeny.polinom->next;
	delete torlendo; // A végén töröljük a fejelemet
	
	return eredmeny;
}

Polinom operator *(const Polinom &p1, const Polinom &p2)
{
	Polinom eredmeny;
	
	Polinom::Lista *seged1 = p1.polinom, *seged2;
	while(seged1 != NULL)
	{
		seged2 = p2.polinom;
		while(seged2 != NULL)
		{
			eredmeny.Hozzaad(Polinom::Monom(seged1->monom.egyutthato * seged2->monom.egyutthato, seged1->monom.kitevo + seged2->monom.kitevo));
			seged2 = seged2->next;
		}
		seged1 = seged1->next;
	}
	
	return eredmeny;
}
