#!/usr/bin/ruby

func walk(n, s, h) {
    n.exists('a') && (
        h{n{'a'}} = s;
        say "#{n{'a'}}: #{s}";
        return();
    );
    walk(n{'0'}, s+'0', h);
    walk(n{'1'}, s+'1', h);
}

func make_tree(text) {
    var letters = Hash.new;
    text.each { |c| letters{c} \\= 0 ++ };
    var nodes = letters.keys.map { |l|
            Hash.new('a' => l, 'freq' => letters{l})
    };

    var n = Hash.new;
    while (nodes.sort!{|a,b| a{'freq'} <=> b{'freq'} }.len > 1) {
        n = Hash.new('0' => nodes.shift, '1' => nodes.shift);
        n{'freq'} = (n{'0'}{'freq'} + n{'1'}{'freq'});
        nodes.append(n);
    }

    walk(n, '', n{'tree'} = Hash.new);
    return n;
}

func encode(s, t) {
    t = t{'tree'};
    s.split(1).join('' => {|c| t{c}});
}

func decode (enc, tree) {
    var n = tree;
    var out = '';

    enc.each {|bit|
        n = n{bit};
        n.has_key('a') && (
            out += n{'a'}; n = tree;
        );
    };

    return out;
}

var text = "this is an example for huffman encoding";
var tree = make_tree(text);
var enc = encode(text, tree);

say enc;
say decode(enc, tree);
