#include "../pnheaders/general.h"
#include "../pnheaders/matrix.h"

static int gcd(int a, int b);

int gcdv(matrix* m, int row, int col)
{
	/*If the matrix pointer is present, get the limits on where we should be'
	processing.*/
	if (m)
	{
		/*Check to make sure the row/column numbers are in range.*/
		if (row >= NumberOfRows(*m) || col >= NumberOfColumns(*m))
		{
			merror(0, "GCDV: The row or column number is out of range");
			return 0;
		}
		int i, j, i0, j0, i1, j1, x;
		/*Check to make sure we aren't being asked to find the gcd of a single
		element.*/
		if (row >= 0 && col >= 0)
		{			
			merror(0, "GCDV: The row and column numbers request the GCD of a single scalar element");
			return 1;
		}
		/*Get the limits over which we will be iterating (row and column)*/
		if (row >= 0)
		{
			i0 = row;
			i1 = row + 1;
		}
		else
		{
			i0 = 0;
			i1 = NumberOfRows(*m);			
		}
		if (col >= 0)
		{
			j0 = col;
			j1 = col + 1;
		}
		else
		{
			j0 = 0;
			j1 = NumberOfColumns(*m);
		}
		/*Do the actual iteration.*/
		for (i = i0; i < i1; i++)
		{
			for (j = j0; j < j1; j++)
			{
				if (i == i0 && j == j0)
				{
					if ((x = GetMatrixEl(m, i, j)) == 1) break;					
				}
				else
				{
					if ((x = gcd(GetMatrixEl(m, i, j), x)) == 1) break;
				}
			}
		}
		return x;
	}
	/*If m was not provided, find the gcd of the row and column numbers.*/
	else
	{
		return gcd(row, col);
	}
}

/*******************************************************************************
Find the greatest common divisor of a pair of integers via the Euclidian
algorithm.*/
int gcd(int a, int b)
{
	int c;
	/*Make sure both are positive.*/
	if (a < 0) a = -a;
	if (b < 0) b = -b;
	/*Make sure a is greater than b by swapping if necessary.*/
	if (a < b)
	{
		c = a;
		a = b;
		b = c;
	}
	/*Division-based Euclidian gcd algorithm.*/
	while (b)
	{
		c = b;
		b = a % b;
		a = c;
	}
	return a;
}
