public class DeterminantFinder
{
    private static boolean atLeastOneByOne(int[][] matrix)
    {
        return matrix != null && matrix.length > 0 && matrix[0].length > 0;
    }
    
    /**
     * Determines if the determinant is defined for matrix.
     * @return true if the determinant is defined, false otherwise
     */
    public static boolean determinantDefined(int[][] matrix)
    {
        if ( ! atLeastOneByOne(matrix) )
            return false;

        return matrix.length >= 2 && matrix.length == matrix[0].length;
    }

    /**
     * Calculates the determinant of matrix, which must be a 2x2 matrix.
     * Precondition: matrix.length == 2 && matrix[0].length == 2 
     * @return the determinant
     */
    public static int findTwoByTwoDeterminant(int[][] matrix)
    {
        if ( ! determinantDefined(matrix) )
            throw new IllegalArgumentException();
        
        if( matrix.length != 2 || matrix[0].length != 2)
            throw new IllegalArgumentException();

        return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
    }

    /**
     * Calculates a matrix identical to matrix with the specific row and column removed.
     * Precondition: rowToRemove >= 0 && colToRemove >= 0 &&
     *      matrix.length > rowToRemove && matrix[0].length > colToRemove
     * @return matrix identical to matrix without the specified row and column.
     */
    public static int[][] withoutRowAndColumn(int[][] matrix, int rowToRemove, int colToRemove)
    {
        if(rowToRemove < 0 || rowToRemove >= matrix.length)
            throw new IllegalArgumentException();
        
        if(colToRemove < 0 || colToRemove >= matrix[0].length)
            throw new IllegalArgumentException();
        
        int[][] newMatrix = new int[matrix.length - 1][matrix[0].length - 1];
        int newRow = 0;

        for (int row = 0; row < matrix.length; row++)
        {
            if (row != rowToRemove)
            {
                for(int col = 0; col < colToRemove; col++)
                    newMatrix[newRow][col] = matrix[row][col];
                
                for(int col = colToRemove + 1; col < matrix[0].length; col++)
                    newMatrix[newRow][col - 1] = matrix[row][col];
                
                newRow++;
            }
        }

        return newMatrix;
    }

    /**
     * Calculates the determinant of matrix.
     * Precondition: determinantDefined(matrix)
     * @return the determinant.
     */
    public static int findDeterminant(int[][] matrix)
    {
        if ( ! determinantDefined(matrix) )
            throw new IllegalArgumentException();

        if (matrix.length == 2)
            return findTwoByTwoDeterminant(matrix);

        final int ROW = 0;
        
        int determinant = 0;

        for (int col = 0; col < matrix[0].length; col++)
        {
            int[][] smallerMatrix = withoutRowAndColumn(matrix, ROW, col);
            
            int part = findDeterminant(smallerMatrix);
            part *= matrix[ROW][col];
            
            if(col % 2 == 0)
                determinant += part;
            else
                determinant -= part;
        }

        return determinant;
    }
}
