using System;
using System.Runtime.InteropServices;
using Tesseract.Interop;

namespace Tesseract
{
    
    
    
    
    
    
    
    public class PageIterator : DisposableBase
    {
        protected readonly Page page;
        protected readonly HandleRef handle;

        internal PageIterator(Page page, IntPtr handle)
        {
            this.page = page;
        	this.handle = new HandleRef(this, handle);
        }

        
        
        
        public void Begin()
        {
            VerifyNotDisposed();
            if (handle.Handle != IntPtr.Zero) {
                TessApi.Native.PageIteratorBegin(handle);
            }
        }

        
        
        
        
        
        
        
        
        public bool Next(PageIteratorLevel level)
        {
            VerifyNotDisposed();
            if (handle.Handle == IntPtr.Zero)
                return false;
            return TessApi.Native.PageIteratorNext(handle, level) != 0;
        }

        
        
        
        
        
        
        public bool Next(PageIteratorLevel level, PageIteratorLevel element)
        {
            VerifyNotDisposed();

            var isAtFinalElement = IsAtFinalOf(level, element);
            if (!isAtFinalElement) {
                return Next(element);
            }

            return false;
        }

        
        
        
        
        
        
        
        
        public bool IsAtBeginningOf(PageIteratorLevel level)
        {
            VerifyNotDisposed();

            if (handle.Handle == IntPtr.Zero)
                return false;
            return TessApi.Native.PageIteratorIsAtBeginningOf(handle, level) != 0;
        }

        
        
        
        
        
        
        public bool IsAtFinalOf(PageIteratorLevel level, PageIteratorLevel element)
        {
            VerifyNotDisposed();

            if (handle.Handle == IntPtr.Zero)
                return false;
            return TessApi.Native.PageIteratorIsAtFinalElement(handle, level, element) != 0;
        }

        public PolyBlockType BlockType
        {
            get
            {
                VerifyNotDisposed();

                if (handle.Handle == IntPtr.Zero)
                    return PolyBlockType.Unknown;
                return TessApi.Native.PageIteratorBlockType(handle);
            }
        }

        public Pix GetBinaryImage(PageIteratorLevel level)
        {
            VerifyNotDisposed();
            if (handle.Handle == IntPtr.Zero) {
                return null;
            }

            return Pix.Create(TessApi.Native.PageIteratorGetBinaryImage(handle, level));
        }

        public Pix GetImage(PageIteratorLevel level, int padding, out int x, out int y)
        {
            VerifyNotDisposed();
            if (handle.Handle == IntPtr.Zero) {
                x = 0;
                y = 0;

                return null;
            }

            return Pix.Create(TessApi.Native.PageIteratorGetImage(handle, level, padding, page.Image.Handle, out x, out y));
        }

        
        
        
        
        
        
        public bool TryGetBoundingBox(PageIteratorLevel level, out Rect bounds)
        {
            VerifyNotDisposed();
            if (handle.Handle != IntPtr.Zero && TessApi.Native.PageIteratorBoundingBox(handle, level, out var x1, out var y1, out var x2, out var y2) != 0)
            {
                bounds = Rect.FromCoords(x1, y1, x2, y2);
                return true;
            }

            bounds = Rect.Empty;
            return false;
        }

        
        
        
        
        
        
        
        
        
        public bool TryGetBaseline(PageIteratorLevel level, out Rect bounds)
        {
            VerifyNotDisposed();
            int x1, y1, x2, y2;
            if (handle.Handle != IntPtr.Zero && TessApi.Native.PageIteratorBaseline(handle, level, out x1, out y1, out x2, out y2) != 0)
            {
                bounds = Rect.FromCoords(x1, y1, x2, y2);
                return true;
            }

            bounds = Rect.Empty;
            return false;
        }

        
        
        
        public ElementProperties GetProperties()
        {
            VerifyNotDisposed();
            if (handle.Handle == IntPtr.Zero) {
                return new ElementProperties(Orientation.PageUp, TextLineOrder.TopToBottom, WritingDirection.LeftToRight, 0f);
            }

            TessApi.Native.PageIteratorOrientation(handle, out var orientation, out var writingDirection, out var textLineOrder, out var deskewAngle);

            return new ElementProperties(orientation, textLineOrder, writingDirection, deskewAngle);
        }


        protected override void Dispose(bool disposing)
        {
            if (handle.Handle != IntPtr.Zero) {
                TessApi.Native.PageIteratorDelete(handle);
            }
        }
    }
}

