package AlgLin;

import java.io.*;
import java.util.*;

public class Vecteur extends Matrice {

	 // Constructeur avec un paramètre entier
    public Vecteur(int taille) {
        super(taille, 1); // Appel du constructeur de la classe parente Matrice
    }
    
    // Constructeur avec un paramètre tableau à une dimension de type double
    public Vecteur(double[] tableau) {
        super(tableau.length, 1); // Appel du constructeur de la classe parente Matrice
        for (int i = 0; i < tableau.length; i++) {
            this.coefficient[i][0] = tableau[i]; // Initialisation des coefficients du vecteur
        }
        
    }
   
    
    // Constructeur avec un paramètre correspondant à un nom de fichier
    public Vecteur(String fichier) throws FileNotFoundException {
        super(0, 1); // Appel du constructeur de la classe parente Matrice avec 0 ligne
        try {
            Scanner sc = new Scanner(new File(fichier));
            int taille = sc.nextInt(); // Lire la taille du vecteur à partir du fichier
            this.coefficient = new double[taille][1]; // Créer un vecteur avec la taille lue et une seule colonne
            for (int i = 0; i < taille; i++) {
                this.coefficient[i][0] = sc.nextDouble(); // Remplir les coefficients du vecteur à partir du fichier
            }
            sc.close();
        } catch (FileNotFoundException e) {
            throw new FileNotFoundException("Fichier absent");
        }
    }
    
    
 // Surcharge de la méthode nbLigne pour renvoyer la taille du vecteur
    @Override
    public int nbLigne() {
        return this.coefficient.length;
    }
    
    //Sans surcharge
    public int taille() {
		 if (this.coefficient != null) {
		        return this.coefficient.length;
		    } else {
		        return 0; 
		    }
	    }
    
    // Surcharge de la méthode getCoef pour renvoyer le coefficient du vecteur à une position donnée
       @Override
       public double getCoef(int ligne, int colonne) {
           if (colonne != 0) { // Vérifie que la colonne est égale à 0 car un vecteur a toujours une seule colonne
               throw new IllegalArgumentException("La colonne doit être 0 pour un vecteur");
           }
           return super.getCoef(ligne, colonne); // Appel de la méthode getCoef de la classe parente Matrice
       }
       
       
    
       //Sans surcharge, prenant un seul parametre de type entier
       // Renvoyer le coefficient du vecteur à une position donnée, sans toujours mettre le second paramettre à 0
          public double getCoef(int position) {
              if (position < 0 || position >= this.nbLigne()) {
                  throw new IllegalArgumentException("Position invalide");
              }
              return this.coefficient[position][0]; // Dans un vecteur, la colonne est toujours 0
          }  

       // Méthode pour remplacer un coefficient du vecteur sans vérification
       public void remplacerCoefficient(int position, double valeur) {
           this.coefficient[position][0] = valeur;
       }

    
       // Méthode pour remplacer un coefficient du vecteur avec vérification
       public void verif_remplacerCoefficient(int position, double valeur) {
           if (position < 0 || position >= this.nbLigne()) {
               throw new IllegalArgumentException("Position invalide");
           }
           this.coefficient[position][0] = valeur;
       }
   
   
    // Affichage du vecteur en colonne
       @Override
       public String toString() {
           StringBuilder builder = new StringBuilder();
           for (int i = 0; i < this.nbLigne(); i++) {
               builder.append(this.getCoef(i, 0)).append("\n"); // Ajout du saut de ligne après chaque coefficient
           }
           return builder.toString();
       }

    // Affichage en ligne
    public String toString1() {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < this.nbLigne(); i++) {
            if (i == 0) {
                builder.append(this.getCoef(i, 0));
            } else {
                builder.append(" ").append(this.getCoef(i, 0));
            }
        }
        return builder.toString();
    }
    
    // Calcul du produit scalaire entre deux vecteurs sans vérification
    public static double produitScalaire(Vecteur v1, Vecteur v2) {
        double produit = 0;
        for (int i = 0; i < v1.nbLigne(); i++) {
            produit += v1.getCoef(i, 0) * v2.getCoef(i, 0);
        }
        return produit;
    }
    
    // Calcul du produit scalaire entre deux vecteurs avec vérification
    public static double verif_produitScalaire(Vecteur v1, Vecteur v2) {
        if (v1.nbLigne() != v2.nbLigne()) {
            throw new IllegalArgumentException("Les deux vecteurs doivent avoir la même taille");
        }
        double produit = 0;
        for (int i = 0; i < v1.nbLigne(); i++) {
            produit += v1.getCoef(i, 0) * v2.getCoef(i, 0);
        }
        return produit;
    }
    
    
    //Ajout des méthodes permettant de calculer les normes
    
    // Calcul de la norme L1 du vecteur
    public double normeL1() {
        double norme = 0.0;
        for (int i = 0; i < taille(); i++) {
            norme += Math.abs(getCoef(i)); // la somme des valeurs absolue des coeffs de 1 a n
        }
        return norme;
    }

    // Calcul de la norme L2 du vecteur
    public double normeL2() {
        double norme = 0.0;
        for (int i = 0; i < taille(); i++) {
            norme += getCoef(i) * getCoef(i); // on obtient la somme des carré des coeffs
        }
        return Math.sqrt(norme); // On fait la racine carré de ce resultat
    }

    // Calcul de la norme Linfini du vecteur
    public double normeLinfini() {
        double norme = 0.0;
        for (int i = 0; i < taille(); i++) {
            norme = Math.max(norme, Math.abs(getCoef(i))); // la valeurs absolue maximale des coeffs
        }
        return norme;
    }
    
    
    //ajout d'une methode static de soustraciton pour le TP4 : 
    public static Vecteur soustraction(Vecteur vec1, Vecteur vec2) {
        if (vec1.taille() != vec2.taille()) {
            throw new IllegalArgumentException("les vecteurs doivent avoir la même taille pour la soustraction");
        }
        double[] resultat = new double[vec1.taille()];
        for (int i = 0; i < vec1.taille(); i++) {
            resultat[i] = vec1.getCoef(i) - vec2.getCoef(i);
        }
        return new Vecteur(resultat);
    }
    
    // Produit matrice-vecteur
    public static Vecteur produitMatriceVecteur(Matrice m, Vecteur v) {
        if (m.nbColonne() != v.taille()) {
            throw new IllegalArgumentException("Le nombre de colonnes de la matrice doit être égal à la taille du vecteur");
        }
        
        int lignes = m.nbLigne();
        Vecteur resultat = new Vecteur(lignes);
        
        for (int i = 0; i < lignes; i++) {
            double somme = 0.0;
            for (int j = 0; j < m.nbColonne(); j++) {
                somme += m.getCoef(i, j) * v.getCoef(j);
            }
            resultat.remplacerCoefficient(i, somme);
        }
        return resultat;
    }

     
    public static void main(String[] args) {
        try {
            // Test du constructeur avec un paramètre entier
            Vecteur vecteur1 = new Vecteur(3);
            System.out.println("Vecteur 1 initialisé avec taille 3 : \n" + vecteur1);
           
            //tests des tailles
            System.out.println("Taille du vecteur 1 : " + vecteur1.nbLigne());
            System.out.println("Taille du vecteur 1 : " + vecteur1.taille());

            //modifications des coefficients
            vecteur1.remplacerCoefficient(0, 1.0);
            vecteur1.remplacerCoefficient(1, 2.0);
            vecteur1.remplacerCoefficient(2, 3.0);
            //testé et affiche ("Erreur : Position invalide")
            /*
            vecteur1.verif_remplacerCoefficient(7, 5.0);
            System.out.println("Vecteur 1 après remplacement avec vérification :\n" + vecteur1);
            */
            System.out.println("Vecteur 1 après modification des coefficients :\n" + vecteur1);
            
            //récupérations des coefficients (doit afficher le même résultats
            System.out.println("Le coefficient à la 3e ligne  :\n" + vecteur1.getCoef(2, 0));
            System.out.println("Le coefficient à la 3e ligne  :\n" + vecteur1.getCoef(2));
            
            //tests des deux toString
            System.out.println("Affichage en colonne : \n" + vecteur1.toString());
            System.out.println("Affichage en ligne : " + vecteur1.toString1());
            
        
            // Test vecteur avec constructeur avec un tableau de doubles
            double[] tableau = {1.0, 2.0, 3.0};
            Vecteur vecteur2 = new Vecteur(tableau);
            System.out.println("Vecteur 2 initialisé avec un tableau : \n" + vecteur2);
            
            //tests des tailles
            System.out.println("Taille du vecteur 2 : " + vecteur2.nbLigne());
            System.out.println("Taille du vecteur 2 : " + vecteur2.taille());
            
            //modifications des coefficients
            vecteur2.remplacerCoefficient(0, 4.0);
            vecteur2.remplacerCoefficient(1, 5.0);
            vecteur2.remplacerCoefficient(2, 6.0);
            
            //testé et affiche ("Erreur : Position invalide")
            /*
            vecteur1.verif_remplacerCoefficient(10, 7.0);
            System.out.println("Vecteur 2 après remplacement avec vérification :\n" + vecteur2);
            */
            System.out.println("Vecteur 2 après modification des coefficients :\n" + vecteur2);
            
            //récupérations des coefficients (doit afficher le même résultats
            System.out.println("Le coefficient à la 2e ligne  :\n" + vecteur2.getCoef(1, 0));
            System.out.println("Le coefficient à la 2e ligne  :\n" + vecteur2.getCoef(1));
            
            //tests des deux toString
            System.out.println("Affichage en colonne : \n" + vecteur2.toString());
            System.out.println("Affichage en ligne : " + vecteur2.toString1());
  

            // Test du constructeur avec un fichier
            Vecteur vecteur3 = new Vecteur("vecteur1.txt");
            System.out.println("Vecteur 3 initialisé à partir d'un fichier : \n" + vecteur3);

            
            //tests des tailles
            System.out.println("Taille du vecteur 3 : " + vecteur3.nbLigne());
            System.out.println("Taille du vecteur 3: " + vecteur3.taille());
            
            //modifications des coefficients
            vecteur3.remplacerCoefficient(0, 40.0);
            vecteur3.remplacerCoefficient(1, 50.0);
            vecteur3.remplacerCoefficient(2, 60.0);
            
            //testé et affiche ("Erreur : Position invalide")
            /*
            vecteur1.verif_remplacerCoefficient(10, 100.0);
            System.out.println("Vecteur 3 après remplacement avec vérification :\n" + vecteur3);
            */
            System.out.println("Vecteur 3 après modification des coefficients :\n" + vecteur3);
            
            //récupérations des coefficients (doit afficher le même résultats
            System.out.println("Le coefficient à la 2e ligne  :\n" + vecteur3.getCoef(0, 0));
            System.out.println("Le coefficient à la 2e ligne  :\n" + vecteur3.getCoef(0));
            
            //tests des deux toString
            System.out.println("Affichage en colonne : \n" + vecteur3.toString());
            System.out.println("Affichage en ligne : " + vecteur3.toString1());
           
            // Test du produit scalaire (verification exterieur avant d'appeler la méthode )
            if (vecteur2.nbLigne() == vecteur3.nbLigne()) {
                double produitScalaire = Vecteur.produitScalaire(vecteur2, vecteur3);
                System.out.println("Produit scalaire entre le vecteur 2 et le vecteur 3 : " + produitScalaire);
            } else {
                System.out.println("Les vecteurs 2 et 3 n'ont pas la même taille. Produit scalaire impossible.");
            }
            
            // avec vérification
            try {
                double verifProduitScalaire = Vecteur.verif_produitScalaire(vecteur1, vecteur2);
                System.out.println("Produit scalaire vérifié entre le vecteur 1 et le vecteur 2 : " + verifProduitScalaire);
            } catch (IllegalArgumentException e) {
                System.out.println("Erreur lors du calcul du produit scalaire vérifié : " + e.getMessage());
            }
            
            
            // Voir si le cas échéant fonctionne
            double[] tabEchec = {1.0, 2.0, 3.0,4.0};
            Vecteur vecteurEchec= new Vecteur(tabEchec);
            // Test du produit scalaire avec vérification
            
            // Test du produit scalaire 
            if (vecteur2.nbLigne() == vecteurEchec.nbLigne()) {
                double produitScalaireEchec = Vecteur.produitScalaire(vecteur2, vecteurEchec);
                System.out.println("Produit scalaire entre le vecteur 2 et le vecteurEchec : " + produitScalaireEchec);
            } else {
                System.out.println("Le vecteur2 et vecteurEchec n'ont pas la même taille. Produit scalaire impossible.");
            }
            
            // avec methode vérification
            try {
                double verifProduitScalaire = Vecteur.verif_produitScalaire(vecteur2, vecteurEchec);
                System.out.println("Produit scalaire vérifié entre le vecteur 2 et le vecteurEchec : " + verifProduitScalaire);
            } catch (IllegalArgumentException e) {
                System.out.println("Erreur lors du calcul du produit scalaire vérifié : " + e.getMessage());
            }
        } catch (FileNotFoundException e) {
            System.out.println("Erreur : fichier non trouvé (" + e.getMessage() + ").");
        } catch (IllegalArgumentException e) {
            System.out.println("Erreur : " + e.getMessage());
        }
    }

}
