First version. It works, but needs improvements (and unit testing).