#include <iostream>
#include <cstdlib>
#include <vector>

using namespace std;

#include "Polino.hpp"
#include "Parser.hpp"
#include "Term.hpp"

Poli::Poli()
{ 
	lid= NULL;
}

Poli::Poli(const Poli& p)
{
	lid= NULL;
	Term* pp= p.Lid();
	while (pp!=NULL) {
		lid= Ins(lid, new Term(pp->Coef(),pp->Expo()));
		pp= pp->Sgte();
	}
}

Poli::~Poli(void)
{
	Term* pp = lid;
	while (pp!=NULL) {
		Term* qq = pp;
		pp= pp->Sgte();
		delete qq;
	}
	lid= NULL;
}


ostream& Poli::Print(ostream& os) const
{
	if (Gr() == -1)
		os << " 0x0";
	else
		for (Term* t= lid; t!=NULL; t= t->Sgte()) {
			if (t->Coef() >= 0.0)
				os << " + " << t->Coef();
			else
				os << " - " << -t->Coef();
				if (t->Expo()==1)
					os << "x";
				else
				if (t->Expo()>1)
					os << "x" << t->Expo();
		}

	os << "; ";
	return os;
}

ostream& operator << (ostream& os, const Poli& p)
{
	return p.Print(os);
}

int Poli::Gr() const
{
	if (lid==NULL)
		return -1;
	else
		return lid->Expo();
}

istream& operator >> (istream& is, Poli& p)
{
	Parser E(is);
	p= E.poli();
	return is;
}

Poli& Poli::operator += (Term t)
{
	lid= Ins(lid, new Term(t.Coef(), t.Expo()));
	return *this;
}

Poli& Poli::operator -= (Term t)
{
	lid= Ins(lid, new Term(-t.Coef(), t.Expo()));
	return *this;
}


Poli operator + (const Poli& p, const Poli& q)
{
	Poli r;
	for (Term* pp= p.Lid(); pp!=NULL; pp=pp->Sgte())
		r+= *pp;
	for (Term* qq= q.Lid(); qq!=NULL; qq=qq->Sgte())
		r+= *qq;
	return r;
}


Poli operator - (const Poli& p, const Poli& q)
{
	Poli r;
	for (Term* pp= p.Lid(); pp!=NULL; pp=pp->Sgte())
		r+= *pp;
	for (Term* qq= q.Lid(); qq!=NULL; qq=qq->Sgte())
		r-= *qq;
	return r;
}


Poli operator - (const Poli& q)
{
	Poli r;
	for (Term* qq= q.Lid(); qq!=NULL; qq=qq->Sgte())
		r-= *qq;
	return r;
}


Poli::Poli(double c, int e)
{
	lid= new Term(c,e,NULL);
}

Poli& Poli::operator = (const Poli& p)
{
	Term* pp= lid;			// borrar la lista previa
	while (pp!=NULL) {
		Term* qq= pp;
 		pp= pp->Sgte();
		delete qq; 
	}

	lid= NULL;				// copiamos la lista de p
	pp= p.Lid(); 
	while (pp!=NULL) {
		lid= Ins(lid, new Term(pp->Coef(),pp->Expo()));
		pp= pp->Sgte();
	}

	return *this;
}


Poli operator * (const Poli& p, const Poli& q)
{
	Poli r;
	for (Term* u= p.Lid(); u!=NULL; u= u->Sgte()) 
		for (Term* v= q.Lid(); v!=NULL; v= v->Sgte()) 
			r+= *u * *v;
	return r;
}

Poli operator / (const Poli& a, const Poli& b)
{
	Poli r= a;
	Poli q;
	while (b.Gr() <= r.Gr()) {
		Poli t(r.Lid()->Coef() / b.Lid()->Coef(),
					r.Lid()->Expo() - b.Lid()->Expo());
		r= r-t*b; 
		q= q+t;
	}
	return q;
}


Poli operator % (const Poli& a, const Poli& b)
{
	Poli r= a;
	Poli q;
	while (b.Gr() <= r.Gr()) {
		Poli t(r.Lid()->Coef() / b.Lid()->Coef(),
				r.Lid()->Expo() - b.Lid()->Expo());
		r= r-t*b; 
		q= q+t;
	}
	return r;
}






