using System;
using Tesseract.Interop;

namespace Tesseract
{
	public unsafe class PixData
	{
		public Pix Pix { get; private set; }

		
		internal PixData(Pix pix)
		{		
            Pix = pix;
            Data = LeptonicaApi.Native.pixGetData(Pix.Handle);
            WordsPerLine = LeptonicaApi.Native.pixGetWpl(Pix.Handle);
 		}
		
		
		
		
		public IntPtr Data { get; private set; }
		
		
		
		
		public int WordsPerLine { get; private set; }

        
        
        
        
        
        
        
        public void EndianByteSwap()
        {
            LeptonicaApi.Native.pixEndianByteSwap(Pix.Handle);
        }

	    public int HorizontalResolution
        {
	        get
	        {
	            LeptonicaApi.Native.pixGetResolution(Pix.Handle, out int xres, out int yres);
	            return xres;
	        }
        }

	    public int VerticalResolution
	    {
	        get
	        {
	            LeptonicaApi.Native.pixGetResolution(Pix.Handle, out int xres, out int yres);
	            return yres;
	        }
	    }

#if Net45
       	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static uint EncodeAsRGBA(byte red, byte green, byte blue, byte alpha)
        {
            return (uint)((red << 24) |
                (green << 16) |
                (blue << 8) |
                alpha);
        }

        
        
        
#if Net45
      	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
		public static uint GetDataBit(uint* data, int index)
		{
			return (*(data + ((index) >> 5)) >> (31 - ((index) & 31))) & 1;			
		}


        
        
        
#if Net45
      	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
		public static void SetDataBit(uint* data, int index, uint value)
		{
			uint* wordPtr = data + ((index) >> 5);
            *wordPtr &= ~(0x80000000 >> ((index) & 31));
            *wordPtr |= (value << (31 - ((index) & 31)));		
		}


        
        
        
#if Net45
      	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
		public static uint GetDataDIBit(uint* data, int index)
		{
			return (*(data + ((index) >> 4)) >> (2 * (15 - ((index) & 15)))) & 3;	
		}



        
        
        
#if Net45
      	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
		public static void SetDataDIBit(uint* data, int index, uint value)
		{
			uint* wordPtr = data + ((index) >> 4);
            *wordPtr &= ~(0xc0000000 >> (2 * ((index) & 15)));
            *wordPtr |= (((value) & 3) << (30 - 2 * ((index) & 15)));			
		}


        
        
        
#if Net45
      	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
		public static uint GetDataQBit(uint* data, int index)
		{
			return (*(data + ((index) >> 3)) >> (4 * (7 - ((index) & 7)))) & 0xf;			
		}


        
        
        
#if Net45
      	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
		public static void SetDataQBit(uint* data, int index, uint value)
		{
			uint* wordPtr = data + ((index) >> 3);
            *wordPtr &= ~(0xf0000000 >> (4 * ((index) & 7)));
            *wordPtr |= (((value) & 15) << (28 - 4 * ((index) & 7)));		
		}


        
        
        
#if Net45
      	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
		public static uint GetDataByte(uint* data, int index)
        {
            
			if(IntPtr.Size == 8) {
        		return *((byte*)((ulong)((byte*)data + index) ^ 3));
			}

            return *((byte*)((uint)((byte*)data + index) ^ 3));
            
            
        }


        
        
        
#if Net45
      	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
		public static void SetDataByte(uint* data, int index, uint value)
		{			
			
			if(IntPtr.Size == 8) {
				*(byte*)((ulong)((byte*)data + index) ^ 3) = (byte)value;
			} else {
			 	*(byte*)((uint)((byte*)data + index) ^ 3) = (byte)value;
			}
			
			
			
		}


        
        
        
#if Net45
      	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
		public static uint GetDataTwoByte(uint* data, int index)
        {
            
			if(IntPtr.Size == 8) {
                return *(ushort*)((ulong)((ushort*)data + index) ^ 2);
			}

            return *(ushort*)((uint)((ushort*)data + index) ^ 2);
            
            
        }


        
        
        
#if Net45
      	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
		public static void SetDataTwoByte(uint* data, int index, uint value)
		{
			
			if(IntPtr.Size == 8) {
    			*(ushort*)((ulong)((ushort*)data + index) ^ 2) = (ushort)value;
			} else {
           		*(ushort*)((uint)((ushort*)data + index) ^ 2) = (ushort)value;
			}
			
            
		}


        
        
        
#if Net45
      	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
		public static uint GetDataFourByte(uint* data, int index)
		{
         	return *(data + index);		
		}


        
        
        
#if Net45
      	[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
		public static void SetDataFourByte(uint* data, int index, uint value)
		{
			*(data + index) = value;			
		}
        


	}
}

