package mardaus.blatt13;

class Matrix {
	/** Konstruktor für n x n */
	public Matrix(int n) {
		matrix = new double[n][n];
	}
	
	/** m.setElement(i,j,x) bedeutet M_ij = x */
	public void setElement(int i, int j, int x) {
		if (i<0 || j<0 || i>=matrix.length || j>=matrix.length) System.out.println("Fehlerhafter Index");
		else matrix[i][j] = x;
	}
	/** m.getElement gibt Element an ij aus */
	public double getElement(int i, int j) { 
		try { return matrix[i][j]; }
		catch (Exception e){
			System.out.println("mindestens ein fehlerhafter Index");
			return -1;
		}
	}
	
	
	/** length Funktion fuer qu. Matrizen */
	public int length(){ return matrix.length; }
	
	/** m.add(a,b) bedeutet m = a+b */
	public void add(Matrix a, Matrix b) {
		if (a.length()!=b.length()) System.out.println("Fehlerhafte Matrixdimensionen");
		else 
			for(int i=0;i<a.length();i++)
				for(int j=0;j<a.length();j++)
					matrix[i][j] = a.matrix[i][j]+b.matrix[i][j];
	}
	
	/** m.sub(a,b) bedeutet m = a-b */
	public void sub(Matrix a, Matrix b) {
		if (a.length()!=b.length()) System.out.println("Fehlerhafte Matrixdimensionen");
		else 
			for(int i=0;i<a.length();i++)
				for(int j=0;j<a.length();j++)
					matrix[i][j] = a.matrix[i][j]-b.matrix[i][j];
	}
	
	/** m.mul(a,b) bedeutet m = a*b (Matrixmultipl.) */
	public void mul(Matrix a, Matrix b){
		double[][]tmp = new double[matrix.length][matrix.length];
		double[][]tmpa = a.matrix;
		double[][]tmpb = b.matrix;
		try{
			for (int i = 0; i < tmpa.length; i++)
				for (int j = 0; j < tmpb[0].length; j++)
					for (int k = 0; k < Math.max(tmpa[0].length,tmpb.length); k++)
						// Maximum damit er bei dim.Fehler Exception bekommt
						tmp[i][j] += tmpa[i][k] * tmpb[k][j];
			matrix = tmp;
		}
		catch (Exception e){
			System.out.println("Fehlerhafte Matrixdimensionen");
		}
	}
	
	/** Matrix transponieren */
	public void transpose(){
		// tausch der elemente oberhalb der hauptdiag mit den jeweiligen unterhalb
		for(int i=0;i<matrix.length;i++)
			for(int j=i+1;j<matrix.length;j++){
				double tmp = matrix[i][j];
				matrix[i][j] = matrix[j][i];
				matrix[j][i] = tmp;
			}	
	}
	
	private double factorial(int n){
		double fuck=1;
		// auch 0!=1 ist kein problem
		for(int i=1;i<=n;i++) // ich denke das is klar
			fuck*=i;
		return fuck;
	}
	
	public void exp(int schritte){
		/*Matrix org = new Matrix(2); org.matrix[0][0]=0;
		Matrix summand = new Matrix(2); summand.matrix[0][0]=0;
		Matrix mpot = new Matrix(2); mpot.matrix[0][0]=0;
		*/
		Matrix org = new Matrix(2);
		org.matrix = this.copy();
		Matrix summe = new Matrix(2); summe.matrix[0][0] = summe.matrix[1][1] = 1;
		Matrix summand = new Matrix(2);
		Matrix mpot = new Matrix(2);
		mpot.matrix = org.copy();
		for(int i=1;i<=schritte;i++){
			summand.matrix = mpot.copy();
			summand.multElem(1/factorial(i));
			summe.add(summe,summand);
			mpot.mul(mpot,org);
		}
		matrix = summe.matrix;
	}
		
	private double[][] copy(){
		double[][]kopie = new double[matrix.length][matrix.length];
		for(int i=0;i<matrix.length;i++)
			for(int j=0;j<matrix.length;j++)
				kopie[i][j]=matrix[i][j];
		return kopie;
	}
	
	public void multElem(double x ){
		for(int i=0;i<matrix.length;i++)
			for(int j=0;j<matrix.length;j++)
				matrix[i][j] = matrix[i][j]*x;
	}
	
	/** Ausgabe */
	public void print() {
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[0].length; j++)
				System.out.print(matrix[i][j]+" ");
			System.out.println();
		}
	}
		
	private
	double[][] matrix;
}
