class CreateAccountHandler implements ContextualRequestMessageHandler<Account> {

   @Override
   public MessageBody handleStaticRequest(PlatformMessage msg) {
      MessageBody request = msg.getValue();
      
      String email = CreateAccountRequest.getEmail(request);
      String password = CreateAccountRequest.getPassword(request);
      Boolean optin = Boolean.parseBoolean(CreateAccountRequest.getOptin(request));
      Map<String, Object> personAttributes = CreateAccountRequest.getPerson(request);
      Map<String, Object> placeAttributes = CreateAccountRequest.getPlace(request);

      if (Strings.isNullOrEmpty(email)) {
         throw new ErrorEventException(Errors.fromCode(ARGUMENT_ERROR, MISSING_EMAIL));
      }

      // FIXME:  check password and return an error event if it does not match requirements.  need
      // to have password checking algorithm in place first
      if (Strings.isNullOrEmpty(password)) {
         throw new ErrorEventException(Errors.fromCode(ARGUMENT_ERROR, MISSING_PASSWORD));
      }
      
      validatePersonAttributes(personAttributes);
      validatePlaceAttributes(placeAttributes);

      UUID placeId = UUID.randomUUID();
      UUID accountId= UUID.randomUUID();

      Person person = new Person();
      person.setAccountId(accountId);
      person.setCurrPlace(placeId);
      person.setEmail(email);
      person.setPrivacyPolicyAgreed(new Date());
      person.setTermsAgreed(new Date());
      person.setHasLogin(true);
      person.setOwner(true);
      if (optin) {
         person.setConsentOffersPromotions(new Date());
      }
      if(personAttributes != null && !personAttributes.isEmpty()) {
         personTransformer.merge(person, personAttributes);
      }

      try {
         person = personDao.create(person, password);
      }
      catch(EmailInUseException e) {
         throw new ErrorEventException( Errors.fromCode(EMAIL_IN_USE_ERROR_CODE, EMAIL_IN_USE_ERROR_MSG) );
      }

      boolean succeeded = false;
      Account account = null;
      Place place = null;
      try {
         account = new Account();
         account.setId(accountId);
         account.setState(Account.AccountState.SIGN_UP_1);
         account.setBillable(true);

         Set<UUID> placeIDs = new HashSet<>();
         placeIDs.add(placeId);
         account.setPlaceIDs(placeIDs);
         account.setOwner(person.getId());
         account = accountDao.create(account);

         place = new Place();
         place.setId(placeId);
         place.setName(DEFAULT_PLACE_HOME);
         if(placeAttributes != null && !placeAttributes.isEmpty()) {
            timezoneHelper.processTimeZoneChanges(placeAttributes);
            placeTransformer.merge(place, placeAttributes);            
         }
         place.setServiceLevel(ServiceLevel.fromString(defaultServiceLevel));
         place.setAccount(account.getId());
         place.setPrimary(true);
         place = placeDao.create(place);

         AuthorizationGrant defaultGrant = new AuthorizationGrant();
         defaultGrant.setAccountId(account.getId());
         defaultGrant.setAccountOwner(true);
         defaultGrant.setEntityId(person.getId());
         defaultGrant.setPlaceId(place.getId());
         defaultGrant.setPlaceName(place.getName());
         defaultGrant.addPermissions("*:*:*");

         grantDao.save(defaultGrant);
         emitEvent(account, place);
         succeeded = true;
      }
      finally {
         if(!succeeded) {
            personDao.delete(person);
            if(place != null && place.isPersisted()) {
               placeDao.delete(place);
            }
            if(account != null && account.isPersisted()) {
               accountDao.delete(account);
            }
         }
      }

      Map<String,Object> response = new HashMap<>();
      response.put(ACCOUNT_RET, accountTransformer.transform(account));
      response.put(PERSON_RET, personTransformer.transform(person));
      response.put(PLACE_RET, placeTransformer.transform(place));
      return MessageBody.buildResponse(request, response);
   }

   @Inject public  CreateAccountHandler(
         AccountDAO accountDao,
         PersonDAO personDao,
         PlaceDAO placeDao,
         AuthorizationGrantDAO grantDao,
         BeanAttributesTransformer<Account> accountTransformer,
         BeanAttributesTransformer<Person> personTransformer,
         BeanAttributesTransformer<Place> placeTransformer,
         PlatformMessageBus bus,
         TimezonesManager timezonesMgr);

}