Code is long but works.