using System;
using System.Collections.Generic;
using System.Text;

using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using TSpdf.Kernel.Font;
using TSpdf.IO.Font.Constants;
using static tsPDFUtilsCore.Imagenes;
using static tsPDFUtilsCore.Enums;


namespace tsPDFUtilsCore
{
    public class Imagenes
    {
        public static Bitmap RedimensionaImagen(Bitmap Original, int NuevoAlto, int NuevoAncho, int CoordenadaX, int CoordenadaY)
        {
            Bitmap newImage = new Bitmap(NuevoAncho, NuevoAlto);
            using (Graphics g = Graphics.FromImage(newImage))
            {
                g.Clear(Color.Transparent);
                g.DrawImage(Original, CoordenadaX, CoordenadaY, Original.Width, Original.Height);
            }
            return newImage;
        }

        public static Bitmap crearBitMapFirmas(List<DatosTextos> listadoTextos, List<DatosImagenFirma> listadoImagenes, List<DatosFuente> ListadoFuentes, TSpdf.Kernel.Geom.Rectangle medidas)
        {
            int dpi = 600;

            int anchoPixeles = (int)medidas.GetWidth() * dpi / 72;
            int altoPixeles = (int)medidas.GetHeight() * dpi / 72;

            Bitmap bmp = new Bitmap(anchoPixeles, altoPixeles, PixelFormat.Format32bppArgb);
            bmp.SetResolution(dpi, dpi);
            Graphics g = Graphics.FromImage(bmp);

            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

            g.Clear(Color.Transparent);

          


            // Dibujar textos
            foreach (var texto in listadoTextos)
            {
                Font font = null;

                if (FontFamily.Families.Any(x => x.Name == texto.NombreFuente))
                    font = new Font(FontFamily.Families.Where(x => x.Name == texto.NombreFuente).First(), texto.size, texto.estiloTexto, GraphicsUnit.Point);
                else if (ListadoFuentes != null && ListadoFuentes.Any(x => x.NombreFuente == texto.NombreFuente))
                {
                    var fuente = ListadoFuentes.Where(x => x.NombreFuente == texto.NombreFuente).First();

                    int dataLength = fuente.memoryFont.Length;
                    IntPtr ptrData = Marshal.AllocCoTaskMem(dataLength);

                    Marshal.Copy(fuente.memoryFont, 0, ptrData, dataLength);

                    PrivateFontCollection privateFontCollection = new PrivateFontCollection();
                    privateFontCollection.AddMemoryFont(ptrData, dataLength);

                    font = new Font(privateFontCollection.Families.FirstOrDefault(), texto.size, texto.estiloTexto, GraphicsUnit.Point);
                }
                else
                    throw new Exception("Fuente " + texto.NombreFuente + " no encontrada");


                var sizeTexto = g.MeasureString(texto.texto, font);

                var coordenadaX = calcularX(texto.distanciaX, texto.distanciaY, texto.PosicionEsquina, bmp, texto.anguloRotacion, (int)sizeTexto.Width, (int)sizeTexto.Height);
                var coordenadaY = calcularY(texto.distanciaY, texto.distanciaX, texto.PosicionEsquina, bmp, texto.anguloRotacion, (int)sizeTexto.Width, (int)sizeTexto.Height);

                PointF rotationPoint = new PointF(texto.distanciaX, texto.distanciaY);

                g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;

                StringFormat stringFormat = new StringFormat();

                g.TranslateTransform(0, 0);
                g.RotateTransform(texto.anguloRotacion);

                if (texto.AlineacionTexto != AlineamientoEnum.JUSTIFICADO)
                    g.DrawString(texto.texto, font, texto.colorTexto, new PointF(coordenadaX, coordenadaY));
                else
                    DrawJustifiedString(ref g, texto.texto, font, texto.colorTexto, new RectangleF(coordenadaX, coordenadaY, altoPixeles, sizeTexto.Height), stringFormat);
                g.ResetTransform();
            }

            foreach (var imagen in listadoImagenes)
            {
                MemoryStream stream = new MemoryStream();
                stream.Write(imagen.Imagen, 0, imagen.Imagen.Length);
                System.Drawing.Image myImage = System.Drawing.Image.FromStream(stream);

                g.TranslateTransform(0, 0);
                g.RotateTransform(imagen.AnguloRotacion);

                int coordenadaX = calcularX(imagen.PosicionX, imagen.PosicionY, imagen.PosicionEsquina, bmp, imagen.AnguloRotacion, myImage.Width, myImage.Height);
                int coordenadaY = calcularY(imagen.PosicionY, imagen.PosicionX, imagen.PosicionEsquina, bmp, imagen.AnguloRotacion, myImage.Width, myImage.Height);

                if (altoPixeles > anchoPixeles)
                    g.DrawImage(myImage, new Rectangle(coordenadaX, coordenadaY, altoPixeles, anchoPixeles));
                else
                    g.DrawImage(myImage, new Rectangle(coordenadaX, coordenadaY, anchoPixeles, altoPixeles));


                g.ResetTransform();
            }
            return bmp;
        }
        public static byte[] BitMapAByteArray(Bitmap bmp)
        {
            MemoryStream msSalida = new MemoryStream();
            bmp.Save(msSalida, ImageFormat.Png);
            byte[] byteArray = msSalida.ToArray();
            msSalida.Close();
            return byteArray;
        }

        public static void DrawJustifiedString(ref Graphics g, string txt, Font font, Brush brush, RectangleF destination, StringFormat format)
        {
            using (StringFormat fmt = (StringFormat)format.Clone())
            {
                fmt.FormatFlags = fmt.FormatFlags | StringFormatFlags.MeasureTrailingSpaces;
                CharacterRange[] cr = { new CharacterRange(0, 1) };
                fmt.SetMeasurableCharacterRanges(cr);
                fmt.Alignment = StringAlignment.Center; 

                float txtWidth = g.MeasureString(txt, font, destination.Location, fmt).Width;
                float spacing = (destination.Width - txtWidth) / (txt.Length - 1);

                RectangleF dest = new RectangleF(destination.X, destination.Y, 0, destination.Height);
                foreach (char c in txt.AsEnumerable())
                {
                    // Graphics#MeasureString is too inaccurate for character placement
                    dest.Width = g.MeasureCharacterRanges(c.ToString(), font, destination, fmt)[0].GetBounds(g).Width;
                    g.DrawString(c.ToString(), font, brush, dest, fmt);
                    dest.X += dest.Width + spacing;
                }
            }
        }

        private static int calcularX(int coordenadaX, int coordenadaY, EsquinaEnum PosicionEsquina, Bitmap medidasFirma, float rotacionElemento, int anchoElemento, int altoElemento)
        {
            int anchoFirma = medidasFirma.Width;
            int altoFirma = medidasFirma.Height;

            int ejeX = 0;

            switch (PosicionEsquina)
            {
                case EsquinaEnum.SUPERIOR_IZQUIERDA:
                    {
                        switch (rotacionElemento)
                        {
                            case 90:
                                {
                                    ejeX = coordenadaY;
                                    break;
                                }

                            case 180:
                                {
                                    ejeX = -coordenadaX - anchoElemento;
                                    break;
                                }

                            case 270:
                                {
                                    ejeX = -coordenadaY - anchoElemento;
                                    break;
                                }

                            default:
                                {
                                    ejeX = coordenadaX;
                                    break;
                                }
                        }

                        break;
                    }

                case EsquinaEnum.INFERIOR_IZQUIERDA:
                    {
                        switch (rotacionElemento)
                        {
                            case 90:
                                {
                                    ejeX = (altoFirma - (coordenadaY + anchoElemento));
                                    break;
                                }

                            case 180:
                                {
                                    ejeX = -coordenadaX - anchoElemento;
                                    break;
                                }

                            case 270:
                                {
                                    ejeX = coordenadaY - altoFirma;
                                    break;
                                }

                            default:
                                {
                                    ejeX = coordenadaX;
                                    break;
                                }
                        }

                        break;
                    }

                case EsquinaEnum.SUPERIOR_DERECHA:
                    {
                        switch (rotacionElemento)
                        {
                            case 90:
                                {
                                    ejeX = coordenadaY;
                                    break;
                                }

                            case 180:
                                {
                                    ejeX = -anchoFirma + coordenadaX;
                                    break;
                                }

                            case 270:
                                {
                                    ejeX = -coordenadaY - anchoElemento;
                                    break;
                                }

                            default:
                                {
                                    ejeX = anchoFirma - (anchoElemento + coordenadaX);
                                    break;
                                }
                        }

                        break;
                    }

                case EsquinaEnum.INFERIOR_DERECHA:
                    {
                        switch (rotacionElemento)
                        {
                            case 90:
                                {
                                    ejeX = (altoFirma - (coordenadaY + anchoElemento));
                                    break;
                                }

                            case 180:
                                {
                                    ejeX = -anchoFirma + coordenadaX;
                                    break;
                                }

                            case 270:
                                {
                                    ejeX = coordenadaY - altoFirma;
                                    break;
                                }

                            default:
                                {
                                    ejeX = anchoFirma - (anchoElemento + coordenadaX);
                                    break;
                                }
                        }

                        break;
                    }
            }

            return ejeX;
        }
        private static int calcularY(int coordenadaY, int coordenadaX, EsquinaEnum PosicionEsquina, Bitmap medidasFirma, float rotacionElemento, int anchoElemento, int altoElemento)
        {
            int anchoFirma = medidasFirma.Width;
            int altoFirma = medidasFirma.Height;
            int ejeY = 0;

            switch (PosicionEsquina)
            {
                case EsquinaEnum.SUPERIOR_IZQUIERDA:
                    {
                        switch (rotacionElemento)
                        {
                            case 90:
                                {
                                    ejeY = -coordenadaX - altoElemento;
                                    break;
                                }

                            case 180:
                                {
                                    ejeY = -coordenadaY - altoElemento;
                                    break;
                                }

                            case 270:
                                {
                                    ejeY = coordenadaX;
                                    break;
                                }

                            default:
                                {
                                    ejeY = coordenadaY;
                                    break;
                                }
                        }

                        break;
                    }

                case EsquinaEnum.INFERIOR_IZQUIERDA:
                    {
                        switch (rotacionElemento)
                        {
                            case 90:
                                {
                                    ejeY = -coordenadaX - altoElemento;
                                    break;
                                }

                            case 180:
                                {
                                    ejeY = -altoFirma + coordenadaY;
                                    break;
                                }

                            case 270:
                                {
                                    ejeY = coordenadaX;
                                    break;
                                }

                            default:
                                {
                                    ejeY = altoFirma - (altoElemento + coordenadaY);
                                    break;
                                }
                        }

                        break;
                    }

                case EsquinaEnum.SUPERIOR_DERECHA:
                    {
                        switch (rotacionElemento)
                        {
                            case 90:
                                {
                                    ejeY = coordenadaX - (anchoFirma);
                                    break;
                                }

                            case 180:
                                {
                                    ejeY = -coordenadaY - altoElemento;
                                    break;
                                }

                            case 270:
                                {
                                    ejeY = anchoFirma - (altoElemento + coordenadaX);
                                    break;
                                }

                            default:
                                {
                                    ejeY = coordenadaY;
                                    break;
                                }
                        }

                        break;
                    }

                case EsquinaEnum.INFERIOR_DERECHA:
                    {
                        switch (rotacionElemento)
                        {
                            case 90:
                                {
                                    ejeY = coordenadaX - (anchoFirma);
                                    break;
                                }

                            case 180:
                                {
                                    ejeY = -altoFirma + coordenadaY;
                                    break;
                                }

                            case 270:
                                {
                                    ejeY = anchoFirma - (altoElemento + coordenadaX);
                                    break;
                                }

                            default:
                                {
                                    ejeY = altoFirma - (altoElemento + coordenadaY);
                                    break;
                                }
                        }

                        break;
                    }
            }

            return ejeY;
        }
        private static TSpdf.Kernel.Font.PdfFont devolverTipoFuente(string nombreFuente)
        {
            TSpdf.Kernel.Font.PdfFont tipoFuente;

            switch (nombreFuente)
            {
                case "COURIER":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.COURIER);
                        break;
                    }

                case "COURIER_BOLD":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.COURIER_BOLD);
                        break;
                    }

                case "COURIER_BOLDOBLIQUE":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.COURIER_BOLDOBLIQUE);
                        break;
                    }

                case "COURIER_OBLIQUE":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.COURIER_OBLIQUE);
                        break;
                    }

                case "HELVETICA":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.HELVETICA);
                        break;
                    }

                case "HELVETICA_BOLD":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD);
                        break;
                    }

                case "HELVETICA_BOLDOBLIQUE":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLDOBLIQUE);
                        break;
                    }

                case "HELVETICA_OBLIQUE":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_OBLIQUE);
                        break;
                    }

                case "SYMBOL":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.SYMBOL);
                        break;
                    }

                case "TIMES_ROMAN":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
                        break;
                    }

                case "TIMES_BOLD":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.TIMES_BOLD);
                        break;
                    }

                case "TIMES_BOLDITALIC":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.TIMES_BOLDITALIC);
                        break;
                    }

                case "TIMES_ITALIC":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.TIMES_ITALIC);
                        break;
                    }

                case "ZAPFDINGBATS":
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.ZAPFDINGBATS);
                        break;
                    }

                default:
                    {
                        tipoFuente = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
                        break;
                    }
            }

            return tipoFuente;
        }

    }
 
}


      public enum EsquinaEnum : int
        {
            INFERIOR_IZQUIERDA = 0,
            INFERIOR_DERECHA = 1,
            SUPERIOR_IZQUIERDA = 2,
            SUPERIOR_DERECHA = 3
        }

        public enum AlineamientoEnum : int
        {
            IZQUIERDA = 0,
            DERECHA = 1,
            CENTRO = 2,
            JUSTIFICADO = 3,
            JUSTIFICADO_ALL = 4
        }


        public enum TipoTextoEnum : int
        {
            NORMAL = 0,
            NUMERO_PAGINA = 1,
            NUMERO_PAGINA_TOTAL_PAGINAS = 2,
        }
        public enum FuenteEnum
        {
            COURIER,
            COURIER_BOLD,
            COURIER_BOLDOBLIQUE,
            COURIER_OBLIQUE,
            HELVETICA,
            HELVETICA_BOLD,
            HELVETICA_BOLDOBLIQUE,
            HELVETICA_OBLIQUE,
            SYMBOL,
            TIMES_ROMAN,
            TIMES_BOLD,
            TIMES_BOLDITALIC,
            TIMES_ITALIC,
            ZAPFDINGBATS
        }





