// Clase para manipular Matrices
// Antonio Carrillo Ledesma


public class Matriz <T extends Numero> {

   // Coeficientes de la Matriz
   private Numero [][] M;

   // Numero de Renglones
   private int ren;
   // Numero de Columnas
   private int col;

   // Constructor de la clase
   public Matriz() {
      col = 0;
      ren = 0;
   }


   // Asigna coeficientes
   public void asignaCoeficientes(Numero [][]coef) {
      int i, j;
      ren = coef.length;
      col = coef[0].length;
      M = new Numero[ren][col];
      for (i = 0; i < ren; i++) {
         for (j = 0; j < col; j++) {
            M[i][j] = coef[i][0].nuevo();
            M[i][j]  = coef[i][j];
         }
      }
   }


   // Retorna los coeficientes
   Numero coeficiente(int i, int j) {
      if (i < 0 || i >= ren || j < 0 || j >= col)  System.out.print("Error");
      return M[i][j];
   }


   // Retorna el numero de renglones
   int renglones() {
      return ren;
   }

   // Retorna el numero de columnas
   int columnas() {
      return col;
   }


   // Visualiza la Matriz
   public void visualiza() {
      int i, j;
      for (i = 0; i < ren; i++) {
         for (j = 0; j < col; j++) {
            M[i][j].visualiza();
            System.out.print(" ");
         }
         System.out.println("");
      }
   }

   // Visualiza la Matriz
   public void visualizaLN() {
      visualiza();
      System.out.println("");
   }


   // Suma con dos operandos
   public void suma(Matriz a, Matriz b) {
      int i, j;
      ren = 0;
      col = 0;

      // Revisa el tamano de las Matrices a sumar
      if(a.renglones() != b.renglones() || a.columnas() != b.columnas()) {
         System.out.println("Error, las dimensiones no son iguales");
      } else {
         // Solicita memoria para la Matriz resultante
         ren = a.renglones();
         col = a.columnas();
         M = new Numero[ren][col];

         for (i = 0; i < ren; i++) {
            for (j = 0; j < col; j++) {
               M[i][j] = a.coeficiente(i, j).nuevo();
               M[i][j].suma(a.coeficiente(i, j), b.coeficiente(i, j));
            }
         }
      }
   }


   // Suma con un operando
   public void suma(Matriz a) {
      int i, j;
      ren = 0;
      col = 0;

      // Revisa el tamano de las Matrices a sumar
      if(renglones() != a.renglones() || columnas() != a.columnas()) {
         System.out.println("Error, las dimensiones no son iguales");
      } else {
         // Solicita memoria para la Matriz resultante

         for (i = 0; i < ren; i++) {
            for (j = 0; j < col; j++) {
               M[i][j].suma(a.coeficiente(i, j));
            }
         }
      }
   }


   // Funcion Principal ....
   public static void main(String[] args) {

      // Ejemplito para Matrices de coeficientes Double
      Double [][]r = new Double[2][2];
      r[0][0] = new Double(1);
      r[1][0] = new Double(2);
      r[0][1] = new Double(3);
      r[1][1] = new Double(4);
      Double [][]s = new Double[2][2];
      s[0][0] = new Double(5);
      s[1][0] = new Double(6);
      s[0][1] = new Double(7);
      s[1][1] = new Double(7);

      Matriz<Double> R = new Matriz<Double> ();
      R.asignaCoeficientes(r);
      Matriz<Double> S = new Matriz<Double> ();
      S.asignaCoeficientes(s);
      Matriz<Double> TT = new Matriz<Double> ();

      System.out.println("Double");
      R.visualizaLN();
      System.out.println("+");
      S.visualizaLN();
      TT.suma(R, S);
      System.out.println("=====================");
      TT.visualizaLN();
      System.out.println("");
      System.out.println("");



      // Ejemplito para Matrices de coeficientes Fraccion
      Fraccion [][]a = new Fraccion[2][2];
      a[0][0] = new Fraccion(1, 2);
      a[1][0] = new Fraccion(2, 2);
      a[0][1] = new Fraccion(3, 2);
      a[1][1] = new Fraccion(3, 2);
      Fraccion [][]b = new Fraccion[2][2];
      b[0][0] = new Fraccion(1, 3);
      b[1][0] = new Fraccion(2, 3);
      b[0][1] = new Fraccion(3, 3);
      b[1][1] = new Fraccion(3, 3);

      Matriz<Fraccion> A = new Matriz<Fraccion> ();
      A.asignaCoeficientes(a);
      Matriz<Fraccion> B = new Matriz<Fraccion> ();
      B.asignaCoeficientes(b);
      Matriz<Fraccion> C = new Matriz<Fraccion> ();

      System.out.println("Fraccion");
      A.visualizaLN();
      System.out.println("+");
      B.visualizaLN();
      C.suma(A, B);
      System.out.println("=====================");
      C.visualizaLN();
      System.out.println("");
      System.out.println("");



      // Ejemplito de Matrices de coeficionets Complejos
      Complejos [][]x = new Complejos[2][2];
      x[0][0] = new Complejos(2, 3);
      x[1][0] = new Complejos(2, 2);
      x[0][1] = new Complejos(3, 2);
      x[1][1] = new Complejos(3, 2);
      Complejos [][]y = new Complejos[2][2];
      y[0][0] = new Complejos(-2, -3);
      y[1][0] = new Complejos(2, 3);
      y[0][1] = new Complejos(3, 3);
      y[1][1] = new Complejos(3, 3);
      Matriz<Complejos> X = new Matriz<Complejos>();
      X.asignaCoeficientes(x);
      Matriz<Complejos> Y = new Matriz<Complejos>();
      Y.asignaCoeficientes(y);
      Matriz<Complejos> Z = new Matriz<Complejos>();

      System.out.println("Complejo");
      X.visualizaLN();
      System.out.println("+");
      Y.visualizaLN();
      Z.suma(X, Y);
      System.out.println("=====================");
      Z.visualizaLN();
      System.out.println("");
      System.out.println("");



      // Ejemplito de Matrices de coeficionets ComplejoFraccionario
      ComplejoFraccionario [][]xx = new ComplejoFraccionario[2][2];
      xx[0][0] = new ComplejoFraccionario(2, 3, 4, 5);
      xx[1][0] = new ComplejoFraccionario(2, 2, 3, 7);
      xx[0][1] = new ComplejoFraccionario(3, 2);
      xx[1][1] = new ComplejoFraccionario(3, 2);
      ComplejoFraccionario [][]xy = new ComplejoFraccionario[2][2];
      xy[0][0] = new ComplejoFraccionario(-2, 3, 5, 6);
      xy[1][0] = new ComplejoFraccionario(2, 3, 7, 9);
      xy[0][1] = new ComplejoFraccionario(3, 3);
      xy[1][1] = new ComplejoFraccionario(3, 3);
      Matriz<ComplejoFraccionario> xX = new Matriz<ComplejoFraccionario>();
      xX.asignaCoeficientes(xx);
      Matriz<ComplejoFraccionario> xY = new Matriz<ComplejoFraccionario>();
      xY.asignaCoeficientes(xy);
      Matriz<ComplejoFraccionario> xZ = new Matriz<ComplejoFraccionario>();

      System.out.println("Complejo Fraccionario");
      xX.visualizaLN();
      System.out.println("+");
      xY.visualizaLN();
      xZ.suma(xX, xY);
      System.out.println("=====================");
      xZ.visualizaLN();
      System.out.println("");
      System.out.println("");

   }
}