#include <algorithm>
#include <filesystem>
#include <fstream>
#include <iostream>

#include "IO.h"
#include "Solver.h"
#include "test_assert.h"

namespace fs = std::filesystem;

const static int EXECUTION_COUNT = 10000;
static constexpr int MATRIX_MAX_SIZE = 7;

static int GetRandomSize() {
	return rand() % MATRIX_MAX_SIZE + 1;
}

static int GetRandomInt() {
	return GetRandomSize();
}

static Matrix GetRandomMatrix(std::size_t a_Raw, std::size_t a_Column) {
	Matrix matrix {a_Raw, a_Column};

	std::generate(matrix.GetLineIterator(0), matrix.GetLineIterator(a_Raw), []() { 
		return GetRandomInt(); 
	});

	return matrix;
}

void TestRectangular(const Matrix& system, const Matrix& origin) {
	Solver solver;

	VectAffine solution = solver.RectangularSystem(std::move(Matrix(system)), origin);

	for (std::size_t i = 0; i < solution.GetBase().GetCardinal(); i++) {
		Matrix vector = solution.GetBase().GetVector(i) + solution.GetOrigin();
		Matrix product = system * vector;
		test_assert(product == origin);
	}
}

void RandomRectangular() {
	for (int i = 0; i < EXECUTION_COUNT; i++) {

		Matrix system = GetRandomMatrix(GetRandomSize(), GetRandomSize());

		Matrix origin = GetRandomMatrix(system.GetRawCount(), 1);

		TestRectangular(system, origin);
	}
}

void TestKernelImage() {
	std::string path = "test";
	for (const auto& entry : fs::directory_iterator(path)) {
		std::string fileName = entry.path().string();

		std::cout << "Opening " << fileName << " ...\n";

		std::ifstream in {fileName};

		Matrix mat, imageMat, noyauMat;
		in >> mat >> imageMat >> noyauMat;

		Vect image {std::move(imageMat)};
		Vect noyau {std::move(noyauMat)};

		Solver solver;

		Matrix copy = mat;

		Vect imageCalc = solver.Image(std::move(copy));
		Vect kernelCalc = solver.Kernel(std::move(mat));

		test_assert(imageCalc == image);
		test_assert(kernelCalc == noyau);
	}
}

int main() {
	srand(time(0));
	TestKernelImage();
	RandomRectangular();
	return 0;
}