using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BitMiracle.LibTiff.Classic;
using OpenCvSharp;

namespace Scan.ReadSoftEmulation
{
    internal static class MatExtensions
    {
        public static void SaveAsMonochrome(this Mat bitmap, double dpi, string filename)
        {
            var black = byte.MinValue;
            var white = byte.MaxValue;
            
            var cols = bitmap.Cols;
            var rowLength = (int) Math.Ceiling(cols / 8d);
            var bytes = new MatOfByte(bitmap);
            var indexer = bytes.GetIndexer();
            try
            {
                using (var output = Tiff.Open(filename, "w"))
                {
                    output.SetField(TiffTag.IMAGEWIDTH, cols);
                    output.SetField(TiffTag.IMAGELENGTH, bitmap.Rows);
                    output.SetField(TiffTag.SAMPLESPERPIXEL, 1);
                    output.SetField(TiffTag.BITSPERSAMPLE, 1);
                    output.SetField(TiffTag.ORIENTATION, Orientation.TOPLEFT);
                    output.SetField(TiffTag.ROWSPERSTRIP, bitmap.Rows);
                    output.SetField(TiffTag.XRESOLUTION, dpi);
                    output.SetField(TiffTag.YRESOLUTION, dpi);
                    output.SetField(TiffTag.RESOLUTIONUNIT, ResUnit.INCH);
                    output.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
                    output.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISWHITE);
                    output.SetField(TiffTag.COMPRESSION, Compression.CCITTFAX3);
                    output.SetField(TiffTag.FILLORDER, FillOrder.MSB2LSB);

                    for (var row = 0; row < bitmap.Rows; row++)
                    {
                        var outBytes = new byte[rowLength];

                        var curByteIndex = 0;
                        var bitIndex = 7;
                        for (var col = 0; col < cols; col++)
                        {
                            var pixel = indexer[row, col];
                            if (pixel == black)
                            {
                                outBytes[curByteIndex] |= (byte)(1 << bitIndex);
                            }
                            else if (pixel != white)
                            {
                                throw new FormatException("Only monochrome images are supported");
                            }

                            --bitIndex;
                            if (bitIndex >= 0)
                            {
                                continue;
                            }

                            bitIndex = 7;
                            ++curByteIndex;
                        }
                        output.WriteScanline(outBytes, row);
                    }
                }
            }
            finally
            {
                bytes.Dispose();
            }
        }
    }
}

