This function is pretty big.