#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Thinning algorithms
"""
import numpy as np
from ._ffi import *

__all__ = ["guo_hall", "zhang_suen"]

def __check_image_grayscale_2d(img):
    """Raise if the image  is not a 2D image"""
    nd = len(img.shape)
    if nd == 3:
        raise ValueError("Can only use binary (i.e. grayscale) images")
    if nd != 2:
        raise ValueError("Image has wrong number of dimensions ({0} instead of 2)".format(nd))  

def __check_image_fortran_order(img):
    """Raise if the image is not in FORTRAN memory order"""
    # Check array memory order
    if np.isfortran(img): # i.e. not C-ordered
        raise ValueError("cv_algorithms thinning implementation works only on C-ordered arrays")

def __check_image_min_wh(img, min_width, min_height):
    """Raise if the image does not have a given minimum width and height"""
    height, width = img.shape
    if height < min_height or width < min_width:
        raise ValueError("Thinning algorithm needs an image at least 3px wide and 3px high but size is {}".format(img.shape))

_ffi.cdef('''
int guo_hall_thinning(uint8_t* binary_image, size_t width, size_t height);
int zhang_suen_thinning(uint8_t* binary_image, size_t width, size_t height);
''')


def guo_hall(img, inplace=False):
    """
    Perform in-place optimized Guo-Hall thinning.
    Returns img.

    Requires a binary grayscale numpy array as input.

    This calls the optimized C backend from cv_algorithms.
    """
    # Copy image (it'll be changed by the C code) if not allowed to modify
    if not inplace:
        img = img.copy()
    # Check if image seems correct
    __check_image_grayscale_2d(img)
    __check_image_fortran_order(img)
    __check_image_min_wh(img, 3, 3)

    # Extract pointer to binary data
    dptr = _ffi.cast("uint8_t*", img.ctypes.data)

    rc = _libcv_algorithms.guo_hall_thinning(dptr, width, height)
    if rc != 0:
        raise ValueError("Internal error (return code {0}) in algorithm C code".format(rc))
    return img


def zhang_suen(img, inplace=False):
    """
    Perform in-place optimized Zhang-Suen thinning.
    Returns img.

    Requires a binary grayscale numpy array as input.

    This calls the optimized C backend from cv_algorithms.
    """
    # Copy image (it'll be changed by the C code) if not allowed to modify
    if not inplace:
        img = img.copy()
    # Check if image seems correct
    __check_image_grayscale_2d(img)
    __check_image_fortran_order(img)
    __check_image_min_wh(img, 3, 3)

    # Extract pointer to binary data
    dptr = _ffi.cast("uint8_t*" , img.ctypes.data)

    rc = _libcv_algorithms.zhang_suen_thinning(dptr, width, height)
    if rc != 0:
        raise ValueError("Internal error (return code {0}) in algorithm C code".format(rc))
    return img

@@ -1244,24 +1244,30 @@
 )%0A%0A%0Adef 
-guo_hall
+__run_thinning
 (img, in
@@ -1263,38 +1263,38 @@
 ing(img, inplace
-=False
+, cfun
 ):%0A    %22%22%22%0A    P
@@ -1291,195 +1291,41 @@
  %22%22%22
-%0A    Perform in-place optimized Guo-Hall thinning.%0A    Returns img.%0A%0A    Requires a binary grayscale numpy array as input.%0A%0A    This calls the optimized C backend from cv_algorithms.%0A    
+Internal common thinning function
 %22%22%22%0A
@@ -1690,43 +1690,12 @@
 c = 
-_libcv_algorithms.guo_hall_thinning
+cfun
 (dpt
@@ -1841,26 +1841,24 @@
 g%0A%0A%0Adef 
-zhang_suen
+guo_hall
 (img, in
@@ -1914,18 +1914,16 @@
 zed 
-Zhang-Suen
+Guo-Hall
  thi
@@ -2077,545 +2077,404 @@
     
-# Copy image (it'll be changed by the C code) if not allowed to modify%0A    if not inplace:%0A        img = img.copy()%0A    # Check if image seems correct%0A    __check_image_grayscale_2d(img)%0A    __check_image_fortran_order(img)%0A    __check_image_min_wh(img, 3, 3)%0A%0A    # Extract pointer to binary data%0A    dptr = _ffi.cast(%22uint8_t*%22 , img.ctypes.data)%0A%0A    rc = _libcv_algorithms.zhang_suen_thinning(dptr, width, height)%0A    if rc != 0:
+return __run_thinning(img, inplace, _libcv_algorithms.guo_hall_thinning)%0A    %0A%0A%0Adef zhang_suen(img, inplace=False):%0A    %22%22%22%0A    Perform in-place optimized Zhang-Suen thinning.%0A    Returns img.%0A%0A    Requires a binary grayscale numpy array as input.%0A%0A    This calls the optimized C backend from cv_algorithms.%0A    %22%22%22
 %0A    
+%0A
     r
-aise ValueError(%22Internal error (return code %7B0%7D) in algorithm C code%22.format(rc))%0A    return img
+eturn __run_thinning(img, inplace, _libcv_algorithms.zhang_suen_thinning)
 %0A

Move thinning execution to common function