Complete rewrite, much nicer API