Refactored somewhat, not yet tested properly.