#ifndef MATRIX_H
#define MATRIX_H

#include "matrix_data.h"
#include "list_data.h"
#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <math.h>

#define MATRIX_DEBUG

/*
 * Alokuje matici o rozmerech M x N.
 */
matrix * matrix_alloc (unsigned int M, unsigned int N);

/*
 * Uvolni z pameti matici.
 */
void matrix_free (matrix * mat);

/*
 * Posune sloupce matice MAT o hodnotu RIGHT. Pokud je RIGHT kladne tak se
 * sloupce posunou doprava o tuto hodnotu. V pripade ze je RIGHT zaporne tak
 * naopak.
 */
void matrix_move_m (matrix *mat, int right);

/*
 * Vytvori kopii matice MAT.
 */
matrix * matrix_clone (matrix * mat);
unsigned int matrix_size_m (matrix * mat);
unsigned int matrix_size_n (matrix * mat);
void matrix_set (matrix * mat, unsigned int i, unsigned int j, double value);
double matrix_get (matrix * mat, unsigned int i, unsigned int j);

#define MATRIX_NUM_CHARS 10
unsigned long matrix_save_length(matrix *mat);
char *matrix_save_save_string(matrix *mat);
int matrix_save(matrix *mat, char *file);
matrix *matrix_load_string(char *str);

matrix *matrix_submatrix(matrix *mat, unsigned int m, unsigned int n, unsigned int i, unsigned int j);
int matrix_equal (matrix * A, matrix * B);
void matrix_print (matrix * mat);
void matrix_print_info (matrix * mat);
int matrix_not_null (matrix * mat);

matrix *matrix_rand_int(unsigned int m, unsigned int n);
matrix *matrix_rand_int_no_repeating(unsigned int m, unsigned int n);
matrix *matrix_reshuffle_impossible (matrix *mat, matrix *impossible);
void matrix_zeros (matrix *mat);
#define MATRIX_LINSPACE_ROW 0
#define MATRIX_LINSPACE_COLUMN 1
matrix *matrix_linspace(unsigned int m, unsigned int n, double a, double b, int how);
#define MATRIX_CAT_HORIZONTALLY 0
#define MATRIX_CAT_VERTICALLY 1
matrix *matrix_cat(matrix *A, matrix *B, unsigned int how);
matrix *matrix_cat_list(list *L, unsigned int how);

matrix *matrix_transpose(matrix *mat);
double matrix_forbenius_norm (matrix *mat);
matrix *matrix_new_transposed (matrix *A);
matrix *matrix_multiply (matrix *A, matrix *B);
matrix *matrix_multiply_constant (matrix *A, double c);
matrix *matrix_adition (matrix *A, matrix *B);
matrix *matrix_substraction (matrix *A, matrix *B);
matrix *matrix_inverse(matrix *A);

matrix *matrix_levinson_durbin(matrix *R /* Musi byt symetricka matice (Töplitzova) */, unsigned int P);

double matrix_sum(matrix *mat);
matrix *matrix_sum_horizontaly (matrix *mat);
matrix *matrix_sum_verticaly (matrix *mat);
double matrix_mean(matrix *mat);
matrix *matrix_row_mean(matrix *mat);
matrix *matrix_row_stdev(matrix *mat);
matrix *matrix_row_max(matrix *mat);

matrix *matrix_boolean(matrix *mat);
matrix *matrix_neg(matrix *mat);
matrix *matrix_and(matrix *A, matrix *B);
matrix *matrix_or(matrix *A, matrix *B);
matrix *matrix_biimp(matrix *A, matrix *B);

#endif