/*
File name: Poly.cpp
Author: Bo Bayles
E-mail address: bmb3h6@umr.edu
Description: This implementation file for the Poly class's functions.
*/

#include "Poly.h"
#include <cmath>
#include <iostream>
using namespace std;

Poly::Poly()
{
  for (int i = 0; i < iMAXSIZE; i++)
    pos[i] = 0;
}
//Default constructor: Initialize each element of the pos array to 0.

Poly::Poly(const float fCoeff, const int iDeg)
{
  for (int i = 0; i < iMAXSIZE; i++)
    pos[i] = 0;
    
  pos[iDeg] = fCoeff;
}
//Coefficient, degree constructor: Initialize each element of the pos
//  array to 0, then set the position of the pos array indicated by
//  iDeg to fCoeff.

Poly::Poly(const float fCoeff)
{
  for (int i = 0; i < iMAXSIZE; i++)
    pos[i] = 0;
  
  pos[0] = fCoeff;
}
//0 position constructor: Initializes each element of the pos array
//  to 0, then sets the 0 position of the pos array to fCoeff's value.

Poly::Poly(const Poly& p)
{
  for (int i = 0; i < iMAXSIZE; i++)
    pos[i] = p.pos[i];
}
//Copy constructor: Copy each element from object p's pos array to the
//  current object's.

Poly::~Poly()
{
  //cout << "Polynomial destructed!" << endl;
}
//Default destructor: Doesn't really do anything.

Poly operator+(Poly p, const Poly q)
{
  p += q;
    
  return p;
}
//+ operator: Get the two Poly objects as paramters. Call += on the 
//  second with the first to perform addition. Return the resultant Poly.

Poly& Poly::operator+=(const Poly& p)
{
  for (int i = 0; i < iMAXSIZE; i++)
    pos[i] = pos[i] + p.pos[i];

  return *this;  
}
//+= operator: Get Poly p as a parameter and add p's pos array elements
//  to the current object's. Return the current object by reference.

Poly operator-(Poly p, const Poly q)
{
  p -= q;
    
  return p;
}
//- operator: Get the two Poly objects as paramters. Call -= on the 
//  second with the first to perform addition. Return the resultant Poly.

Poly& Poly::operator-=(const Poly& p)
{
  for (int i = 0; i < iMAXSIZE; i++)
    pos[i] = pos[i] - p.pos[i];

  return *this;
}
//-= operator: Get Poly p as a parameter and subtract p's pos array
//  elements from the current object's. Return the current object.

Poly operator*(Poly p, const Poly q)
{
  p *= q.pos[0];
  
  return p;
}
//* operator: Get Poly p and the multiplier as parameters and set p equal
//  to resultPoly. Call *= on resultPoly and fMult, and then return it.


Poly& Poly::operator*=(const float fMult)
{
  for (int i = 0; i < iMAXSIZE; i++)
    pos[i] = pos[i] * fMult;

  return *this;    
}
//*= Get fMult as a parameter and set the current object's pos array 
//  elements equal to fMult * each element. Return the current object.


ostream& operator<<(ostream &out, Poly p)
{
  for (int i = (iMAXSIZE - 1); i >= 0; i--)
  {
    if (!p)
    {
      out << "0";
      break;
    }
    if (p.pos[i] != 0)
    {
      if  ( (p.pos[i] > 0) && (!p.emptyBefore(i)) )
        out << " + ";
        out << p.pos[i];
      if (i > 1)
        out << "x^" << i;
      if (i == 1)
        out << "x";
    }        
  }
  return out;
}
//<< operator: Get the output stream and the Poly to be displayed as 
//  parameters. Then check to see if it's empty. If so, display 0 and 
//  break. If not, loop through each position. Display a + if the current
//  position has a positive value and it's not empty before that, and 
//  also the coefficient. If the current position is bigger than one,
//  display x^ and the current position to indicate the power. If it's
//  one, just display x.

float Poly::operator()(const float fValue)
{
  float fEval = 0;
  
  for (int i = 0; i < iMAXSIZE; i++)
    fEval += pos[i] * pow(fValue,i);

  return fEval;
}
//() operator: Get the value to evaluate as a paramter and then loop
//  through the array, keeping a total of the coefficient and the value
//  to the position's power using cmath.h's pow function.

Poly Poly::operator-()
{
  Poly resultPoly;
  
  for (int i = 0; i < iMAXSIZE; i++)
    resultPoly.pos[i] = -pos[i];

  return resultPoly;
}
//Unary - operator: Negate every position in the pos array.

Poly Poly::operator~()
{
  Poly resultPoly;
  for (int i = 0; i < iMAXSIZE; i++)
    resultPoly.pos[i] = pos[i];
  
  int iLargest = 0;
  
  for (int i = 0; i < iMAXSIZE; i++)
  {
    if (pos[i] != 0)
      iLargest = i; 
  }
  
  resultPoly.pos[iLargest] = 0;

  return resultPoly;
}
//~ operator: Find the largest full position in the array and set it
//  to 0 for diminution.


Poly::operator bool() const
{
  bool bResult = false;
  
  for (int i = 0; i < iMAXSIZE; i++)
  {
    if (pos[i] != 0)
    {
      bResult = true;
      break;
    }
  }
  
  return bResult;
}
//bool conversion: If every position in the array is zero, return false.
//  Otherwise return true.

bool Poly::emptyBefore(const int iDeg)
{
  bool bResult = true;
  
  for (int i = (iDeg+1); i < iMAXSIZE; i++)
  {
    if (pos[i] != 0)
    {
      bResult = false;
      break;
    }
  }
  
  return bResult;
}
//emptyBefore function: If everything in the array above the position
//  indicated by iDeg is zero, return true. Otherwise return false.

