// file: readPoly.cpp
// by: Dawn Lawrie
// date: 3/19/2005

#include <iostream>
#include <stdexcept>
#include <string>
#include <cmath>
#include <ctype.h>

using namespace std;

#define VARIABLE 'x'  // If you want to allow for other variables, you would
                      // have to change the code where variable is used
                      // However since there is only one variable, you only
                      // have to recognize it once

// New Type holds polynomials
struct Poly {
  int coeff;
  int power;
  // Construct
  // By default, the coeff and power are 0
  Poly (int c=0, int p=0) : 
    coeff(c), power(p) {
  }
};

// Exception class
class PolyFormatException: public logic_error
{
public:
  PolyFormatException(const string & message="")
    : logic_error(message.c_str())
  {}
};

// Helper Functions

// Finds the position of the first charater than is not a space, at or after 
// the position passed in
// pos will hold the position of the first non-whitespace or the end of the
// string
void skipSpace( string str, int &pos);

// Isolates the coeffienct
// Stores the value in coeff
// Sets the strPos to the character after the last one used
void getCoeff(string poly, int sign, int& strPos, int& coeff);

// Isolates the power
// Stores the value in power
// Set the strPos to the character after the last one used
void getPower(string poly, int& strPos, int& power);

// Determines the sign of the next coefficient
// Stores the sign as -1 or 1 in sign
// Sets the strPos to the character after the last one used
void getSign(string poly, int &strPos, int &sign);

int main() {

  // Variables
  const int MAX_TERMS = 20;  // I will not be able to process more than 20 terms
  Poly poly[MAX_TERMS];      // Holds the parsed information
  string userPoly;           // Characters entered by user
  int curPos = 0;            // position in the string
  int curTerm =0;            // Number of terms processed
  int sign = 1;  // Used to make coefficients negative when necessary

  // Ask for polynomial
  do {
    cout << "Please enter a polynomial in the form -2x^2 + x + 5" << endl;
    getline(cin, userPoly, '\n');

    // Find the beginning the the real input
    curPos = 0;
    skipSpace(userPoly, curPos);
    if (curPos >= userPoly.length()) {
      cerr << "Invalid input" << endl;
    }
  } while (curPos >= userPoly.length());
  
  while (curPos < userPoly.length() && curTerm < MAX_TERMS) {
    
    // Isolate the term
    try {
      getCoeff(userPoly, sign, curPos, poly[curTerm].coeff); 
      getPower(userPoly, curPos, poly[curTerm].power);
      
      // Determine sign of next term if there is one
      if (curPos < userPoly.length()) {
	getSign(userPoly, curPos, sign);
      }
      
      curTerm++;
    }
    catch (PolyFormatException pf) {
      cerr << "ERROR: " << pf.what() << endl;
      return 1;
    }
  }

  cout << "You entered: " << endl;
  for (int i = 0; i < curTerm; i++) {
    if (i != 0)
      cout << "+ ";
    cout << poly[i].coeff << "x^" << poly[i].power << " ";
  }
  cout << endl;

  return 0;
}

// Finds the position of the first charater than is not a space, at or after 
// the position passed in
void skipSpace( string str, int &pos) {
  while (pos < str.length() && isspace(str[pos]))
    pos++;
}

// Isolates the coeffienct
// Stores the value in coeff
// Sets the strPos to the character after the last one used
void getCoeff(string poly, int sign, int& strPos, int& coeff) {

  int begin = strPos;
  
  // Find the first character
  skipSpace(poly, begin);

  // There should be at least a number if this is the end of the string
  // there is a format problme
  if (begin >= poly.length()) 
    throw PolyFormatException("No Coefficient");
  
  // There may be an implicit 1
  if (poly[begin] == VARIABLE) {
    coeff = 1;
    strPos = begin;
  }
  else {
    int end = begin + 1;
  
    // Look for end of number
    while (end < poly.length() && isdigit(poly[end]))
      end++;
    
    // Extract coefficient
    coeff = atoi(poly.substr(begin, end-begin).c_str()) * sign;
    strPos = end;
  }
}

// Isolates the power
// May Encounter x, then ^ which must be followed by a number
// Stores the value in power
// Set the strPos to the character after the last one used
void getPower(string poly, int& strPos, int& power) {
  
  int begin = strPos;
  // Find first non-whitespace
  skipSpace(poly, begin);

  // If there is nothing left in the string or the next character
  // is not the variable, the power must be 0
  if (begin >= poly.length() || poly[begin] != VARIABLE) {
    power = 0;
    strPos = begin;
  }
  else {
    begin++;     // Pass the variable
    
    // Find first non-whitespace
    skipSpace(poly, begin);

    // If this character is not a carrot or the end of the string is reached, 
    // then the power is one
    if (begin >= poly.length() || poly[begin] != '^') {
      power = 1;
      strPos = begin;
    }
    else {
      begin++;
      // Skip possible white space
      skipSpace(poly, begin);

      // Powers must be numbers, but they may be negative
      if (begin >= poly.length() || !(poly[begin] == '-' || 
				      isdigit(poly[begin]))) 
	throw PolyFormatException("^ must be followed by number");

      // Look for end of number
      int end = begin+1;
      while (end < poly.length() && isdigit(poly[end]))
	end++;

      // Extract the power
      power = atoi(poly.substr(begin, end-begin).c_str());
      strPos = end;
    }
  }
}

// Determines the sign of the next coefficient
// Stores the sign as -1 or 1 in sign
// Sets the strPos to the character after the last one used
void getSign(string poly, int &strPos, int &sign) {
  
  int curPos = strPos;

  // Skip possible white space
  skipSpace(poly, curPos);

  // Recognize the sign
  if (curPos >= poly.length() || poly[curPos] == '+')
    sign = 1;
  else if (poly[curPos] == '-')
    sign = -1;
  else 
    throw PolyFormatException("Must add or subtract terms");
  
  strPos = curPos+1;
}

				

