huge internal rewrite, lots of cleanup and added tests (fixes #1)