rewrite everything, need more polishing later