package pas.huffman;

import java.io.File;
import java.util.HashMap;
import java.util.PriorityQueue;

/**
 * A class that implements a Huffman tree.
 * 
 * From OpenDSA: https://opendsa-server.cs.vt.edu/ODSA/Books/Everything/html/Huffman.html
 */
public class HuffTree {

  private HuffBaseNode root; // The root of the Huffman tree. May be null.
  private HashMap<Byte, Integer> frequencies; // A mapping from bytes to their frequencies.
  private HashMap<Byte, BitSequence> codes; // Maps from bytes to their Huffman codes.

  /**
   * Creates a Huffman tree from a file. Used for zipping an uncompressed file.
   * @param inFile the file to read from
   */
  public HuffTree(File inFile) {

    // UNFINISHED

    // Remember, a constructor should initialize all instance variables.
  }

  /**
   * Creates a Huffman tree from a frequency table. Used for unzipping a compressed file.
   * @param frequencies the frequency table
   */
  public HuffTree(HashMap<Byte, Integer> frequencies) {

    // UNFINISHED

    // Remember, a constructor should initialize all instance variables.
  }

  /**
   * Returns the frequencies of the bytes in the file.
   * @return a HashMap mapping bytes to their frequencies
   */
  public HashMap<Byte, Integer> getFrequencies() {
    return new HashMap<>(frequencies);
  }

  /**
   * Encodes a file using Huffman coding.
   * @param inFile the file to encode
   * @return a BitSequence representing the encoded file
   */
  public BitSequence encode(File inFile) {

    // UNFINISHED

    return null;
  }

  public void decode(BitSequence encoding, File outFile) {

    // UNFINISHED
  }

  private HuffBaseNode buildTree(HashMap<Byte, Integer> frequencies) {
    HuffBaseNode tmp1, tmp2, tmp3 = null;

    PriorityQueue<HuffBaseNode> pq = new PriorityQueue<>();

    for (Byte symbol : frequencies.keySet()) {
      pq.add(new HuffLeafNode(symbol, frequencies.get(symbol)));
    }

    while (pq.size() > 1) { // While two items left
      tmp1 = pq.poll();
      tmp2 = pq.poll();
      tmp3 = new HuffInternalNode(tmp1, tmp2, tmp1.getWeight() + tmp2.getWeight());
      pq.add(tmp3); // Return new tree to heap
    }
    return tmp3; // Return the tree
  }

}
