#pragma once

/**
 * \file Vect.h
 * \brief Contient la définition d'un espace affine et d'un espace vectoriel
 */

#include "Matrix.h"

/**
 * \class Vect
 * \brief Représente une base d'un espace vectoriel de dimension finie
 */
class Vect {
  private:
	Matrix m_Data;

  public:
	/**
	 * \brief Construit une base d'un espace vectoriel à partir des colonnes d'une matrice.
	 * Les colonnes de 0 sont ignorées
	 * \param a_Matrix Une matrice échelonnée.
	 */
	Vect(Matrix&& a_Matrix);

	/**
	 * \brief Permet d'obtenir le ieme vecteur de la base
	 * \param a_Index l'index du vecteur souhaité
	 * \return Une matrice colonne
	 */
	Matrix GetVector(std::size_t a_Index) const;

	/**
	 * \brief Retourne le nombre de coordonnées des vecteurs de la base (leur nombre de colonne)
	 */
	std::size_t GetDimension() const;

	/**
	 * \brief Retourne le nombre de vecteur de la base
	 */
	std::size_t GetCardinal() const;

	/**
	 * \brief Exprime l'espace vectoriel comme les solutions d'un système linéaire des coordonnées des vecteurs
	 * \return Une matrice représentant le système linéaire
	 */
	Matrix GetLinearSystem() const;

	/**
	 * \brief Concatène la base actuelle avec un nouveau vecteur
	 * \param a_Vector Une matrice colonne de taille GetDimension()
	 */
	void AddVector(const Matrix& a_Vector);

	/**
	 * \brief Vérifie si le vecteur spécifié appartient au sous-espace vectoriel
	 * \param a_Vector Une matrice colonne représentant le vecteur à tester
	 */
	bool IsElementOf(const Matrix& a_Vector) const;

	bool operator==(const Vect& a_Other) const;
	bool operator!=(const Vect& a_Other) const;

  private:
	void Simplify();

	friend class VectAffine;
};

/**
 * \class VectAffine
 * \brief Représente un espace affine
 */
class VectAffine {
  private:
	Vect m_Base;
	Matrix m_Origin;

  public:
	/**
	 * \brief Construit un espace affine à partir d'un espace vectoriel et d'une origine
	 * \param a_Base La base de l'espace vectoriel
	 * \param a_Origin Le vecteur d'origine (matrice colonne)
	 */
	VectAffine(const Vect& a_Base, const Matrix& a_Origin);

	/**
	 * \brief Retourne l'espace vectoriel correspondant
	 */
	const Vect& GetBase() const {
		return m_Base;
	}

	/**
	 * \brief Retourne l'origine de l'espace affine
	 * \return Un vecteur colonne
	 */
	const Matrix& GetOrigin() const {
		return m_Origin;
	}

	/**
	 * \brief Vérifie si le vecteur spécifié appartient à l'espace affine
	 * \param a_Vector Une matrice colonne représentant le vecteur à tester
	 */
	bool IsElementOf(const Matrix& a_Vector) const;

	/**
	 * \brief Exprime l'espace vectoriel comme les solutions d'un système linéaire des coordonnées des vecteurs
	 * \return Une matrice représentant le système linéaire
	 */
	Matrix GetLinearSystem() const;

	bool operator==(const VectAffine& a_VectAffine) const {
		return m_Origin == a_VectAffine.GetOrigin() && m_Base == a_VectAffine.GetBase();
	};
};