"""
CommandLine:
    rm -rf /media/raid/work/PZ_MTEST/_ibsdb/_ibeis_cache/match_thumbs/
    python -m ibeis.gui.inspect_gui --test-test_review_widget --show --verbose-thumb
"""
from __future__ import absolute_import, division, print_function
from guitool_ibeis.__PYQT__ import QtGui, QtCore
from guitool_ibeis.__PYQT__ import QtWidgets  # NOQA
import six
from os.path import exists
import utool as ut
ut.noinject(__name__, '[APIThumbDelegate]')


VERBOSE_QT = ut.get_argflag(('--verbose-qt', '--verbqt'))
VERBOSE_THUMB = ut.VERBOSE or ut.get_argflag(('--verbose-thumb', '--verbthumb')) or VERBOSE_QT


MAX_NUM_THUMB_THREADS = 1


def read_thumb_size(thumb_path):
    import vtool_ibeis as vt
    if VERBOSE_THUMB:
        print('[ThumbDelegate] Reading thumb size')
    # npimg = vt.imread(thumb_path, delete_if_corrupted=True)
    # (height, width) = npimg.shape[0:2]
    # del npimg
    try:
        width, height = vt.open_image_size(thumb_path)
    except IOError as ex:
        if ut.checkpath(thumb_path, verbose=True):
            ut.printex(ex, 'image=%r seems corrupted. Needs deletion' %
                       (thumb_path,), iswarning=True)
            ut.delete(thumb_path)
        else:
            ut.printex(ex, 'image=%r does not exist', (thumb_path,),
                       iswarning=True)
        raise
    return width, height


def test_show_qimg(qimg):
    qpixmap = QtGui.QPixmap(qimg)
    lbl = QtWidgets.QLabel()
    lbl.setPixmap(qpixmap)
    lbl.show()   # show label with qim image
    return lbl


#@ut.memprof
def read_thumb_as_qimg(thumb_path):
    r"""
    Args:
        thumb_path (?):

    Returns:
        tuple: (qimg, width, height)

    CommandLine:
        python -m guitool_ibeis.api_thumb_delegate --test-read_thumb_as_qimg --show

    Example:
        >>> # ENABLE_DOCTEST
        >>> # xdoctest: +REQUIRES(env:DISPLAY)
        >>> from guitool_ibeis.api_thumb_delegate import *  # NOQA
        >>> import guitool_ibeis
        >>> # build test data
        >>> thumb_path = ut.grab_test_imgpath('carl.jpg')
        >>> # execute function
        >>> guitool_ibeis.ensure_qtapp()
        >>> qimg = read_thumb_as_qimg(thumb_path)
        >>> print(qimg)
        >>> # xdoctest: +REQUIRES(--show)
        >>> lbl = test_show_qimg(qimg)
        >>> #guitool_ibeis.qtapp_loop()
        >>> # verify results

    Timeit::
        %timeit np.dstack((npimg, np.full(npimg.shape[0:2], 255, dtype=np.uint8)))
        %timeit cv2.cvtColor(npimg, cv2.COLOR_BGR2BGRA)
        npimg1 = np.dstack((npimg, np.full(npimg.shape[0:2], 255, dtype=np.uint8)))
        # seems to be memory leak in cvtColor?
        npimg2 = cv2.cvtColor(npimg, cv2.COLOR_BGR2BGRA)

    """
    if VERBOSE_THUMB:
        print('[ThumbDelegate] Reading thumb as qimg. thumb_path=%r' % (thumb_path,))
    # Read thumbnail image and convert to 32bit aligned for Qt
    #if False:
    #    data  = np.dstack((npimg, np.full(npimg.shape[0:2], 255, dtype=np.uint8)))
    #if False:
    #    # Reading the npimage and then handing it off to Qt causes a memory
    #    # leak. The numpy array probably is never unallocated because qt doesn't
    #    # own it and it never loses its reference count
    #    #npimg = vt.imread(thumb_path, delete_if_corrupted=True)
    #    #print('npimg.dtype = %r, %r' % (npimg.shape, npimg.dtype))
    #    #npimg   = cv2.cvtColor(npimg, cv2.COLOR_BGR2BGRA)
    #    #format_ = QtGui.QImage.Format_ARGB32
    #    ##    #data    = npimg.astype(np.uint8)
    #    ##    #npimg   = np.dstack((npimg[:, :, 3], npimg[:, :, 0:2]))
    #    ##    #data    = npimg.astype(np.uint8)
    #    ##else:
    #    ## Memory seems to be no freed by the QImage?
    #    ##data = np.ascontiguousarray(npimg[:, :, ::-1].astype(np.uint8), dtype=np.uint8)
    #    ##data = np.ascontiguousarray(npimg[:, :, :].astype(np.uint8), dtype=np.uint8)
    #    #data = npimg
    #    ##format_ = QtGui.QImage.Format_RGB888
    #    #(height, width) = data.shape[0:2]
    #    #qimg    = QtGui.QImage(data, width, height, format_)
    #    #del npimg
    #    #del data
    #else:
    #format_ = QtGui.QImage.Format_ARGB32
    #qimg    = QtGui.QImage(thumb_path, format_)
    qimg    = QtGui.QImage(thumb_path)
    return qimg


RUNNING_CREATION_THREADS = {}


def register_thread(key, val):
    global RUNNING_CREATION_THREADS
    RUNNING_CREATION_THREADS[key] = val


def unregister_thread(key):
    global RUNNING_CREATION_THREADS
    del RUNNING_CREATION_THREADS[key]


DELEGATE_BASE = QtWidgets.QItemDelegate


class APIThumbDelegate(DELEGATE_BASE):
    """
    There is one Thumb Delegate per column. Keep that in mind when writing for
    this class.

    TODO: The delegate can have a reference to the view, and it is allowed
    to resize the rows to fit the images.  It probably should not resize columns
    but it can get the column width and resize the image to that size.

    get_thumb_size is a callback function which should return whatever the
    requested thumbnail size is

    SeeAlso:
         api_item_view.infer_delegates
    """
    def __init__(dgt, parent=None, get_thumb_size=None):
        if VERBOSE_THUMB:
            print('[ThumbDelegate] __init__ parent=%r, get_thumb_size=%r' %
                    (parent, get_thumb_size))
        DELEGATE_BASE.__init__(dgt, parent)
        dgt.pool = None
        # TODO: get from the view
        if get_thumb_size is None:
            dgt.get_thumb_size = lambda: 128  # 256
        else:
            dgt.get_thumb_size = get_thumb_size  # 256
        dgt.last_thumbsize = None
        dgt.row_rezised_flags = {}  # SUPER HACK FOR RESIZE SHRINK
        try:
            import cachetools
            dgt.thumb_cache = cachetools.TTLCache(256, ttl=2)
        except ImportError:
            dgt.thumb_cache = ut.LRUDict(256)
        #import utool
        #utool.embed()

    def paint(dgt, painter, option, qtindex):
        """
        TODO: prevent recursive paint
        """
        view = dgt.parent()
        offset = view.verticalOffset() + option.rect.y()
        # Check if still in viewport
        if view_would_not_be_visible(view, offset):
            return None
        try:
            thumb_path = dgt.get_thumb_path_if_exists(view, offset, qtindex)
            if thumb_path is not None:
                # Check if still in viewport
                if view_would_not_be_visible(view, offset):
                    return None
                # Read the precomputed thumbnail
                if thumb_path in dgt.thumb_cache:
                    qimg = dgt.thumb_cache[thumb_path]
                else:
                    qimg = read_thumb_as_qimg(thumb_path)
                    dgt.thumb_cache[thumb_path] = qimg
                width, height = qimg.width(), qimg.height()
                # Adjust the cell size to fit the image
                dgt.adjust_thumb_cell_size(qtindex, width, height)
                # Check if still in viewport
                if view_would_not_be_visible(view, offset):
                    return None
                # Paint image on an item in some view
                painter.save()
                painter.setClipRect(option.rect)
                painter.translate(option.rect.x(), option.rect.y())
                painter.drawImage(QtCore.QRectF(0, 0, width, height), qimg)
                painter.restore()
        except Exception as ex:
            print('Error in APIThumbDelegate')
            ut.printex(ex, 'Error in APIThumbDelegate', tb=True)
            painter.save()
            painter.restore()

    def sizeHint(dgt, option, qtindex):
        view = dgt.parent()
        offset = view.verticalOffset() + option.rect.y()
        try:
            thumb_path = dgt.get_thumb_path_if_exists(view, offset, qtindex)
            if thumb_path is not None:
                # Read the precomputed thumbnail
                width, height = read_thumb_size(thumb_path)
                return QtCore.QSize(width, height)
            else:
                #print("[APIThumbDelegate] Name not found")
                return QtCore.QSize()
        except Exception as ex:
            print('Error in APIThumbDelegate')
            ut.printex(ex, 'Error in APIThumbDelegate', tb=True,
                       iswarning=True)
            return QtCore.QSize()

    def get_model_data(dgt, qtindex):
        """
        The model data for a thumb should be a tuple:
        (thumb_path, img_path, imgsize, bboxes, thetas)
        """
        model = qtindex.model()
        datakw = dict(thumbsize=dgt.get_thumb_size())
        data = model.data(qtindex, QtCore.Qt.DisplayRole, **datakw)
        if data is None:
            return None
        # The data should be specified as a thumbtup
        #if isinstance(data, QtCore.QVariant):
        if hasattr(data, 'toPyObject'):
            data = data.toPyObject()
        if data is None:
            return None
        if isinstance(data, six.string_types):
            # data = (data, None, None, None, None)
            return data
        if isinstance(data, dict):
            # HACK FOR DIFFERENT TYPE OF THUMB DATA
            return data
        assert isinstance(data, tuple), (
            'data=%r is %r. should be a thumbtup' % (data, type(data)))
        thumbtup = data
        #(thumb_path, img_path, bbox_list) = thumbtup
        return thumbtup

    def spawn_thumb_creation_thread(dgt, thumb_path, img_path, img_size,
                                    qtindex, view, offset, bbox_list,
                                    theta_list, interest_list):
        if VERBOSE_THUMB:
            print('[ThumbDelegate] Spawning thumbnail creation thread')
        thumbsize = dgt.get_thumb_size()
        thumb_creation_thread = ThumbnailCreationThread(
            thumb_path, img_path, img_size, thumbsize,
            qtindex, view, offset, bbox_list, theta_list,
            interest_list
        )
        #register_thread(thumb_path, thumb_creation_thread)
        # Initialize threadcount
        if dgt.pool is None:
            #dgt.pool = QtCore.QThreadPool()
            #dgt.pool.setMaxThreadCount(MAX_NUM_THUMB_THREADS)
            dgt.pool = QtCore.QThreadPool.globalInstance()
        dgt.pool.start(thumb_creation_thread)
        # print('[ThumbDelegate] Waiting to compute')

    def get_thumb_path_if_exists(dgt, view, offset, qtindex):
        """
        Checks if the thumbnail is ready to paint

        Returns:
            thumb_path if computed otherwise returns None
        """

        # Check if still in viewport
        if view_would_not_be_visible(view, offset):
            return None

        # Get data from the models display role
        try:
            data = dgt.get_model_data(qtindex)
            if data is None:
                if VERBOSE_THUMB:
                    print('[thumb_delegate] no data')
                return
            thumbtup_mode = isinstance(data, tuple)
            thumbdat_mode = isinstance(data, dict)
            if isinstance(data, six.string_types):
                thumb_path = data
                assert exists(thumb_path), 'must exist'
                return thumb_path
            if thumbtup_mode:
                if len(data) == 5:
                    (thumb_path, img_path, img_size, bbox_list, theta_list) = data
                    interest_list = []
                else:
                    (thumb_path, img_path, img_size, bbox_list, theta_list,
                     interest_list) = data
                invalid = (thumb_path is None or img_path is None or bbox_list is
                           None or img_size is None)
                if invalid:
                    print('[thumb_delegate] something is wrong')
                    return
            elif thumbdat_mode:
                thumb_path = data['fpath']
            else:
                print('[thumb_delegate] something is wrong')
                return
        except AssertionError as ex:
            ut.printex(ex, 'error getting thumbnail data')
            return

        # Check if still in viewport
        if view_would_not_be_visible(view, offset):
            return None

        if not exists(thumb_path):
            if thumbtup_mode:
                if not exists(img_path):
                    if VERBOSE_THUMB:
                        print('[ThumbDelegate] SOURCE IMAGE NOT COMPUTED: %r' %
                              (img_path,))
                    return None
                dgt.spawn_thumb_creation_thread(
                    thumb_path, img_path, img_size, qtindex, view, offset,
                    bbox_list, theta_list, interest_list)
                return None
            elif thumbdat_mode:
                thumbdat = data
                thread_func = thumbdat['thread_func']
                main_func = thumbdat['main_func']
                #kwargs = data['kwargs']
                #func(*args, **kwargs)
                #print('data = %r' % (data,))
                #print('newdata not computed')
                # SPAWN
                if VERBOSE_THUMB:
                    print('[ThumbDelegate] Spawning thumbnail creation thread')
                args = main_func()
                thumb_creation_thread = ThumbnailCreationThread2(
                    thread_func, args, qtindex, view, offset
                )
                #register_thread(thumb_path, thumb_creation_thread)
                # Initialize threadcount
                if dgt.pool is None:
                    #dgt.pool = QtCore.QThreadPool()
                    #dgt.pool.setMaxThreadCount(MAX_NUM_THUMB_THREADS)
                    dgt.pool = QtCore.QThreadPool.globalInstance()
                dgt.pool.start(thumb_creation_thread)
                # print('[ThumbDelegate] Waiting to compute')
                return None
        else:
            # thumb is computed return the path
            return thumb_path

    def adjust_thumb_cell_size(dgt, qtindex, width, height):
        """
        called during paint to ensure that the cell is large enough for the
        image.
        """
        view = dgt.parent()
        if isinstance(view, QtWidgets.QTableView):
            # dimensions of the table cells
            row = qtindex.row()
            col_width = view.columnWidth(qtindex.column())
            col_height = view.rowHeight(row)
            thumbsize = dgt.get_thumb_size()
            if thumbsize != dgt.last_thumbsize:
                # has thumbsize changed?
                if thumbsize != col_width:
                    view.setColumnWidth(qtindex.column(), thumbsize)
                if height != col_height:
                    view.setRowHeight(qtindex.row(), height)
                dgt.last_thumbsize = thumbsize
            # Let columns shrink
            if thumbsize != col_width:
                view.setColumnWidth(qtindex.column(), thumbsize)
            # Let rows grow
            if height > col_height:
                view.setRowHeight(qtindex.row(), height)
            if dgt.row_rezised_flags.get(row):
                # HACK TO ONLY SHRINK ONCE WONT WORK WITH RESORT
                return
            else:
                dgt.row_rezised_flags[row] = True
                # Let rows shrink
                # IF THERE IS MORE THAN ONE COLUMN WITH THUMBS THEN THIS WILL CAUSE
                # COLS TO BE RESIZED MANY TIMES UNDER THE HOOD. THAT CAUSES
                # MULTIPLE READS OF THE THUMBS WHICH CAUSES MAJOR SLOWDOWNS.
                if height < col_height:
                    view.setRowHeight(qtindex.row(), height)
        elif isinstance(view, QtWidgets.QTreeView):
            col_width = view.columnWidth(qtindex.column())
            col_height = view.rowHeight(qtindex)
            # TODO: finishme


def view_would_not_be_visible(view, offset):
    """
    Check if the current scroll position is far beyond the
    scroll position when this was initially requested.
    """
    viewport = view.viewport()
    height = viewport.size().height()
    height_offset = view.verticalOffset()
    current_offset = height_offset + height // 2
    return abs(current_offset - offset) >= height


def get_thread_thumb_info(bbox_list, theta_list, thumbsize, img_size):
    r"""
    CommandLine:
        python -m guitool_ibeis.api_thumb_delegate --test-get_thread_thumb_info

    Example:
        >>> # ENABLE_DOCTEST
        >>> from guitool_ibeis.api_thumb_delegate import *  # NOQA
        >>> # build test data
        >>> bbox_list = [(100, 50, 400, 200)]
        >>> theta_list = [0]
        >>> thumbsize = 128
        >>> img_size = 600, 300
        >>> # execute function
        >>> result = get_thread_thumb_info(bbox_list, theta_list, thumbsize, img_size)
        >>> # verify results
        >>> print(result)
        ((128, 64), [[[21, 11], [107, 11], [107, 53], [21, 53], [21, 11]]])

    """
    import vtool_ibeis as vt
    theta_list = [theta_list] if not ut.is_listlike(theta_list) else theta_list
    max_dsize = (thumbsize, thumbsize)
    dsize, sx, sy = vt.resized_clamped_thumb_dims(img_size, max_dsize)
    # Compute new verts list
    new_verts_list = list(vt.scaled_verts_from_bbox_gen(bbox_list, theta_list, sx, sy))
    return dsize, new_verts_list


def make_thread_thumb(img_path, dsize, new_verts_list, interest_list):
    r"""
    Makes thumbnail with overlay. Called in thead

    CommandLine:
        python -m guitool_ibeis.api_thumb_delegate --test-make_thread_thumb --show

    Example:
        >>> # DISABLE_DOCTEST
        >>> from guitool_ibeis.api_thumb_delegate import *  # NOQA
        >>> import plottool_ibeis as pt
        >>> # build test data
        >>> img_path = ut.grab_test_imgpath('carl.jpg')
        >>> dsize = (32, 32)
        >>> new_verts_list = []
        >>> # execute function
        >>> thumb = make_thread_thumb(img_path, dsize, new_verts_list)
        >>> ut.quit_if_noshow()
        >>> pt.imshow(thumb)
        >>> pt.show_if_requested()
    """
    import vtool_ibeis as vt
    from vtool_ibeis import geometry
    orange_bgr = (0, 128, 255)
    blue_bgr = (255, 128, 0)
    # imread causes a MEMORY LEAK most likely!
    img = vt.imread(img_path)  # Read Image (.0424s) <- Takes most time!
    #if False:
    #    #http://stackoverflow.com/questions/9794019/convert-numpy-array-to-pyside-qpixmap
    #    # http://kogs-www.informatik.uni-hamburg.de/~meine/software/vigraqt/qimage2ndarray.py
    #    #import numpy as np
    #    #qimg = QtGui.QImage(img_path, str(QtGui.QImage.Format_RGB32))
    #    #temp_shape = (qimg.height(), qimg.bytesPerLine() * 8 // qimg.depth(), 4)
    #    #result_shape = (qimg.height(), qimg.width())
    #    #buf = qimg.bits().asstring(qimg.numBytes())
    #    #result  = np.frombuffer(buf, np.uint8).reshape(temp_shape)
    #    #result = result[:, :result_shape[1]]
    #    #result = result[..., :3]
    #    #img = result
    thumb = vt.image.resize(img, dsize)  # Resize to thumb dims (.0015s)
    del img
    # Draw bboxes on thumb (not image)
    color_bgr_list = [blue_bgr if interest else orange_bgr for interest in interest_list]
    for new_verts, color_bgr in zip(new_verts_list, color_bgr_list):
        if new_verts is not None:
            geometry.draw_verts(thumb, new_verts, color=color_bgr, thickness=2, out=thumb)
        #thumb = geometry.draw_verts(thumb, new_verts, color=orange_bgr, thickness=2)
    return thumb


RUNNABLE_BASE = QtCore.QRunnable


class ThumbnailCreationThread2(RUNNABLE_BASE):
    """
    HACK
    TODO: http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt
    """

    def __init__(thread, thread_func, args, qtindex, view, offset):
        RUNNABLE_BASE.__init__(thread)
        thread.thread_func = thread_func
        thread.args = args
        thread.qtindex = qtindex
        thread.offset = offset
        thread.view = view

    def thumb_would_not_be_visible(thread):
        return view_would_not_be_visible(thread.view, thread.offset)

    def _run(thread):
        """ Compute thumbnail in a different thread """
        if thread.thumb_would_not_be_visible():
            return
        #func = thread.thumbdat['func']
        thread.thread_func(thread.thumb_would_not_be_visible, *thread.args)
        #func(check_func=thread.thumb_would_not_be_visible)
        thread.qtindex.model().dataChanged.emit(thread.qtindex, thread.qtindex)

    def run(thread):
        try:
            thread._run()
        except Exception as ex:
            ut.printex(ex, 'thread failed', tb=True)
            #raise


class ThumbnailCreationThread(RUNNABLE_BASE):
    """
    Helper to compute thumbnails concurrently

    References:
        TODO:
        http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt
    """

    def __init__(thread, thumb_path, img_path, img_size, thumbsize, qtindex,
                 view, offset, bbox_list, theta_list, interest_list):
        RUNNABLE_BASE.__init__(thread)
        thread.thumb_path = thumb_path
        thread.img_path = img_path
        thread.img_size = img_size
        thread.qtindex = qtindex
        thread.offset = offset
        thread.thumbsize = thumbsize
        thread.view = view
        thread.bbox_list = bbox_list
        thread.theta_list = theta_list
        thread.interest_list = interest_list

    def thumb_would_not_be_visible(thread):
        return view_would_not_be_visible(thread.view, thread.offset)

    def _run(thread):
        """ Compute thumbnail in a different thread """
        import vtool_ibeis as vt
        #time.sleep(.005)  # Wait a in case the user is just scrolling
        if thread.thumb_would_not_be_visible():
            return
        # Precompute info BEFORE reading the image (.0002s)
        dsize, new_verts_list = get_thread_thumb_info(
            thread.bbox_list, thread.theta_list, thread.thumbsize, thread.img_size)
        #time.sleep(.005)  # Wait a in case the user is just scrolling
        if thread.thumb_would_not_be_visible():
            return
        # -----------------
        # This part takes time, hopefully the user actually wants to see this
        # thumbnail.
        thumb = make_thread_thumb(thread.img_path, dsize, new_verts_list, thread.interest_list)
        if thread.thumb_would_not_be_visible():
            return
        vt.image.imwrite(thread.thumb_path, thumb)
        del thumb
        if thread.thumb_would_not_be_visible():
            return
        #print('[ThumbCreationThread] Thumb Written: %s' % thread.thumb_path)
        thread.qtindex.model().dataChanged.emit(thread.qtindex, thread.qtindex)
        #unregister_thread(thread.thumb_path)

    def run(thread):
        try:
            thread._run()
        except Exception as ex:
            ut.printex(ex, 'thread failed', tb=True)
            #raise

    #def __del__(self):
    #    print('About to delete creation thread')


# GRAVE:
#print('[APIItemDelegate] Request Thumb: rc=(%d, %d), nBboxes=%r' %
#      (qtindex.row(), qtindex.column(), len(bbox_list)))
#print('[APIItemDelegate] bbox_list = %r' % (bbox_list,))

def simple_thumbnail_widget():
    r"""
    Very simple example to test thumbnails

    CommandLine:
        python -m guitool_ibeis.api_thumb_delegate --test-simple_thumbnail_widget  --show --verbthumb
        python -m guitool_ibeis.api_thumb_delegate --test-simple_thumbnail_widget  --show --tb

    Example:
        >>> # GUI_DOCTEST
        >>> # xdoctest: +REQUIRES(--gui)
        >>> from guitool_ibeis.api_thumb_delegate import *  # NOQA
        >>> import guitool_ibeis
        >>> guitool_ibeis.ensure_qapp()  # must be ensured before any embeding
        >>> wgt = simple_thumbnail_widget()
        >>> ut.quit_if_noshow()
        >>> wgt.show()
        >>> guitool_ibeis.qtapp_loop(wgt, frequency=100)
    """
    import guitool_ibeis
    guitool_ibeis.ensure_qapp()
    col_name_list = ['rowid', 'image_name', 'thumb']
    col_types_dict = {
        'thumb': 'PIXMAP',
    }

    guitool_test_thumbdir = ut.ensure_app_resource_dir('guitool_ibeis', 'thumbs')
    ut.delete(guitool_test_thumbdir)
    ut.ensuredir(guitool_test_thumbdir)
    import vtool_ibeis as vt
    from os.path import join

    #imgname_list = sorted(ut.TESTIMG_URL_DICT.keys())
    imgname_list = ['carl.jpg', 'astro.png', 'patsy.jpg']
    imgname_list += ['doesnotexist.jpg']

    num_imgs = list(range(len(imgname_list)))
    # num_imgs = list(range(500))

    def thread_func(would_be, id_):
        from vtool_ibeis.fontdemo import get_text_test_img
        get_text_test_img(id_)

    def thumb_getter(id_, thumbsize=128):
        """ Thumb getters must conform to thumbtup structure """

        if id_ not in imgname_list:
            return {
                'fpath': id_ + '.jpg',
                'thread_func': thread_func,
                'main_func': lambda : (id_,),
            }
        #print(id_)
        if id_ == 'doesnotexist.jpg':
            return None
            img_path = None
            img_size = (100, 100)
        else:
            img_path = ut.grab_test_imgpath(id_, verbose=False)
            img_size = vt.open_image_size(img_path)
        thumb_path = join(guitool_test_thumbdir, ut.hashstr(str(img_path)) + '.jpg')
        if id_ == 'carl.jpg':
            bbox_list = [(10, 10, 200, 200)]
            theta_list = [0]
        elif id_ == 'astro.png':
            #bbox_list = [(10, 10, 200, 200)]
            bbox_list = [None]
            theta_list = [None]
        else:
            bbox_list = []
            theta_list = []
        interest_list = [False]
        thumbtup = (thumb_path, img_path, img_size, bbox_list, theta_list, interest_list)
        #print('thumbtup = %r' % (thumbtup,))
        return thumbtup
        #return None

    def imgname_getter(rowid):
        if rowid < len(imgname_list):
            return imgname_list[rowid]
        else:
            return str(rowid)

    col_getter_dict = {
        'rowid': num_imgs,
        'image_name': imgname_getter,
        'thumb': thumb_getter
    }
    col_ider_dict = {
        'thumb': 'image_name',
    }
    col_setter_dict = {}
    editable_colnames = []
    sortby = 'rowid'
    def get_thumb_size():
        return 128
    #get_thumb_size = lambda: 128  # NOQA
    col_width_dict = {}
    col_bgrole_dict = {}

    api = guitool_ibeis.CustomAPI(
        col_name_list, col_types_dict, col_getter_dict,
        col_bgrole_dict, col_ider_dict, col_setter_dict,
        editable_colnames, sortby, get_thumb_size, True, col_width_dict)
    headers = api.make_headers(tblnice='Utool Test Images')

    wgt = guitool_ibeis.APIItemWidget()
    wgt.change_headers(headers)
    wgt.resize(600, 400)
    #guitool_ibeis.qtapp_loop(qwin=wgt, ipy=ipy, frequency=loop_freq)
    return wgt


if __name__ == '__main__':
    """
    CommandLine:
        python -m guitool_ibeis.api_thumb_delegate
        python -m guitool_ibeis.api_thumb_delegate --allexamples
        python -m guitool_ibeis.api_thumb_delegate --allexamples --noface --nosrc
    """
    import multiprocessing
    multiprocessing.freeze_support()  # for win32
    import utool as ut  # NOQA
    ut.doctest_funcs()
