using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ImageProcessor
{
	public static class FrameInjector
	{
		public static void GetBitmapPixels ( Bitmap originalBitmap, out Color [ , ] bitmapPixels, out int originalBitmapWidth, out int originalBitmapHeight )
		{
			Color [ , ] calced;
			lock ( originalBitmap )
			{
				originalBitmapWidth = originalBitmap.Width;
				originalBitmapHeight = originalBitmap.Height;
				calced = new Color [ originalBitmap.Width, originalBitmap.Height ];

				for ( int y1 = 0; y1 < originalBitmapHeight; y1++ )
					for ( int x1 = 0; x1 < originalBitmapWidth; x1++ )
						calced [ x1, y1 ] = originalBitmap.GetPixel ( x1, y1 );
			}
			bitmapPixels = calced;
		}

		public static async Task<Bitmap> Injection ( Bitmap originalBitmap, int frame, Color backgroundColor, Color frameColor )
		{
			Color [ , ] calced;
			int originalBitmapWidth, originalBitmapHeight;
			GetBitmapPixels ( originalBitmap, out calced, out originalBitmapWidth, out originalBitmapHeight );
			return await Injection ( calced, originalBitmapWidth, originalBitmapHeight, frame, backgroundColor, frameColor );
		}

		public static async Task<Bitmap> Injection ( Color [ , ] originalBitmap, int originalBitmapWidth, int originalBitmapHeight,
			int frame, Color backgroundColor, Color frameColor )
		{
			return await Task.Run<Bitmap> ( () =>
			{
				Color [ , ] calced = originalBitmap.Clone () as Color [ , ];
				Color [ , ] temp = new Color [ originalBitmapWidth, originalBitmapHeight ];
				for ( int i = 0; i < frame; i++ )
				{
					Parallel.For ( 0, originalBitmapHeight, ( int y1 ) =>
					{
						Parallel.For ( 0, originalBitmapWidth, ( int x1 ) =>
						{
								temp [ x1, y1 ] = backgroundColor;
						} );
					} );

					Parallel.For ( 0, originalBitmapWidth, ( int x ) =>
					{
						Parallel.For ( 0, originalBitmapHeight, ( int y ) =>
						{
							if ( calced [ x, y ] != backgroundColor &&
								!( calced [ x, y ].A == 0 && backgroundColor.A == 0 ) )
							{
								if ( x - 1 >= 0 )
									temp [ x - 1, y ] = frameColor;
								if ( y - 1 >= 0 )
									temp [ x, y - 1 ] = frameColor;
								if ( x + 1 < originalBitmapWidth )
									temp [ x + 1, y ] = frameColor;
								if ( y + 1 < originalBitmapHeight )
									temp [ x, y + 1 ] = frameColor;
							}
						} );
					} );

					Parallel.For ( 0, originalBitmapWidth, ( int x1 ) =>
					{
						Parallel.For ( 0, originalBitmapHeight, ( int y1 ) =>
						{
							if ( calced [ x1, y1 ] == backgroundColor )
								calced [ x1, y1 ] = temp [ x1, y1 ];
						} );
					} );
				}

				Bitmap retValue = new Bitmap ( originalBitmapWidth, originalBitmapHeight );

				for ( int y1 = 0; y1 < originalBitmapHeight; y1++ )
					for ( int x1 = 0; x1 < originalBitmapWidth; x1++ )
						retValue.SetPixel ( x1, y1, calced [ x1, y1 ] );
				return retValue;
			} );
		}
	}
}
