/*mult_2_matrix.c: Programa al que le entramos 2 matrices por teclado y
				   nos devuelve la multiplicación de estas.*/
/*Programado por PAMTUMACA STUDIOS
	Miembros:
		Pau Bitlloch Puigvert
		Xavier Lligadas Rodríguez
	contacto:
		newthalion@hotmail.com     */

#include <stdio.h>
#include <stdlib.h>

/*definimos el máximo número posible de columnas y filas que 
  podran tener nuestras matrices.*/
#define MAX_NUM_COL 9
#define MAX_NUM_FIL 9

/*definimos un nuevo dato que contendrá nuestras matrices*/
typedef struct{
	float *dataPtr;
	int num_col, num_fil;
} MATRIX, *MATRIXPTR;	

/*declaración de funciones*/

void studios_info(void);
int obtener_matrices_mult(MATRIXPTR, MATRIXPTR);
int entrar_matriz(MATRIXPTR, int, int);
int init_matriz(MATRIXPTR, int, int);
int mult_matrices(MATRIXPTR, MATRIXPTR, MATRIXPTR);
int mostrar_resultado(MATRIXPTR);
int mostrar_matriz(MATRIXPTR);

/*definición de funciones*/

int main()
{
	MATRIX mtx1, mtx2, result_mtx;

	/*mostramos información de los creadores del programa*/
	studios_info();
	
	/*cogemos los datos de las matrices a multiplicar*/;
	if(!obtener_matrices_mult(&mtx1, &mtx2))
		return(0);  
	
	/*inicializamos la matriz que mostrara el resultado*/
	if(!init_matriz(&result_mtx, mtx1.num_fil, mtx2.num_col))
	{
		/*liberamos la memoria utilizada y salimos*/
		free(mtx1.dataPtr);
		free(mtx2.dataPtr);
		return(0);
	}

	/*multiplicamos las matrices, si no fue posible liberamos
	  la memoria usada y salimos del programa*/
	if(!mult_matrices(&mtx1, &mtx2, &result_mtx))
	{
		free(mtx1.dataPtr);
		free(mtx2.dataPtr);
		free(result_mtx.dataPtr);
		return(0);
	}

	/*mostramos el resultado y si hay error liberamos la memoria
	  utilizada*/
	if(!mostrar_resultado(&result_mtx))
	{
		free(mtx1.dataPtr);
		free(mtx2.dataPtr);
		free(result_mtx.dataPtr);
		return(0);
	}
	
	/*todo ha ido bien, liberamos toda la memoria utilizada*/
	free(mtx1.dataPtr);
	free(mtx2.dataPtr);
	free(result_mtx.dataPtr);

	/*devolvemos éxito*/
	return(1);
}

/*******************************************************
Funcion obtener_matrices: Esta funcion recibe dos punteros
	a una estructura matrix, y los llena pidiendo al usuario
	la entrada por teclado.
********************************************************/
int obtener_matrices_mult(MATRIXPTR mtx1Ptr, MATRIXPTR mtx2Ptr)
{
	int num_col1, num_filas1, num_col2, num_filas2;
	
	/*primero pedimos filas y columnas de las matrices a multiplicar
	  y si no se pudiesen multiplicar paramos la ejecucion*/
	/*pedimos el numero de filas de la primera matriz y lo guardamos*/
	printf("MATRIZ1\n\n");
	printf("Introduce el numero de filas de la primera matriz. (maximo %d): ", MAX_NUM_FIL);
	scanf("%d", &num_filas1);
	/*miramos que el numero de filas no sea excesivo*/
	if(num_filas1 > MAX_NUM_FIL || num_filas1 <= 0)
	{
		printf("error: numero de filas invalido.\n");
		return(0);
	}
	/*pedimos el número de columnas de la primera matriz y lo guadamos*/
	printf("Introduce el numero de columnas de la primera matriz. (maximo %d): ", MAX_NUM_COL);
	scanf("%d", &num_col1);
	/*miramos que el número de columnas no supere el maximo*/
	if(num_col1 > MAX_NUM_COL || num_col1 <= 0)
	{
		printf("error: numero de columnas invalido.\n");
		return(0);
	}
	/*cogemos los datos de la segunda matriz*/
	printf("\nMATRIZ2\n\n");
	/*pedimos y cogemos el numero de filas de la segunda matriz*/
	printf("Introduce el numero de filas de la segunda matriz. (maximo %d): ", MAX_NUM_FIL);
	scanf("%d", &num_filas2);
	/*comprovamos que el numero de filas no supere el maximo*/
	if(num_filas2 > MAX_NUM_FIL || num_filas2 <= 0)
	{
		printf("error: numero de filas invalido.\n");
		return(0);
	}
	/*pedimos el numero de columnas de la segunda matriz*/
	printf("Introduce el numero de columnas de la segunda matriz. (maximo %d): ", MAX_NUM_COL);
	scanf("%d", &num_col2);
	/*miramos que el numero de columnas no supere el maximo*/
	if(num_col2 > MAX_NUM_COL || num_col2 <= 0)
	{
		printf("error: numero de columnas invalido.\n");
		return(0);
	}
	/*comprovamos que se pueda realizar la multiplicacion*/
	if(num_col1 != num_filas2)
	{
		printf("error: Las matrices introducidas no se pueden multiplicar.\n");
		return(0);
	}

	/*cogemos los datos de la primera matriz si no es posible
	  devolvemos error*/
	printf("\nMATRIZ 1\n");
	if(!entrar_matriz(mtx1Ptr, num_filas1, num_col1))
		return(0);
	/*cogemos los datos de la segunda matriz si no es posible
	  devolvemos error*/
	printf("\nMATRIZ 2\n");
	if(!entrar_matriz(mtx2Ptr, num_filas2, num_col2))
	{
		/*liberamos la memoria obtenida para la primera matriz*/
		free(mtx1Ptr->dataPtr);
		return(0);
	}

	/*devolvemos exito*/
	return(1);
}
	
/************************************************
funcion entrar_matriz: Nos coge un puntero a una
	estructura matriz y el numero de filas y 
	columnas y nos toma los datos de la matriz por
	teclado.
*************************************************/

int entrar_matriz(MATRIXPTR mtxPtr,int num_filas,int num_columnas)
{
	int fila, colum;
	float aux_num;

	/*inicializamos la estructura matriz si hay espacio disponible*/
	if(!init_matriz(mtxPtr, num_filas, num_columnas))
		return(0);

	/*obtenemos los datos de la matriz*/
	for(fila=0; fila < mtxPtr->num_fil; fila++)
		for(colum=0; colum < mtxPtr->num_col; colum++)
		{
			/*sumamos 1 a fila y columna para que cuente las filas y 
			  columnas a partir del 1 y no del 0*/
			printf("Introduce el elemento (%d, %d): ", fila+1, colum+1);
			scanf("%f", &aux_num);
			*((mtxPtr->dataPtr)+fila*(mtxPtr->num_col)+colum)=aux_num;
		}

	/*devolvemos exito*/
	return(1);
}

/****************************************************
funcion init_matriz: funcion que nos inicializa los
	tres campos principales de una estructura matriz,
	el numero de columnas, el numero de filas y el 
	puntero a los datos.
****************************************************/
int init_matriz(MATRIXPTR mtxPtr, int filas, int columnas)
{
	/*inicializamos los campos*/
	mtxPtr->num_fil=filas;
	mtxPtr->num_col=columnas;
	mtxPtr->dataPtr=(float *) calloc(filas*columnas, sizeof(float));

	/*miramos si ha havido memoria suficiente*/
        if(!(mtxPtr->dataPtr))
	{
		printf("Error: memoria insuficiente.\n");
		return(0);
	}

	/*devolvemos exito*/
	return(1);
}

/***************************************************
funcion mult_matrices: funcion que toma tres punteros
	a estructura matrix, multiplica las dos primeras y
	los guarda en la tercera.
	Tambien comprueva que la multiplicacion sea realizable.
****************************************************/
int mult_matrices(MATRIXPTR mtx1Ptr, MATRIXPTR mtx2Ptr, MATRIXPTR mtx_resPtr)
{
	int fil, col, j;
	float acum=0; /*guardaremos las sumas del calculo de un elemento*/

	/*miramos que la multiplicacion se pueda realizar*/
	if(mtx1Ptr->num_col!=mtx2Ptr->num_fil)
	{
		printf("error: las matrices no se pueden multiplicar.\n");
		return(0);
	}

	/*comprovamos que en la matriz resultante se pueda poner el
	  resultado final*/
	if(mtx_resPtr->num_fil != mtx1Ptr->num_fil || 
		mtx_resPtr->num_col != mtx2Ptr->num_col)
	{
		printf("error: la matriz resultante es no apta para el resultado.\n");
		return(0);
	}
	
	/*realizamos la multiplicacion de las matrices*/
	for(fil=0; fil < mtx_resPtr->num_fil; fil++)
		/*calculamos toda una fila de la matriz resultante*/
		for(col=0; col < mtx_resPtr->num_col; col++)
		{
			/*calculamos el elemento (fil,col) de la matriz resultante*/
			for(j=0; j < mtx1Ptr->num_col; j++)
			{
				/*multiplicamos el elemento (fil,j) de la primera matriz
				  por el elemento (j, col) de la segunda matriz*/
				acum+= *((mtx1Ptr->dataPtr)+fil*(mtx1Ptr->num_col)+j) *
					   *((mtx2Ptr->dataPtr)+j*(mtx2Ptr->num_col)+col);
			}
			*((mtx_resPtr->dataPtr)+fil*mtx_resPtr->num_col+col)=acum;
			/*ponemos el acumulador a 0 para la proxima pasada*/
			acum=0;
		}

	/*devolvemos exito*/
	return(1);

}

/**********************************************
funcion mostrar_resultado: Nos muestra el resultado
	de la matriz pero nos lo acompaña con una pequeña
	frase de explicación del resultado.
***********************************************/
int mostrar_resultado(MATRIXPTR mtxPtr)
{
	/*pequeño mensaje de lo que mostramos*/
	printf("El resultado de la operacion es:\n");
	/*mostramos la matriz*/
	if(!mostrar_matriz(mtxPtr))
		return(0);
	
	/*devolvemos exito*/
	return(1);
}

/**********************************************
funcion mostrar_matriz: Recibe como argumento un
	puntero a matriz y nos muestra los datos que 
	este contiene en forma matricial.
***********************************************/
int mostrar_matriz(MATRIXPTR mtxPtr)
{
	int fil, col;

	/*comprovamos que el numero de filas y columnas sea correcto*/
	if(mtxPtr->num_col <= 0 || mtxPtr->num_fil <= 0)
	{
		printf("error: numero de elementos no valido.\n");
		return(0);
	}
	
	/*muestra la matriz*/
	for(fil=0; fil < mtxPtr->num_fil; fil++)
	{
		/*parentesis de la matriz inicial*/
		printf("|");
		/*mostramos una fila*/
		for(col=0; col < mtxPtr->num_col; col++)
			printf("%7.2f ", *((mtxPtr->dataPtr)+fil*(mtxPtr->num_col)+col));
		/*parentesis de la matriz final y nueva fila*/
		printf("|\n");
	}
	printf("\n");
	
	/*devolvemos éxito*/
	return(1);
}

/**********************************************
funcion estudios_info: Nos muestra informacion de
	los creadores del programa, OSEA!!, nosotros.xDD
***********************************************/
void studios_info(void)
{
	printf("**********************************************************\n");
	printf("* PAMTUMACASTUDIOS presenta el programa:                 *\n");
	printf("*   Mult2Matrix.                                         *\n");
	printf("* Programado por:                                        *\n");
	printf("*   Pau Bitlloch Puigvert                                *\n");
	printf("*   Xavier Lligadas Rodriguez                            *\n");
	printf("* Quejas o sugerencias:                                  *\n");
	printf("*   Newthalion@hotmail.com                               *\n");
	printf("**********************************************************\n\n\n");
}
			

	
	
