#include "VectorCpx.h"
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <limits>
using namespace std;

ostream& operator<<(ostream& ostr, const Complex& cp)
{
    ostr << "R:" << cp.real() << ", I:" << cp.imag();
    return ostr;
}

// ------------------------------------------------------
// Member function definition of Complex
Complex::Complex(double _real, double _imag): mReal(_real), mImag(_imag)
{

}

const double& Complex::real() const
{
    return mReal;
}

const double& Complex::imag() const
{
	return mImag;
}

void Complex::real(double value)
{ 
	mReal = value;
}

void Complex::imag(double value)
{ 
	mImag = value;
}

Complex	Complex::operator + (const Complex& cpx)const
{
	Complex cpOut;
	cpOut.real(mReal + cpx.real());
	cpOut.imag(mImag + cpx.imag());
	return cpOut;
}

Complex	Complex::operator - (const Complex& cpx)const
{
	Complex cpOut;
	cpOut.real(mReal - cpx.real());
	cpOut.imag(mImag - cpx.imag());
	return cpOut;
}

Complex	Complex::operator * (const Complex& cpx)const
{
	Complex cpOut;
	cpOut.real( mReal * cpx.real() - mImag * cpx.imag() );
	cpOut.imag( mReal * cpx.imag() + mImag * cpx.real() );
	return cpOut;
}

Complex	Complex::operator / (const Complex& cpx)const
{
	Complex cpOut;
	double rDiv = cpx.real() * cpx.real() + cpx.imag() * cpx.imag();
	if( rDiv < numeric_limits<double>::min()) 
		return cpOut;
    cpOut.real( (mReal * cpx.real() + mImag * cpx.imag()) / rDiv );
    cpOut.imag( (mImag * cpx.real() - mReal * cpx.imag()) / rDiv );
	return cpOut;
}

// -----------------------------------------------
// member functio of VectorCpx
VectorCpx::VectorCpx(unsigned _n, const Complex& cpx):pCpx(NULL), mSize(0), mCapacity(0)
{
    resize(_n, cpx);
}

VectorCpx::VectorCpx(const VectorCpx& v):pCpx(NULL), mSize(v.mSize), mCapacity(v.mCapacity)
{
    if(mCapacity > 0)
	{
        pCpx = new Complex[mCapacity];
        for(unsigned i=0; i<mSize; ++i)
            pCpx[i] = v.pCpx[i];
    }
}

VectorCpx::~VectorCpx()
{
    if(pCpx != NULL)
        delete [] pCpx;
}

unsigned VectorCpx::size() const 
{
	return mSize;
}

unsigned VectorCpx::capacity() const 
{
	return mCapacity;
}

const Complex& VectorCpx::operator[](int i) const
{
    if(i<0) 
		return pCpx[0];
    else if(static_cast<unsigned>(i) >= mSize) 
		return pCpx[mSize-1];
    else return pCpx[i];
}

Complex& VectorCpx::operator[](int i)
{
    if(i<0) 
		return pCpx[0];
    else if(static_cast<unsigned>(i) >= mSize) 
		return pCpx[mSize-1];
    else return pCpx[i];
}

VectorCpx& VectorCpx::push_back(const Complex& cpx)
{
    resize(mSize+1, cpx);
    return *this;
}

VectorCpx& VectorCpx::resize(unsigned _n, const Complex& cpx)
{
    if(_n > mCapacity)
	{
        if(mCapacity < 1) 
			mCapacity = 1;
        while (mCapacity < _n) 
			mCapacity <<= 1;
        Complex *pNew = new Complex[mCapacity];
        // Restore original data
        if(mSize > 0)
		{
            for(unsigned i=0; i<mSize; ++i) pNew[i] = pCpx[i];
            delete [] pCpx;
        }
        pCpx = pNew;
    }
    
    for(unsigned i=mSize; i<_n; pCpx[i++] = cpx);
    mSize = _n;
    return *this;
}

VectorCpx& VectorCpx::operator=(const VectorCpx& v)
{
    if(this != &v)
	{
        this->VectorCpx::~VectorCpx();
        mSize = v.mSize;
        if(mSize>0)
		{
            mCapacity = 1;
            while (mCapacity < mSize) 
				mCapacity <<= 1;
            pCpx = new Complex[mCapacity];
            for(unsigned i=0; i<mSize; ++i)
                pCpx[i] = v.pCpx[i];
        }
    }
    return *this;
}

VectorCpx VectorCpx::operator*(const Complex& cpx)const
{
    VectorCpx vOut = *this;
    for(int i=0; i<mSize; ++i)
        vOut.pCpx[i] = vOut.pCpx[i] * cpx;
    return vOut;
}

Complex VectorCpx::operator*(const VectorCpx& v)
{
    Complex cpxDot = 0;
    unsigned nLoop = mSize<v.mSize?mSize:v.mSize;
    for(int i=0; i<nLoop; ++i)
	{
        cpxDot = cpxDot + pCpx[i] * v.pCpx[i];
    }
    return cpxDot;
}

VectorCpx& VectorCpx::operator>>(fstream& file)	//= =
{
	cout << "^_^" << endl;
	return *this;
}

VectorCpx& VectorCpx::operator<<(fstream& file)	//......-.-
{
	cout << "XD" << endl;
	return *this;
}

VectorCpx operator*(const Complex& cpx, const VectorCpx& v)
{
    VectorCpx vOut = v;
    unsigned n = v.size();
    for(int i=0; i<n; ++i)
        vOut[i] = vOut[i] * cpx;
    return vOut;
}

ostream& operator<<(ostream& ostr, const VectorCpx& v)
{
    unsigned n = v.size();
    for(int i=0; i<n;)
	{
        ostr << v[i];
        ++i;
        if(i<n) 
			ostr << "; ";
    }
    ostr << endl;
    return ostr;
}

//-------------------------------------------------------------
//member function of AdvVectorO

AdvVectorO::AdvVectorO(unsigned number, const Complex& input):VectorCpx(number, input)	//constructor
{
	
}

AdvVectorO::AdvVectorO(const VectorCpx& vec):VectorCpx(vec)	//copy constructor
{
	
}

AdvVectorO& AdvVectorO::operator>>(fstream& file)
{
	for(int i = 0; i < mSize; i++)
	{
		file << (*this)[i].real() << " " << (*this)[i].imag();
		file << endl;
	}

	return *this;
}

//-------------------------------------------------------------
//member function of AdvVectorI

AdvVectorI::AdvVectorI(unsigned number, const Complex& input):VectorCpx(number, input)	//constructor
{
	
}

AdvVectorI::AdvVectorI(const VectorCpx& vec):VectorCpx(vec)	//copy constructor
{
	
}

AdvVectorI& AdvVectorI::operator<<(fstream& file)
{
	double regR = 0.0, regI = 0.0;

	while(file >> regR >> regI)	//如果寫while(!file.eof()){file >> regR >> regI;...}的話，會造成最後一個地方讀兩遍，因為C++的eof()是條件「已發生」才會回傳true
		push_back(Complex(regR,regI));	//每從文件讀一組數字進來，就push_back這組數字到原本的VectorCpx後面

	return *this;
}

//-------------------------------------------------------------
//member function of AdvVectorIO

//因為這裡要求以binary的形式操作程式，因此不能像前面用Complex的指標做爽爽，得先轉成char型態指標，再用fstream的函式去做

AdvVectorIO::AdvVectorIO(unsigned number, const Complex& input):VectorCpx(number, input)	//constructor
{
	
}

AdvVectorIO::AdvVectorIO(const VectorCpx& vec):VectorCpx(vec)	//copy constructor
{
	
}

AdvVectorIO& AdvVectorIO::operator>>(fstream& file)
{
	int size = sizeof(Complex)*mSize;
	
	file.write((char*)(&pCpx[0]), size);	//write(const unsigned char buf,int num)，從buf指向的暫存區寫入num長度的字元到文件中
											//由於pCpx[]是Complex型態，因此需要先在前面加"&"讓它成為指標，再用強制轉換變成char指標
	return *this;							//到時候執行時，程式就會從pCpx[0]當下指著的VectorCpx上，一口氣把所有的數字都寫到文件中
}

AdvVectorIO& AdvVectorIO::operator<<(fstream& file)
{
	Complex reg;

	while(file.read((char*)(&reg), sizeof(Complex)))	//read(unsigned char buf,int num)，從文件中讀取num長度的字元到buf指向的暫存區
		push_back(reg);									//每從文件讀一組數字進來，就push_back這組數字到原本的VectorCpx後面

	return *this;
}