needs a ton of refactoring but it almost works