lots of refactor, too long to describe :)