#include <vector>
#include "Biginteger.h"
#include <iostream>

using namespace std;

Biginteger::Biginteger()
{
}
Biginteger::Biginteger(vector<int> value)
{
	digits = value;
}
Biginteger::Biginteger(int value)
{
	setValue(value);
}
void Biginteger::setSize(int size)
{
	digits.resize(size);
}
void Biginteger::setValue(vector<int> value)
{
	digits = value;
}
void Biginteger::setValue(int value)
{
	int counter = 0;
	vector<int> value_array = { value % 10 };
	int value_copy = value / 10;
	while (value_copy != 0)
	{
		if (value_array.size() <= counter)
			value_array.push_back(value_copy % 10);
		else
			value_array[counter] = value_copy % 10;
		counter++;
		value_copy /= 10;
	}
	digits = value_array;
}

void Biginteger::carryAddMul(int position, Biginteger& number)
{
	if (number.getSize() <= position + 1)
		number.push_back(0);
	number[position + 1] += number[position] / 10;		 //Höherer Ziffer den Zehntel des gegebenen Wertes zuweisen
	number[position] -= (number[position] / 10) * 10;	//Zweite Ziffer der niederwertigen Ziffer entfernen
	if (number[position + 1] >= 10)						//Testen, ob höherwertige Ziffer mehr als eine Stelle hat
		carryAddMul(position + 1, number);				//rekursiv aufrufen, um die Stelle auf die jeweils höherwertige Ziffer zu übertragen
}
void Biginteger::push_back(int number)
{
	digits.push_back(number);
}
Biginteger Biginteger::multiplicate(Biginteger firstfactor, Biginteger secondfactor)
{
	Biginteger product; 
	product.setSize(firstfactor.getSize() + secondfactor.getSize() - 1); //Vektor mit Größe 
	for (int ff = 0; ff < firstfactor.getSize(); ff++)
	{
		for (int sf = 0; sf < secondfactor.getSize(); sf++)
		{
			product[sf + ff] += firstfactor[ff] * secondfactor[sf];
			if (product[sf + ff] >= 10)
				carryAddMul(sf + ff, product);
		}
	}
	return product;
}
Biginteger Biginteger::add(Biginteger firstsummand, Biginteger secondsummand)
{
	Biginteger sum;
	sum.setSize(firstsummand.getSize() > secondsummand.getSize() ? firstsummand.getSize() : secondsummand.getSize()); 
	for (int i = 0; i < (firstsummand.getSize() > secondsummand.getSize() ? firstsummand.getSize() : secondsummand.getSize()); i++)
	{
		if (i >= (firstsummand.getSize() < secondsummand.getSize() ? firstsummand.getSize() : secondsummand.getSize()))
		{
			sum[i] += firstsummand.getSize() > secondsummand.getSize() ? firstsummand[i] : secondsummand[i];
		}
		else
		{
			sum[i] += firstsummand[i] + secondsummand[i];
			
		}
		if (sum[i] >= 10)
			carryAddMul(i, sum);
	}
	return sum;
}
bool Biginteger::equalsone()
{
	for (int i = 1; i < digits.size(); i++)
	{
		if (digits[i] != 0)
			return false;
	}
	if (digits[0] == 1)
		return true;
	else
		return false;
}
void Biginteger::carrySub(int position, Biginteger& number)
{
	number[position + 1]--;
	number[position] += 10; //Zahl von höherwertiger Ziffer holen
	if (number[position + 1] < 0) //Testen, ob höherwertige Zahl nun kleiner null ist 
		carrySub(position + 1, number); //rekursiv aufrufen, um die negative Stelle zu berichtigen
}
Biginteger Biginteger::substracte(Biginteger minuend, Biginteger subtrahent)
{
	for (int i = 0; i < subtrahent.getSize(); i++)
	{
		minuend[i] -= subtrahent[i];
		if (minuend[i] < 0)
			carrySub(i, minuend);
	}
	return minuend;
}
Biginteger Biginteger::factorial(Biginteger factor) //Standard-Fakultätfunktion auf std::vector angepasst
{
	if (!factor.equalsone())
		return multiplicate(factor, factorial(substracte(factor, { 1 })));
	else
		return{ 1 };
}
int Biginteger::at(int position)
{
	return digits[position];
}
int Biginteger::getSize()
{
	return digits.size();
}
vector<int> Biginteger::getValue()
{
	return digits;
}
Biginteger operator+ (const Biginteger& firstsummand, const Biginteger& secondsummand)
{
	return Biginteger::add(firstsummand, secondsummand);
}
Biginteger operator*(const Biginteger& firstfactor, const Biginteger& secondfactor)
{
	return Biginteger::multiplicate(firstfactor, secondfactor);
}
Biginteger Biginteger::operator=(Biginteger number)
{
	digits = number.getValue();
	return *this;
}
Biginteger Biginteger::operator=(vector<int> number)
{
	digits = number;
	return *this;
}
Biginteger Biginteger::operator=(int number)
{
	setValue(number);
	return *this;
}
int& Biginteger::operator[](int number) 
{
	return digits[number];
}
Biginteger Biginteger::operator+=(const Biginteger& summand)
{
	return Biginteger::add(*this, summand);
}
