package de.rwth.idsg.bikeman.service;
import com.google.common.base.Optional;
import de.rwth.idsg.bikeman.domain.BookedTariff;
import de.rwth.idsg.bikeman.domain.CardAccount;
import de.rwth.idsg.bikeman.domain.CustomerType;
import de.rwth.idsg.bikeman.domain.OperationState;
import de.rwth.idsg.bikeman.domain.TariffType;
import de.rwth.idsg.bikeman.domain.User;
import de.rwth.idsg.bikeman.psinterface.dto.request.CardActivationDTO;
import de.rwth.idsg.bikeman.psinterface.dto.request.CardActivationStatusDTO;
import de.rwth.idsg.bikeman.psinterface.dto.response.CardActivationResponseDTO;
import de.rwth.idsg.bikeman.psinterface.dto.response.CardWriteKeyDTO;
import de.rwth.idsg.bikeman.psinterface.repository.PsiStationRepository;
import de.rwth.idsg.bikeman.repository.CardAccountRepository;
import de.rwth.idsg.bikeman.repository.TariffRepository;
import de.rwth.idsg.bikeman.repository.UserRepository;
import de.rwth.idsg.bikeman.security.SecurityUtils;
import de.rwth.idsg.bikeman.web.rest.dto.modify.CardAccountBaseDTO;
import de.rwth.idsg.bikeman.web.rest.dto.modify.CreateCardAccountBatchDTO;
import de.rwth.idsg.bikeman.web.rest.dto.modify.CreateEditCardAccountDTO;
import de.rwth.idsg.bikeman.web.rest.dto.view.ViewCardAccountDTO;
import de.rwth.idsg.bikeman.web.rest.exception.DatabaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.joda.time.LocalDateTime;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
/**
* Created by swam on 20/10/14.
*/
@Service
@Slf4j
public class CardAccountService {
@Inject private CardAccountRepository cardAccountRepository;
@Inject private UserRepository userRepository;
@Inject private TariffRepository tariffRepository;
@Inject private PsiStationRepository stationRepository;
@Transactional(readOnly = true)
public Optional<CardActivationResponseDTO> activateCardAccount(CardActivationDTO cardActivationDTO) {
CardAccount cardAccount = cardAccountRepository.findByActivationKey(cardActivationDTO.getActivationKey());
if (cardAccount == null) {
return Optional.absent();
}
cardAccount.setOperationState(OperationState.INOPERATIVE);
cardAccount.setActivationKey(null);
cardAccount.setCardPin(cardActivationDTO.getCardPin());
cardAccountRepository.save(cardAccount);
CardWriteKeyDTO keys = stationRepository.getCardWriteKey();
CardActivationResponseDTO dto = CardActivationResponseDTO.builder()
.cardId(cardAccount.getCardId())
.readKey(keys.getReadKey())
.writeKey(keys.getWriteKey())
.applicationKey(keys.getApplicationKey())
.initialApplicationKey(keys.getInitialApplicationKey())
.build();
return Optional.of(dto);
}
public void setCardOperative(CardActivationStatusDTO dto) {
if (dto.isSuccessfulActivation()) {
cardAccountRepository.setOperationStateForCardId(OperationState.OPERATIVE, dto.getCardId());
} else {
// TODO: We should probably raise an exception, or notice somebody instead
log.warn("The cardId '{}' could not be activated", dto.getCardId());
}
}
@Transactional(readOnly = true)
public List<ViewCardAccountDTO> getCardAccountDTOsOfCurrentUser() {
String userLogin = SecurityUtils.getCurrentLogin();
List<CardAccount> cardAccountList = cardAccountRepository.findByUserLogin(userLogin);
List<ViewCardAccountDTO> viewCardAccountDTOList = new ArrayList<>();
for (CardAccount cardAccount : cardAccountList) {
viewCardAccountDTOList.add(this.convertCardAccount(cardAccount));
}
return viewCardAccountDTOList;
}
@Transactional(readOnly = true)
public List<CardAccount> getCardAccountsOfCurrentUser() {
String userLogin = SecurityUtils.getCurrentLogin();
return cardAccountRepository.findByUserLogin(userLogin);
}
@Transactional
public void createCardAccount(CreateEditCardAccountDTO createEditCardAccountDTO) throws DatabaseException {
createCardAccount(createEditCardAccountDTO.getLogin(), createEditCardAccountDTO.getTariff(), createEditCardAccountDTO.getCardId(), createEditCardAccountDTO.getCardPin());
}
@Transactional
public void createCardAccountWithBatch(CreateCardAccountBatchDTO createCardAccountBatchDTO) {
for (CardAccountBaseDTO cardAccount : createCardAccountBatchDTO.getCardAccountBatch()) {
createCardAccount(createCardAccountBatchDTO.getLogin(), createCardAccountBatchDTO.getTariff(), cardAccount.getCardId(), cardAccount.getCardPin());
}
}
private void createCardAccount(String login, TariffType tariffType, String cardId, String cardPin) {
User user = checkAndGetUser(login);
BookedTariff bookedTariff = getBookedTariff(tariffType);
CardAccount cardAccount = new CardAccount();
cardAccount.setCardId(cardId);
cardAccount.setCardPin(cardPin);
cardAccount.setActivationKey(RandomStringUtils.randomNumeric(12));
cardAccount.setOperationState(OperationState.OPERATIVE);
cardAccount.setOwnerType(CustomerType.MAJOR_CUSTOMER);
cardAccount.setUser(user);
cardAccount.setCurrentTariff(bookedTariff);
try {
cardAccountRepository.save(cardAccount);
} catch (Throwable e) {
throw new DatabaseException("CardId already exists.");
}
}
private BookedTariff getBookedTariff(TariffType tariffType) {
BookedTariff bookedTariff = new BookedTariff();
bookedTariff.setTariff(tariffRepository.findByName(tariffType));
bookedTariff.setBookedFrom(LocalDateTime.now());
// set the bookedUntil date to null, if no subscription term is declared
if (tariffRepository.findByName(tariffType).getTerm() == null) {
bookedTariff.setBookedUntil(null);
} else {
bookedTariff.setBookedUntil(new LocalDateTime().plusDays(
tariffRepository.findByName(tariffType).getTerm()
));
}
return bookedTariff;
}
private User checkAndGetUser(String login) {
User user;// when no login exists, add to current user
if (login == null) {
user = userRepository.findByLoginIgnoreCase(SecurityUtils.getCurrentLogin());
} else {
user = userRepository.findByLoginIgnoreCase(login);
}
return user;
}
private ViewCardAccountDTO convertCardAccount(CardAccount cardAccount) {
return ViewCardAccountDTO.builder()
.cardId(cardAccount.getCardId())
.cardPin(cardAccount.getCardPin())
.inTransaction(cardAccount.getInTransaction())
.operationState(cardAccount.getOperationState())
.build();
}
}