<repo_name>xseg18/Lab2<file_sep>/Parte 1/Heap.cs
﻿using System;

namespace Parte_1
{
    public class Heap
    { 
        internal Node[] Queue;
        int p;
        internal class Node
        {
            internal Node Right;
            internal Node Left;
            internal Node Parent;
            IHuffman.Node Key;
            internal IHuffman.Node Keys
            {
                get => Key;
                set => Key = value;
            }
        }
        Node root;
        internal Heap(int x)
        {
            Queue = new Node[x + 1];
            p = 1;
        }

        internal void Add(IHuffman.Node value)
        {
            if(root == null)
            {
                root = new Node();
                root.Keys = value;
                Queue[p] = root;
                p++;
            }
            else
            {
                Node add = new Node
                {
                    Keys = value
                };
                //hijo izquierdo
                if(p%2 == 0)
                {
                    Queue[p / 2].Left = add;
                    add.Parent = Queue[p / 2];
                }
                else
                {
                    Queue[p / 2].Right = add;
                    add.Parent = Queue[p / 2];
                }
                Queue[p] = add;
                Ordenar(p);
                p++;
            }
        }

       
        void Ordenar(int x)
        {
            if (Queue[x] != null)
            {
                if (Queue[x].Keys.Prio < Queue[x/2].Keys.Prio)
                {
                    IHuffman.Node prov = Queue[x].Keys;
                    Queue[x].Keys = Queue[x/2].Keys;
                    Queue[x / 2].Keys = prov;
                    if (x/2 != 1)
                    {
                        Ordenar(x / 2);
                    }
                }
            }    
        }

        void OrdenarRaiz(int x)
        {
            //hijo izquierdo y que hijo izquierdo sea menor que hijo derecho
            if (Queue[(x * 2) + 1] != null)
            {
                if (Queue[x * 2].Keys.Prio < Queue[x].Keys.Prio && Queue[(x * 2) + 1].Keys.Prio >= Queue[x * 2].Keys.Prio)
                {
                    IHuffman.Node prov = Queue[x].Keys;
                    Queue[x].Keys = Queue[x * 2].Keys;
                    Queue[x * 2].Keys = prov;
                    if ((x * 2) * 2 < p || ((x * 2) * 2) + 1 < p)
                    {
                        OrdenarRaiz(x * 2);
                    }
                }
                else if (Queue[(x * 2) + 1].Keys.Prio < Queue[x].Keys.Prio)
                {
                    IHuffman.Node prov = Queue[x].Keys;
                    Queue[x].Keys = Queue[(x * 2) + 1].Keys;
                    Queue[(x * 2) + 1].Keys = prov;
                    if (((x * 2) + 1) * 2 < p || (((x * 2) + 1) * 2) + 1 < p)
                    {
                        OrdenarRaiz((x * 2) + 1);
                    }
                }
            }
            else if(Queue[(x * 2) + 1] == null)
            {
                if (Queue[x * 2].Keys.Prio < Queue[x].Keys.Prio)
                {
                    IHuffman.Node prov = Queue[x].Keys;
                    Queue[x].Keys = Queue[x * 2].Keys;
                    Queue[x * 2].Keys = prov;
                    if ((x * 2) * 2 < p || ((x * 2) * 2) + 1 < p)
                    {
                        OrdenarRaiz(x * 2);
                    }
                }
            }
        }

        internal IHuffman.Node Pop()
        {
            IHuffman.Node pop = root.Keys;
            if(Queue[2] != null)
            {
                Queue[1].Keys = Queue[p - 1].Keys;
                Queue[p - 1] = null;
                p--;
                if(p > 2)
                {
                    OrdenarRaiz(1);
                }
            }
            else
            {
                p = 1;
                root = null;
            }
            return pop;
        }

        internal int Count()
        {
            return p - 1;
        }
    }
}
<file_sep>/Parte 2/Program.cs
﻿using System;
using Parte_1;

namespace Parte_2
{
    class Program
    {
        static void Main(string[] args)
        {
            IHuffman h = new ImplementationClass();
            string prueba = h.Comprimir("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ullamcorper eros ut convallis placerat. Praesent tincidunt facilisis orci in aliquet. Sed convallis sapien erat, ac cursus felis tempus nec. Ut placerat tortor felis, sed accumsan velit elementum quis. Pellentesque finibus elit iaculis, luctus metus vitae, volutpat odio. Fusce feugiat quis lectus et dapibus. Nullam rutrum nisl massa, sed aliquet nisi faucibus non. Etiam eu ullamcorper metus. Sed vel leo aliquet, ullamcorper felis vitae, commodo velit. Phasellus aliquet condimentum convallis. Integer id ultrices magna. Mauris semper vitae odio non commodo.");
            string prueba2 = h.Descomprimir(prueba);
        }
    }
}
<file_sep>/Parte 1/Huffman.cs
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;


namespace Parte_1
{
    public interface IHuffman
    {
        //nodo árbol
        internal class Node
        {
            int Priority;
            char Symbol;
            internal Node Left;
            internal Node Right;
            internal Node Parent;
            internal int Prio
            {
                get => Priority;
                set => Priority = value;
            }
            internal char Symb
            {
                get => Symbol;
                set => Symbol = value;
            }
            //recorrido para código prefijo
            internal List<char> Recorrido(Node search, List<char> binary)
            {
                if(search != null)
                {
                    if(search.Parent.Left == search)
                    {
                        if (search.Parent.Parent != null)
                        {
                            Recorrido(search.Parent, binary);
                        }
                        binary.Add('0');
                    }
                    else
                    {
                        if (search.Parent.Parent != null)
                        {
                            Recorrido(search.Parent, binary);
                        }
                        binary.Add('1');
                    }
                    return binary;
                }
                return null;
            }
            //encuentra el nodo a partir del caracter
            internal Node Find(char s, Node root)
            {
                if (root != null)
                {
                    if (root.Symb == s)
                    {
                        return root;
                    }
                    else
                    {
                        Node found = Find(s, root.Left);
                        if (found == null)
                        {
                            found = Find(s, root.Right);
                        }
                        return found;
                    }
                }
                else
                {
                    return null;
                }
            }
        }
        public string Comprimir(string compress);
        public string Descomprimir(string decompress);
    }

    public class ImplementationClass : IHuffman
    {
        string IHuffman.Comprimir(string compress)
        {
            //diccionario donde se guardan las frecuencias
            Dictionary<char, int> Leyenda = new Dictionary<char, int>();
            for (int i = 0; i < compress.Length; i++)
            {
                if (!Leyenda.ContainsKey(compress[i]))
                {
                    Leyenda.Add(compress[i], 0);
                }
                Leyenda[compress[i]]++;
            }
            //cola de prioridad
            Heap PrioHeap = new Heap(Leyenda.Count);
            foreach (KeyValuePair<char, int> symbol in Leyenda)
            {
                IHuffman.Node a = new IHuffman.Node
                {
                    Symb = symbol.Key,
                    Prio = symbol.Value
                };
                PrioHeap.Add(a);
            }
            //árbol de códigos prefijo
            IHuffman.Node Parent = new IHuffman.Node();
            while (2 <= PrioHeap.Count())
            {
                IHuffman.Node Left = PrioHeap.Pop();
                IHuffman.Node Right = PrioHeap.Pop();
                Parent = new IHuffman.Node
                {
                    Prio = Left.Prio + Right.Prio,
                    Left = Left,
                    Right = Right
                };
                Left.Parent = Parent;
                Right.Parent = Parent;
                PrioHeap.Add(Parent);
            }
            //código binario de todo el árbol
            List<char> binary = new List<char>();
            for (int i = 0; i < compress.Length; i++)
            {
                IHuffman.Node s = Parent.Find(compress[i], Parent);
                Parent.Recorrido(s, binary);
            }
            //string final 
            String final = string.Empty;
            //Leyenda de letras
            foreach(var par in Leyenda)
            {
                final += par.Key + "[" + par.Value.ToString() + "]";
            }
            //Final de metadata
            final += "!eNd¡";
            //archivo comprimido    
            string p = "";
            for (int i = 0; i < binary.Count; i++)
            {
                p+= binary[i];
                if(p.Length == 8)
                {
                    final += Convert.ToChar(BinDec(Convert.ToInt32(p)));
                    p = "";
                }
            }
            if(p != "")
            {
                while (p.Length < 8)
                {
                    p += '0';
                }
                final += Convert.ToChar(BinDec(Convert.ToInt32(p)));
            }
            int x = final.Length;
            return final;
        }
        string IHuffman.Descomprimir(string decompress)
        {
            //encontrar metadata
            int pos = 0;
            string info = string.Empty;
            while (!info.Contains("!eNd¡"))
            {
                info += decompress[pos];
                pos++;
            }
            //quitamos metadata
            decompress = decompress.Remove(0, pos);
            //quitamos separador
            info = info.Replace("!eNd¡", "");
            //array de pares ordenados
            string[] par = info.Split(']');
            //pares ordenados separados
            string[] frequencies = info.Split('[', ']');
            //heap y contador de caracteres
            Heap PrioHeap = new Heap(par.Length);
            int charcount = 0;
            for (int i = 0; i < frequencies.Length - 1; i++)
            {
                IHuffman.Node a = new IHuffman.Node
                {
                    Symb = Convert.ToChar(frequencies[i]),
                    Prio = Convert.ToInt32(frequencies[i+1])
                };
                charcount += Convert.ToInt32(frequencies[i + 1]);
                PrioHeap.Add(a);
                i++;
            }
            //creación codigos prefijo
            IHuffman.Node Parent = new IHuffman.Node();
            while (2 <= PrioHeap.Count())
            {
                IHuffman.Node Left = PrioHeap.Pop();
                IHuffman.Node Right = PrioHeap.Pop();
                Parent = new IHuffman.Node
                {
                    Prio = Left.Prio + Right.Prio,
                    Left = Left,
                    Right = Right
                };
                Left.Parent = Parent;
                Right.Parent = Parent;
                PrioHeap.Add(Parent);
            }
            //diccionario códigos prefijo
            Dictionary<char, string> Prefix = new Dictionary<char, string>();
            for (int i = 0; i < par.Length - 1; i++)
            {
                IHuffman.Node found = Parent.Find(par[i][0], Parent);
                List<char> binary = new List<char>();
                Parent.Recorrido(found, binary);
                string path = "";
                for (int j = 0; j < binary.Count; j++)
                {
                    path += binary[j];
                }
                Prefix.Add(par[i][0], path); 
            }
            //descompresión de archivo 
            string actualpath = "";
            string final = "";
            char[] deco = decompress.ToArray<char>();
            //de caracteres a prefijos
            for (int i = 0; i < decompress.Length; i++)
            {
                actualpath += DecBin(decompress[i]);
            }
            //de prefijos a letras
            int cc = 0;
            while (charcount != cc)
            {
                foreach (var pars in Prefix)
                {
                    if (actualpath.StartsWith(pars.Value))
                    {
                        final += pars.Key;
                        actualpath = actualpath.Substring(pars.Value.Length);
                        break;
                    }
                }
                cc++;
            }
            return final;
        }
        int BinDec(long binary)
        {

            int decim = 0;
            int digit = 0;
            const int div = 10;

            for (long i = binary, j = 0; i > 0; i /= div, j++)
            {
                digit = (int)i % div;
                if (digit != 1 && digit != 0)
                {
                    return -1;
                }
                decim += digit * (int)Math.Pow(2, j);
            }
            return decim;
        }
        string DecBin(int decim)
        {
            long bin = 0;
            const int div = 2;
            long digit = 0;
            for (int i = decim % div, j = 0; decim > 0; decim /= div, i = decim % div, j++)
            {
                digit = i % div;
                bin += digit * (long)Math.Pow(10, j);
            }
            string Bin = bin.ToString();
            while (Bin.Length < 8)
            {
                Bin = "0" + Bin;
            }
            return Bin;
        }
    }
}
<file_sep>/Controllers/HuffmanController.cs
﻿using Lab2.Models.Data;
using Lab2.Models;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text;
using System.Threading.Tasks;
using Parte_1;

namespace Lab2.Controllers
{
    [ApiController]
    [Route("api")]
    public class HuffmanController : Controller
    {
        [Route("compress/{name}")]
        [HttpPost]
        public ActionResult Compress([FromRoute] string name, IFormFile file)
        {
            try
            {
                if (file.Length > 0)
                {
                    var fileBytes = (dynamic)null;
                    var compressedBytes = (dynamic)null;
                    using (var ms = new MemoryStream())
                    {
                        file.CopyTo(ms);
                        fileBytes = ms.ToArray();
                    }
                    IHuffman h = new ImplementationClass();
                    compressedBytes = Encoding.UTF8.GetBytes(file.FileName + h.Comprimir(Encoding.UTF8.GetString(fileBytes)));
                    double fileCount = Convert.ToDouble(Encoding.UTF8.GetByteCount(Encoding.UTF8.GetString(fileBytes)));
                    double compressedCount = Convert.ToDouble(Encoding.UTF8.GetByteCount(Encoding.UTF8.GetString(compressedBytes)));
                    var newCompression = new Compressions
                    {
                        originalName = file.FileName,
                        compressedName = name + ".huff",
                        path = Environment.CurrentDirectory,
                        ratio = compressedCount / fileCount,
                        factor = fileCount / compressedCount,
                        percentage = Convert.ToString((compressedCount / fileCount) * 100) + "%"
                    };
                    System.IO.File.WriteAllBytes(name + ".huff", compressedBytes);
                    Singleton.Instance.Compressions.Add(newCompression);
                    return Ok("Archivo comprimido en: " + Environment.CurrentDirectory);
                }
                else
                {
                    return BadRequest();
                }
            }
            catch (Exception)
            {
                return new StatusCodeResult(StatusCodes.Status500InternalServerError);
            }
        }

        [Route("decompress")]
        [HttpPost]
        public IActionResult Decompress(IFormFile file)
        {
            try
            {
                if (file.Length > 0)
                {
                    var fileBytes = (dynamic)null;
                    var compressedBytes = (dynamic)null;
                    using (var ms = new MemoryStream())
                    {
                        file.CopyTo(ms);
                        fileBytes = ms.ToArray();
                    }
                    IHuffman h = new ImplementationClass();
                    int found = Encoding.UTF8.GetString(fileBytes).IndexOf(".txt");
                    compressedBytes = Encoding.UTF8.GetBytes(h.Descomprimir(Encoding.UTF8.GetString(fileBytes).Substring(found + 4)));
                    System.IO.File.WriteAllBytes(Encoding.UTF8.GetString(fileBytes).Substring(0, found + 4), compressedBytes);
                    return Ok("Archivo descomprimido en : " + Environment.CurrentDirectory);
                }
                else
                {
                    return BadRequest();
                }
            }
            catch (Exception)
            {
                return new StatusCodeResult(StatusCodes.Status500InternalServerError);
            }
        }

        [Route("compressions")]
        [HttpGet]
        public ActionResult Compressions()
        {
            return Ok(JsonSerializer.Serialize(Singleton.Instance.Compressions));
        }
    }
}
<file_sep>/Models/Data/Singleton.cs
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Lab2.Models.Data
{
    public class Singleton
    {
        private readonly static Singleton _instance = new Singleton();
        public List<Compressions> Compressions { get; set; }

        private Singleton()
        {
            Compressions = new List<Compressions>();
        }

        public static Singleton Instance
        {
            get
            {
                return _instance;
            }
        }
    }
}
<file_sep>/README.md
El laboratorio 3 se encuentra en la branch "Lab3"
<file_sep>/Models/Compressions.cs
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Lab2.Models
{
    public class Compressions
    {
        public string originalName { get; set; }
        public string compressedName { get; set; }
        public string path { get; set; }
        public double ratio { get; set; }
        public double factor { get; set; }
        public string percentage { get; set; }
    }
}
