#include"Cvec.h"
#include"io.h"
#include<iostream>
#include<math.h>
#include<fstream>

Cvec::Cvec() {};
Cvec::Cvec(const int n) {
	this->init(n);
}
Cvec::Cvec(const Cvec& in) {
	*this = in;
}
Cvec::Cvec(double start, double dx_in, double end) {
	int n = (int)((end + dx_in - start) / dx_in);
	this->init(n);
	for (int i = 0; i < size; i++) vec[i] = start + i * dx_in;
}
Cvec::Cvec(int start, double dx_in, int end) {
	int n = (int)(end + dx_in - start) / dx_in;
	this->init(n);
	for (int i = 0; i < size; i++) vec[i] = start + i * dx_in;
}

Cvec::~Cvec() {

	if (size > 0)	delete vec;
}

void Cvec::init(int n) {
	if (size == n) {
		*this = 0;
		return;
	}
	if (size > 0) {
		delete vec;
	}
	size = n;
	vec = new Creal[size];
	*this = 0;
}

int Cvec::get_size() const {
	return size;
}

void Cvec::print() {
	for (int i = 0; i < size; i++) std::cout << vec[i] << std::endl;//printf("%5.4f, %5.4f\n", real(vec[i]), vec[i].imag());
}

void Cvec::set_vec(double start, double dx_in, double end) {
	int n = (int)(end + dx_in - start) / dx_in;
	size = n;
	for (int i = 0; i < size; i++) vec[i] = start + i * dx_in;
}

Cvec& Cvec::operator=(const double& in) {
	for (int i = 0; i < size; i++) this->vec[i] = Creal(in, 0.0);
	return *this;
}
Cvec& Cvec::operator=(const Creal& in) {
	for (int i = 0; i < size; i++) this->vec[i] = in;
	return *this;
}
Cvec& Cvec::operator=(const Cvec& in) {
	if (this->size != in.size) this->init(in.size);
	for (int i = 0; i < size; i++) this->vec[i] = in.vec[i];
	return *this;
}

Cvec Cvec::operator+(const Cvec& in) {
	if (size != in.size) {
		std::cout << "ERROR, Vectors must have the same length" << std::endl;
		exit(0);
	}
	Cvec out(size);
	for (int i = 0; i < size; i++) out[i] = (*this)[i] + in[i];
	return out;
}
Cvec Cvec::operator+(const double& in) {
	Cvec out(size);
	for (int i = 0; i < size; i++) out[i] = vec[i] + in;
	return out;
}
Cvec Cvec::operator+(const Creal& in) {
	Cvec out(size);
	for (int i = 0; i < size; i++) out[i] = vec[i] + in;
	return out;
}

Cvec Cvec::operator-(const Cvec& in) {
	if (size != in.size) {
		std::cout << "ERROR, Vectors must have the same length" << std::endl;
		exit(0);
	}
	Cvec out(size);
	for (int i = 0; i < size; i++) out[i] = (*this)[i] - in[i];
	return out;
}
Cvec Cvec::operator-(const double& in) {
	Cvec out(size);
	for (int i = 0; i < size; i++) out[i] = vec[i] - in;
	return out;
}
Cvec Cvec::operator-(const Creal& in) {
	Cvec out(size);
	for (int i = 0; i < size; i++) out[i] = vec[i] - in;
	return out;
}

Cvec Cvec::operator/(const double& in) {
	if (in == 0) {
		std::cout << "ERROR: Divide by Zero" << std::endl;
		exit(0);
	}
	Cvec out(size);
	for (int i = 0; i < size; i++) out[i] = vec[i] / in;
	return out;
}
Cvec Cvec::operator/(const Cvec& in) {
	Cvec out(size);
	for (int i = 0; i < size; i++) {
		if (in[i].imag() * in[i].imag() + in[i].real() * in[i].real() == 0) {
			std::cout << "ERROR: Divide by Zero" << std::endl;
			exit(0);
		}
		out[i] = vec[i] / in[i];
	}
	return out;
}
Cvec Cvec::operator/(const Creal& in) {
	Cvec out(size);
	for (int i = 0; i < size; i++) {
		if (in.imag() * in.imag() + in.real() * in.real() == 0) {
			std::cout << "ERROR: Divide by Zero" << std::endl;
			exit(0);
		}
		out[i] = vec[i] / in;
	}
	return out;
}

Cvec Cvec::operator*(const Cvec& in) {
	if (size != in.size) {
		std::cout << "ERROR, Vectors must have the same length" << std::endl;
		exit(0);
	}
	Cvec out(size);
	for (int i = 0; i < size; i++) out[i] = (*this)[i] * in[i];
	return out;
}
Cvec Cvec::operator*(const double& in) {
	Cvec out(size);
	for (int i = 0; i < size; i++) out[i] = vec[i] * in;
	return out;
}
Cvec Cvec::operator*(const Creal& in) {
	Cvec out(size);
	for (int i = 0; i < size; i++) out[i] = vec[i] * in;
	return out;
}


Cvec Cvec::operator+=(const Cvec& in) {
	if (size != in.size) {
		std::cout << "ERROR, Vectors must have the same length" << std::endl;
		exit(0);
	}
	for (int i = 0; i < size; i++) (*this)[i] = (*this)[i] + in[i];
	return *this;
}
Cvec Cvec::operator+=(const double& in) {
	for (int i = 0; i < size; i++) vec[i] = vec[i] + in;
	return *this;
}
Cvec Cvec::operator+=(const Creal& in) {
	for (int i = 0; i < size; i++) vec[i] = vec[i] + in;
	return *this;
}

Cvec Cvec::operator-=(const Cvec& in) {
	if (size != in.size) {
		std::cout << "ERROR, Vectors must have the same length" << std::endl;
		exit(0);
	}
	for (int i = 0; i < size; i++) vec[i] = vec[i] - in[i];
	return *this;
}
Cvec Cvec::operator-=(const double& in) {
	for (int i = 0; i < size; i++) vec[i] = vec[i] - in;
	return *this;
}
Cvec Cvec::operator-=(const Creal& in) {
	for (int i = 0; i < size; i++) vec[i] = vec[i] - in;
	return *this;
}

Cvec Cvec::operator/=(const double& in) {
	if (in == 0) {
		std::cout << "ERROR: Divide by Zero" << std::endl;
		exit(0);
	}
	for (int i = 0; i < size; i++) vec[i] = vec[i] / in;
	return *this;
}
Cvec Cvec::operator/=(const Cvec& in) {
	for (int i = 0; i < size; i++) {
		if (in[i].imag() * in[i].imag() + in[i].real() * in[i].real() == 0) {
			std::cout << "ERROR: Divide by Zero" << std::endl;
			exit(0);
		}
		vec[i] = vec[i] / in[i];
	}
	return *this;
}
Cvec Cvec::operator/=(const Creal& in) {
	for (int i = 0; i < size; i++) {
		if (in.imag() * in.imag() + in.real() * in.real() == 0) {
			std::cout << "ERROR: Divide by Zero" << std::endl;
			exit(0);
		}
		vec[i] = vec[i] / in;
	}
	return *this;
}

Cvec Cvec::operator*=(const Cvec& in) {
	if (size != in.size) {
		std::cout << "ERROR, Vectors must have the same length" << std::endl;
		exit(0);
	}
	for (int i = 0; i < size; i++) vec[i] = (*this)[i] * in[i];
	return *this;
}
Cvec Cvec::operator*=(const double& in) {
	for (int i = 0; i < size; i++) vec[i] = vec[i] * in;
	return *this;
}
Cvec Cvec::operator*=(const Creal& in) {
	for (int i = 0; i < size; i++) vec[i] = vec[i] * in;
	return *this;
}

Creal& Cvec::operator[](int i) {
	if (i < 0 || i >= size) {
		std::cout << "ERROR: Index out of bounds" << std::endl;
		exit(0);
	}
	return vec[i];
}
Creal& Cvec::operator[](int i) const {
	if (i < 0 || i >= size) {
		std::cout << "ERROR: Index out of bounds" << std::endl;
		exit(0);
	}
	return vec[i];
}

void Cvec::save(std::string filename) {
	std::ofstream ofs;
	ofs.open(filename, std::ios::out | std::ios::binary);
	saveHeader(ofs, "1.0");
	saveInt(ofs, size);
	//ofs.write((char*)&size, sizeof(size));
	//ofs.write((char*)&dx, sizeof(dx));
	//std::cout << sizeof(vec) << std::endl << size * sizeof(vec) << std::endl;
	for (int n = 0; n < size; n++) {
		double r = vec[n].real();
		double i = vec[n].imag();
		saveDouble(ofs, r);
		saveDouble(ofs, i);
		//ofs.write((char*)&r, sizeof(r));
		//ofs.write((char*)&i, sizeof(i));
	}
	ofs.close();
}

void Cvec::read(std::string filename) {
	std::ifstream ifs;
	ifs.open(filename, std::ios::in | std::ios::binary);
	readHeader(ifs, "1.0");
	int n = readInt(ifs);
	init(n);

	for (int n = 0; n < size; n++) {
		double r = readDouble(ifs);
		double i = readDouble(ifs);
		vec[n] = r + Creal(0, 1) * i;
	}
	ifs.close();

}