pretty much done; needs some refactoring