public GameBoyPrinterEmulatorWindow(IControllerReader reader)
        {
            if (Properties.Settings.Default.UpgradeRequired)
            {
                Properties.Settings.Default.Upgrade();
                Properties.Settings.Default.UpgradeRequired = false;
                Properties.Settings.Default.Save();
            }

            InitializeComponent();
            DataContext = this;

            _reader = reader ?? throw new ArgumentNullException(nameof(reader));

            SelectedPalette = Properties.Settings.Default.SelectedPalette;
            PrintSize       = Properties.Settings.Default.PrintSize;

            using (Bitmap bmp = new Bitmap(Properties.Resources.PrintImage))
            {
                _imageBuffer = new BitmapPixelMaker(480, 432);

                _imageBuffer.SetColor(palettes[SelectedPalette][0][3], palettes[SelectedPalette][1][3], palettes[SelectedPalette][2][3]);

                for (int i = 0; i < bmp.Width; ++i)
                {
                    for (int j = 0; j < bmp.Height; ++j)
                    {
                        System.Drawing.Color pixel = bmp.GetPixel(i, j);
                        if (pixel.R == 255 && pixel.G == 255 && pixel.B == 255)
                        {
                            _imageBuffer.SetRed(i, j, palettes[SelectedPalette][0][0]);
                            _imageBuffer.SetGreen(i, j, palettes[SelectedPalette][1][0]);
                            _imageBuffer.SetBlue(i, j, palettes[SelectedPalette][2][0]);
                        }
                    }
                }

                WriteableBitmap wbitmap = _imageBuffer.MakeBitmap(96, 96);

                // Create an Image to display the bitmap.
                _image = new System.Windows.Controls.Image
                {
                    Stretch = Stretch.None,
                    Margin  = new Thickness(0)
                };

                _             = GameBoyPrinterEmulatorWindowGrid.Children.Add(_image);
                _image.Source = wbitmap;

                _reader.ControllerStateChanged += Reader_ControllerStateChanged;
                _reader.ControllerDisconnected += Reader_ControllerDisconnected;

                CheckPalette(SelectedPalette);
                CheckSize(PrintSize);
            }
        }
        private void Paint(BitmapPixelMaker canvas, byte[] pixels, int pixel_width, int pixel_height, int tile_x_offset, int tile_y_offset)
        {   // This paints the tile with a specified offset and pixel width
            int pixel_x_offset = TILE_PIXEL_WIDTH * tile_x_offset * pixel_width;
            int pixel_y_offset = TILE_PIXEL_HEIGHT * tile_y_offset * pixel_height;


            for (int i = 0; i < TILE_PIXEL_WIDTH; i++)
            {     // pixels along the tile's x axis
                for (int j = 0; j < TILE_PIXEL_HEIGHT; j++)
                { // pixels along the tile's y axis
                    canvas.SetRect(pixel_x_offset + (i * pixel_width),
                                   pixel_y_offset + (j * pixel_height),
                                   pixel_width,
                                   pixel_height,
                                   palettes[SelectedPalette][0][pixels[(j * TILE_PIXEL_WIDTH) + i]],
                                   palettes[SelectedPalette][1][pixels[(j * TILE_PIXEL_WIDTH) + i]],
                                   palettes[SelectedPalette][2][pixels[(j * TILE_PIXEL_WIDTH) + i]]);
                }
            }
        }
        private void DisplayError()
        {
            SelectedPalette = Properties.Settings.Default.SelectedPalette;
            PrintSize       = Properties.Settings.Default.PrintSize;

            using (Bitmap bmp = new Bitmap(Properties.Resources.ErrorImage))
            {
                _imageBuffer = new BitmapPixelMaker(480, 432);

                _imageBuffer.SetColor(palettes[SelectedPalette][0][3], palettes[SelectedPalette][1][3], palettes[SelectedPalette][2][3]);

                for (int i = 0; i < bmp.Width; ++i)
                {
                    for (int j = 0; j < bmp.Height; ++j)
                    {
                        System.Drawing.Color pixel = bmp.GetPixel(i, j);
                        if (pixel.R == 255 && pixel.G == 255 && pixel.B == 255)
                        {
                            _imageBuffer.SetRed(i, j, palettes[SelectedPalette][0][0]);
                            _imageBuffer.SetGreen(i, j, palettes[SelectedPalette][1][0]);
                            _imageBuffer.SetBlue(i, j, palettes[SelectedPalette][2][0]);
                        }
                    }
                }


                // imageBuffer.SetColor(0, 0, 0);
                // Convert the pixel data into a WriteableBitmap.
                WriteableBitmap wbitmap = _imageBuffer.MakeBitmap(96, 96);

                // Set the Image source.
                _image.Source = wbitmap;

                GameBoyPrinterEmulatorWindowGrid.Height = 432;
                GameBoyPrinterEmulatorWindowGrid.Width  = 480;
                Height = 432;
                Width  = 480;
            }
        }
        private void Reader_ControllerStateChanged(object reader, ControllerStateEventArgs e)
        {
            _imageBuffer.SetColor(0, 0, 0, 255);

            int square_width  = PrintSize;// 480 / (TILE_PIXEL_WIDTH * TILES_PER_LINE);
            int square_height = square_width;

            string[] tiles_rawBytes_array = e.RawPrinterData.Split('\n');

            int total_tile_count = 0;

            for (int tile_i = 0; tile_i < tiles_rawBytes_array.Length; tile_i++)
            {
                string tile_element = tiles_rawBytes_array[tile_i];

                // Check for invalid raw lines
                if (tile_element.Length == 0)
                {   // Skip lines with no bytes (can happen with .split() )
                    continue;
                }
                else if (tile_element.StartsWith("!", StringComparison.Ordinal))
                {   // Skip lines used for comments
                    continue;
                }
                else if (tile_element.StartsWith("#", StringComparison.Ordinal))
                {   // Skip lines used for comments
                    continue;
                }
                else if (tile_element.StartsWith("//", StringComparison.Ordinal))
                {   // Skip lines used for comments
                    continue;
                }
                else if (tile_element.StartsWith("{", StringComparison.Ordinal))
                {   // Skip lines used for comments
                    continue;
                }
                total_tile_count++;
            }

            int tile_height_count = total_tile_count / TILES_PER_LINE;

            if (tile_height_count == 0)
            {
                DisplayError();
                return;
            }

            _imageBuffer = new BitmapPixelMaker(square_width * TILE_PIXEL_WIDTH * TILES_PER_LINE, square_height * TILE_PIXEL_HEIGHT * tile_height_count);

            _image.Height = square_height * TILE_PIXEL_HEIGHT * tile_height_count;
            _image.Width  = square_width * TILE_PIXEL_WIDTH * TILES_PER_LINE;
            GameBoyPrinterEmulatorWindowGrid.Height = square_height * TILE_PIXEL_HEIGHT * tile_height_count;;
            GameBoyPrinterEmulatorWindowGrid.Width  = square_width * TILE_PIXEL_WIDTH * TILES_PER_LINE;
            Height = square_height * TILE_PIXEL_HEIGHT * tile_height_count;
            Width  = square_width * TILE_PIXEL_WIDTH * TILES_PER_LINE;

            int tile_count = 0;

            for (int tile_i = 0; tile_i < tiles_rawBytes_array.Length; tile_i++)
            {
                string tile_element = tiles_rawBytes_array[tile_i];

                // Check for invalid raw lines
                if (tile_element.Length == 0)
                {   // Skip lines with no bytes (can happen with .split() )
                    continue;
                }
                else if (tile_element.StartsWith("!", StringComparison.Ordinal))
                {   // Skip lines used for comments
                    continue;
                }
                else if (tile_element.StartsWith("#", StringComparison.Ordinal))
                {   // Skip lines used for comments
                    continue;
                }
                else if (tile_element.StartsWith("//", StringComparison.Ordinal))
                {   // Skip lines used for comments
                    continue;
                }
                else if (tile_element.StartsWith("{", StringComparison.Ordinal))
                {   // Skip lines used for comments
                    continue;
                }

                // Gameboy Tile Offset
                int tile_x_offset = tile_count % TILES_PER_LINE;
                int tile_y_offset = tile_count / TILES_PER_LINE;

                byte[] pixels = Decode(tile_element);

                if (pixels != null)
                {
                    Paint(_imageBuffer, pixels, square_width, square_height, tile_x_offset, tile_y_offset);
                }
                else
                {
                    //status = false;
                }


                // Increment Tile Count Tracker
                tile_count++;
            }

            //imageBuffer.SetColor(0, 0, 0);
            // Convert the pixel data into a WriteableBitmap.
            WriteableBitmap wbitmap = _imageBuffer.MakeBitmap(96, 96);

            // Set the Image source.
            _image.Source = wbitmap;
        }