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

// TODO Matrix-Funktionen implementieren

/*Matrix createMatrix(unsigned int rows, unsigned int cols) {
    Matrix matrix;
    matrix.rows = rows;
    matrix.cols = cols;
    matrix.buffer = NULL;

    if(rows>0 && cols>0) {
        matrix.buffer = (MatrixType **)malloc(rows * sizeof(MatrixType *));                             // Speicher für Zeiger auf Zeilen
        if(matrix.buffer == NULL) {
            matrix.rows = 0;
            matrix.cols = 0;
            return matrix;
        }

        for(int i=0;i<rows;i++) {
            matrix.buffer[i] = (MatrixType *)malloc(cols * sizeof(MatrixType));                         // Speicher für jede Zeile (Spalten)
            if(matrix.buffer[i] == NULL) {                                                             // Wenn fehler, dann freigeben
                for(int j=0;j<i;j++) {
                    free(matrix.buffer[j]);
                }
                free(matrix.buffer);
                matrix.buffer = NULL;
                matrix.rows = 0;
                matrix.cols = 0;
                return matrix;
            }
        }
        
        for(int i;i<rows;i++){
            for(int ii;ii<cols;ii++){
                matrix.buffer[i][ii] = UNDEFINED_MATRIX_VALUE;
            }
        }
    }

    return matrix;
}*/
Matrix createMatrix(unsigned int rows, unsigned int cols) {
    Matrix matrix;
    matrix.rows = 0;
    matrix.cols = 0;
    matrix.buffer = NULL;

    if (rows > 0 && cols > 0) {
        matrix.buffer = malloc(rows * cols * sizeof(MatrixType));
        if (matrix.buffer == NULL) {
            return matrix;
        }
        matrix.rows = rows;
        matrix.cols = cols;
        memset(matrix.buffer, UNDEFINED_MATRIX_VALUE, rows*cols);

    }

    return matrix;
}

void clearMatrix(Matrix *matrix)
{
    free(matrix->buffer);
    matrix->rows = 0;
    matrix->cols = 0;
    matrix->buffer = NULL;
    free(matrix->buffer);
}

void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
    if(rowIdx<(matrix.rows) && colIdx<(matrix.cols)){
        matrix.buffer[matrix.cols*rowIdx + colIdx]=value;
    }
}

MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
    if(rowIdx<(matrix.rows) && colIdx<(matrix.cols)){
        return matrix.buffer[matrix.cols*rowIdx + colIdx];
    }
    else{
        return UNDEFINED_MATRIX_VALUE;
    }
}

Matrix add(const Matrix matrix1, const Matrix matrix2)
{
    Matrix output = {.rows=0, .cols=0, .buffer=NULL};

    if(matrix1.rows==matrix2.rows && matrix1.cols==matrix2.cols){
        output.rows = matrix1.rows;
        output.cols = matrix1.cols;
        for (int i=0;i<matrix1.rows*matrix1.cols;i++){
            output.buffer[i]= matrix1.buffer[i]+matrix2.buffer[i];
        }
    }
    return output;
}

Matrix multiply(const Matrix matrix1, const Matrix matrix2)
{
    Matrix output = {.rows=0, .cols=0, .buffer=NULL};
    if(matrix1.cols==matrix2.rows){
        output.rows = matrix1.rows;
        output.cols = matrix2.cols;
        memset(output.buffer, 0 ,output.rows*output.cols);
        for (int spalte2=0;spalte2<output.cols;spalte2++){
            for (int zeile1=0;zeile1<matrix1.rows;zeile1++){
                for (int zeile2=0;zeile2<matrix2.rows;zeile2++){
                    output.buffer[zeile1*output.cols+spalte2]= output.buffer[zeile1*output.cols+spalte2] + (matrix1.buffer[zeile1*matrix1.cols+zeile2]*matrix2.buffer[zeile2*matrix2.cols+spalte2]);
                }
            }
        }
    }
    return output;
}