using System;
using System.Drawing;
using System.Drawing.Imaging;

namespace GrayScaleClass
{
    public class GrayScale
    {
        //--------------------------------------------------------
        public int Width { get { return FWidth; } }
        public int Height { get { return FHeight; } }
        public Bitmap BMP { get { return FGrayBitmap; } }
        public int StrIde { get { return FStrIde; } }

        public GrayScale (int Width, int Height)
        {
            CreateBitmap( Width, Height );
        }
        public GrayScale (Bitmap Source)
        {
            CreateBitmap( Source.Width, Source.Height );
            LockBits( ImageLockMode.ReadWrite );
            try
            {
                BitmapData BD = Source.LockBits( new Rectangle( 0, 0, FWidth, FHeight ), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb );
                try
                {
                    unsafe
                    {
                        byte* B0 = (byte*)BD.Scan0;
                        byte* B1 = (byte*)FData.Scan0;
                        int Len = FHeight * FStrIde;
                        int SW = ( FWidth * 3 + 3 ) / 4 * 4;
                        for ( int Y = 0; Y < FHeight; Y++ )
                        {
                            int SX = Y * SW;
                            int DX = Y * FStrIde;
                            for ( int X = 0; X < FWidth; X++ )
                            {
                                int BB = ( B0[ SX + X * 3 + 0 ] + B0[ SX + X * 3 + 1 ] + B0[ SX + X * 3 + 2 ] ) / 3;
                                B1[ DX + X ] = (byte)BB;
                            }
                        }
                    }
                }
                finally
                {
                    Source.UnlockBits( BD );
                }
            }
            finally
            {
                UnLock( );
            }
        }
        public void CreateBitmap (int Width, int Height)
        {
            FWidth = Width;
            FHeight = Height;
            FStrIde = ( ( FWidth + 3 ) / 4 ) * 4;
            int Len = FStrIde * FHeight;
            UnLock( );
            FGrayBitmap = new Bitmap( Width, Height, PixelFormat.Format8bppIndexed );

            ColorPalette P = FGrayBitmap.Palette;
            for ( int i = 0; i < P.Entries.Length; i++ )
                P.Entries[ i ] = Color.FromArgb( i, i, i );
            FGrayBitmap.Palette = P;
        }
        private bool LockBits ( )
        {
            return LockBits( ImageLockMode.ReadOnly );
        }
        private void UnLock ( )
        {
            if ( FData == null ) return;
            FGrayBitmap.UnlockBits( FData );
            FData = null;
        }

        public delegate Int32 DecBitsHandler (Int32 RowCount, Int32 ColCount, IntPtr[ ] PPBits);

        public event DecBitsHandler OnDecBits;

        bool LockBits (ImageLockMode Mode)
        {
            if ( FGrayBitmap == null ) return false;
            FData = FGrayBitmap.LockBits( new Rectangle( 0, 0, FWidth, FHeight ), Mode, PixelFormat.Format8bppIndexed );

            return true;
        }

        public int DecodeBits ( )
        {
            int Result = -1;
            if ( FGrayBitmap == null ) return -1;
            LockBits( ImageLockMode.ReadOnly );
            try
            {
                IntPtr[] FPBits = new IntPtr[ FHeight ];
                unsafe
                {
                    fixed ( IntPtr* imgPtr = FPBits )
                    {
                        int Buf = FData.Scan0.ToInt32( );
                        for ( int i = 0; i < FHeight; i++ )
                        {
                            imgPtr[ i ] = new IntPtr( Buf + i * FStrIde );
                        }
                        Result = OnDecBits( FHeight, FWidth, FPBits );
                    }
                }
            }
            finally
            {
                UnLock( );
            }

            return Result;
        }
        //--------------------------------------------------------

        private int FWidth, FHeight, FStrIde;
        private Bitmap FGrayBitmap;
        private BitmapData FData;
        //--------------------------------------------------------
    }

    public class StringConvertor
    {
        public StringConvertor (int codepage)
        {
            System.Text.Encoding EE = System.Text.Encoding.GetEncoding(codepage);

            Encoder = EE.Clone() as System.Text.Encoding;
            Encoder.DecoderFallback=System.Text.DecoderFallback.ExceptionFallback;//new System.Text.Encoder(codepage, System.Text.EncoderFallback.ReplacementFallback, System.Text.DecoderFallback.ExceptionFallback);
        }
        public StringConvertor ( )
        {
            Encoder = Console.Out.Encoding;
        }

        public string ByteArrayToString (byte[ ] A)
        {
            return Encoder.GetString( A, 0, A.Length );
        }

        public unsafe string PCharToString(byte* PC)
        {
            string Result = "";
            int Len = 0;
            byte* PPC = PC;
            while (*PC != 0) { Len++; PC++; };
            Result = PCharToString(PPC, Len);
            return Result;
        }

        public int CodePage { get { return Encoder.CodePage; } }
        public bool IsSingleByte { get { return Encoder.IsSingleByte; } }
        public unsafe string PCharToString(byte* PC, int Len)
        {
            string Result = "";
            byte[ ] A = PCharToArray( PC, Len );
            Result = ByteArrayToString( A );
            return Result;
        }

          public unsafe byte[] PCharToArray(byte* PC, int Len)
        {
            byte[ ] Result = new byte[ Len ];
            int i;
            for ( i = 0; i < Len; i++ )
            {
                byte B = *PC;
                Result[ i ] = B;
                PC++;
            }
            return Result;
        }
          public unsafe byte[] PWCharToArray(ushort* PC, int Len)
          {
              byte[] A = new byte[Len * 2];
              int i, j;
              j = 0;
              for (i = 0; i < Len; i++)
              {
                  ushort W = *PC;
                  byte B;
                  if ((W & 0xFF00) != 0)
                  {
                      B = (byte)(W >> 8);
                      A[j] = B; j++;
                  }
                  B = (byte)(W & 0xFF);
                  A[j] = B; j++;
                  PC++;
              }
              byte[] Result = new byte[j];
              Array.Copy(A, Result, j);

              return Result;
          }
          public System.Text.Encoding Encoder;
    }
    //
}
