I think this is working completely, but need to check some corner cases.