using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SkiaSharp;
using ZXing;
using ZXing.Common;
using ZXing.QrCode.Internal;

namespace 常用工具集.Utility.Qrcode
{
    public class BarCodeUtils
    {
        public static SKBitmap EncodeBarCode(BarcodeFormat barcodeFormat, string message, int widthPixels, int hightPixels, out string svg)
        {
            Dictionary<EncodeHintType, object> hints = new Dictionary<EncodeHintType, object>();
            hints.Add(EncodeHintType.CHARACTER_SET, "utf-8");
            hints.Add(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            hints.Add(EncodeHintType.MARGIN, 1);
            BitMatrix matrix = new MultiFormatWriter().encode(message, barcodeFormat, widthPixels, hightPixels, hints);
            //matrix = deleteWhite(matrix);//删除白边
            SKBitmap bitmap = new SKBitmap(matrix.Width, matrix.Height);
            SKCanvas canvas = new SKCanvas(bitmap);
            canvas.Clear();
            SKPaint paint = new SKPaint()
            {
                Color = SKColors.Black,
                IsAntialias = true,
                Style = SKPaintStyle.Fill
            };


            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            sb.AppendLine($"<svg version=\"1.1\" id=\"图层_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\r\n\t viewBox=\"0 0 {matrix.Width} {matrix.Height}\" style=\"enable-background:new 0 0 {matrix.Width} {matrix.Height};\" xml:space=\"preserve\">");
            sb.AppendLine("<style type=\"text/css\">.st0{fill:#E60012;}</style>");
            bool[,] handled = new bool[matrix.Width, matrix.Height];//默认全部false
            for (int x = 0; x < matrix.Width; x++)
            {
                for (int y = 0; y < matrix.Height; y++)
                {
                    if (matrix[x, y] && !handled[x, y])
                    {
                        //从当前位置找矩形区域
                        FindRect(x, y, matrix, ref handled, out int width, out int height);
                        //x从x到x+width
                        //y从y到y+height 
                        //这些区域是已处理的
                        for (int i = 0; i < width; i++)
                        {
                            for (int j = 0; j < height; j++)
                            {
                                handled[x + i, y + j] = true;
                            }
                        }
                        sb.AppendLine($"<rect class=\"st0\" x=\"{x}\" y=\"{y}\" width=\"{width}\" height=\"{height}\" />");
                        canvas.DrawRect(x, y, width, height, paint);
                    }
                }
            }
            sb.AppendLine("</svg>");
            svg = sb.ToString();
            canvas.Dispose();
            return bitmap;



            //BarcodeWriter writer = new BarcodeWriter();
            ////使用ITF 格式，不能被现在常用的支付宝、微信扫出来
            ////如果想生成可识别的可以使用 CODE_128 格式
            ////writer.Format = BarcodeFormat.ITF;
            //writer.Format = barcodeFormat;
            //EncodingOptions options = new EncodingOptions()
            //{
            //    Width = widthPixels,
            //    Height = hightPixels,
            //    Margin = 2
            //};
            //writer.Options = options;
            //Bitmap map = writer.Write(message);
            //return map;
        }


        /// <summary>
        /// 找到未处理的矩形区域
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="matrix"></param>
        /// <param name="handled"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        private static void FindRect(int x, int y, BitMatrix matrix, ref bool[,] handled, out int width, out int height)
        {
            width = 1;
            height = 1;
            bool flag = false;
            int maxOffset = FindXMax(matrix, x, y, ref handled);
        A:
            if (maxOffset == 0)
            {
                return;
            }
            while (true)
            {
                height++;
                if ((y + height) >= matrix.Height)
                {
                    break;
                }
                if (!matrix[x, y + height] || handled[x, y + height])
                {
                    break;
                }
                bool allTrue = true;//默认最后一行全是true
                for (int i = 0; i < maxOffset; i++)
                {
                    if (!matrix[x + i, y + height])
                    {
                        allTrue = false;
                        break;
                    }
                    if (handled[x + i, y + height])
                    {
                        allTrue = false;
                        break;
                    }
                }
                if (allTrue)
                {
                    flag = true;
                }
                else
                {
                    if (flag || height == 2)
                    {
                        height--;
                        break;
                    }
                    maxOffset--;
                    flag = false;
                    goto A;
                }
            }
            width = maxOffset + 1;
        }

        private static int FindXMax(BitMatrix matrix, int x, int y, ref bool[,] handled)
        {
            int offset = 0;
            while (true)
            {
                if ((x + offset) > matrix.Width)
                {
                    break;
                }
                if (!matrix[x + offset, y])
                {
                    offset--;
                    break;
                }
                offset++;
            }
            return offset;
        }
        public static SKBitmap EncodeBarCode(string message, int widthPixels, int hightPixels, out string svg)
        {
            return EncodeBarCode(BarcodeFormat.CODE_128, message, widthPixels, hightPixels, out svg);
        }


        public static SKBitmap EncodeBarCode(string msg, out string svg)
        {
            return EncodeBarCode(msg, 960, 500, out svg);
        }
         
    }
}