#include <iostream>
#include <sstream>
#include <string>

#include "Complex.h"

// This sample implementation prints diagnostic messages that
// would not be included in a production class, but are helpful
// for observing how the class works.

namespace complex {

Complex::Complex(const double real, const double imag) {
  std::cout << "constructor(" << real << "," << imag << ")";
  std::cout << ", the constructed object is at " << this << std::endl;
  this->real_ = real;
  this->imag_ = imag;
}

Complex::Complex(const double real) {
  std::cout << "constructor(" << real << ")";
  std::cout << ", the constructed object is at " << this << std::endl;
  this->real_ = real;
  this->imag_ = 0.0;
}

Complex::Complex(const Complex &copyme) {
  std::cout << "copy constructor(copy " << &copyme << ")";
  std::cout << ", the constructed object is at " << this << std::endl;
  this->real_ = copyme.real_;
  this->imag_ = copyme.imag_;
}

Complex::~Complex() {
  std::cout << "destructor of object at " << this << std::endl;
}

Complex Complex::operator-(const Complex &a) const {
  Complex tmp(0,0);
  std::cout << "-: subtracting " << this << " - " << &a;
  std::cout << ", tmp is at " << &tmp << std::endl;
  tmp.real_ = this->real_ - a.real_;
  tmp.imag_ = this->imag_ - a.imag_;
  return tmp;
}

Complex &Complex::operator=(const Complex &a) {
  std::cout << "=operator: " << this << " = " << &a << std::endl;
  if (this != &a) {
    this->real_ = a.real_;
    this->imag_ = a.imag_;
  }
  return *this;
}

Complex &Complex::operator+=(const Complex &a) {
  std::cout << "+=operator: " << this << " += " << &a << std::endl;
  this->real_ += a.real_;
  this->imag_ += a.imag_;
  return *this;
}

Complex &Complex::operator-=(const Complex &a) {
  std::cout << "-=operator: " << this << " -= " << &a << std::endl;
  this->real_ -= a.real_;
  this->imag_ -= a.imag_;
  return *this;
}

// additional non-member overloaded operators in complex namespace

Complex operator+(const Complex &a, const Complex &b) {
  Complex tmp = a;
  std::cout << "+: adding " << &a << " + " << &b;
  std::cout << ", tmp is at " << &tmp << std::endl;
  tmp += b;
  return tmp;
}

std::ostream &operator<<(std::ostream &out, const Complex &a) {
  std::cout << "<<operator: from " << &a << std::endl;
  out << "(" << a.real() << " + " << a.imag() << "i)";
  return out;
}

std::istream &operator>>(std::istream &in, Complex &a) {
  std::cout << ">>operator: to " << &a << std::endl;

  double realtmp, imagtmp;
  // Make sure the next character is '('.
  if (in.peek() != '(') {
    in.setstate(std::ios_base::failbit);
    return in;
  }
  in.get();

  // Try to read the next thing as a double.
  if (!(in >> realtmp)) {
    return in;
  }

  // Read the next three chars (' + ').
  if (in.get() != ' ')
    return in;
  if (in.get() != '+')
    return in;
  if (in.get() != ' ')
    return in;

  // Try to read the next token as a double ending in 'i'.
  std::string x;
  if (!getline(in, x, 'i')) {
    return in;
  }

  std::stringstream ss(x);
  if (!(ss >> imagtmp)) {
    return in;
  }

  // Verify the next char is ')'.
  if (in.peek() != ')') {
    in.setstate(std::ios_base::failbit);
    return in;
  }
  in.get();

  a.real_ = realtmp;
  a.imag_ = imagtmp;
  return in;
}


}  // namespace complex