#include <stdlib.h>
#include <string.h>
#include "matrix.h"

// TODO Matrix-Funktionen implementieren

Matrix createMatrix(unsigned int rows, unsigned int cols)
{
    if(rows <= 0 || cols <= 0){
        Matrix matrix = { NULL , 0 , UNDEFINED_MATRIX_VALUE };
        return matrix;
    }

    Matrix matrix = { 0 ,rows , cols };

    matrix.buffer = malloc((sizeof(MatrixType)*rows*cols));

    return matrix;
}

void clearMatrix(Matrix *matrix)
{
   free(matrix->buffer);

    matrix->buffer = NULL;
    matrix->rows = 0;
    matrix->cols = 0;
}

void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
    *(matrix.buffer + (rowIdx * matrix.cols + colIdx)) = value;

}

MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
    if(matrix.rows <= rowIdx || matrix.cols <= colIdx)
    return UNDEFINED_MATRIX_VALUE;

    MatrixType value;
    value = *(matrix.buffer + (rowIdx * matrix.cols + colIdx));
    return value;
}

Matrix add(const Matrix matrix1, const Matrix matrix2)
{
    int matrixResultCols;

	//abgleichen welche matrix die größere spalten anzahl besitzt
    if(matrix1.cols <= matrix2.cols){
        matrixResultCols = matrix2.cols;
    }
    else{
        matrixResultCols = matrix1.cols;
    }

	//Matrix für das ergebnis generieren
    Matrix result = createMatrix(matrix1.rows, matrixResultCols);

	//prüfen auf gleiche Reihenanzahl
    if(matrix1.rows != matrix2.rows){

        result.buffer = NULL;
        result.rows = 0;
        result.cols = 0;
        return result;
    }

	//Addition bei gleicher spalten Anzahl
    if(matrix1.cols == matrix2.cols){
        for(int i = 0; i < matrix1.rows; i++){
           for(int j = 0; j < matrix1.cols; j++){
              *(result.buffer + (matrix1.cols * i + j)) = *(matrix1.buffer + (matrix1.cols * i + j)) + *(matrix2.buffer + (matrix2.cols * i + j)) ;
            }
        }
    }

	//Addition wenn matrix1 nur eine Spalte hat
    if((matrix1.cols ==1 && matrix2.cols != 1)){
       for(int i = 0; i < matrix2.rows; i++){
          for(int j = 0; j < matrix2.cols; j++){
              *(result.buffer + (result.cols * i + j)) = *(matrix2.buffer + (matrix2.cols * i + j)) + *(matrix1.buffer + i);
           }
        }
    }

	//Addition wenn matrix2 nur eine Spalte hat
   if((matrix2.cols == 1 && matrix1.cols != 1)){
       for(int i = 0; i < matrix1.rows; i++){
           for(int j = 0; j < matrix1.cols; j++){
               *(result.buffer + (result.cols * i + j)) = *(matrix1.buffer + (matrix1.cols * i + j)) + *(matrix2.buffer + i);
           }
       }
   }

    return result;
}

Matrix multiply(const Matrix matrix1, const Matrix matrix2)
{
    if (matrix1.cols != matrix2.rows) {
        Matrix invalid = {NULL ,0, 0};
        return invalid;
    }

    Matrix result = createMatrix(matrix1.rows, matrix2.cols);
    if (result.buffer == NULL)
    return result;


    for (unsigned int i = 0; i < matrix1.rows; i++){
	    for (unsigned int j = 0; j < matrix2.cols; j++){
	        *(result.buffer + (i * result.cols + j)) = 0;

			for (unsigned int k = 0; k < matrix1.cols; k++){
			    *(result.buffer + (i * result.cols + j)) += *(matrix1.buffer + (i * matrix1.cols + k)) * *(matrix2.buffer + (k * matrix2.cols + j));
       		}
    	}
	}

return result;
}