package carpool.dbservice;
import java.util.*;
import javax.swing.text.DateFormatter;
import carpool.carpoolDAO.CarpoolDaoMessage;
import carpool.carpoolDAO.CarpoolDaoTransaction;
import carpool.carpoolDAO.CarpoolDaoUser;
import carpool.common.*;
import carpool.configurations.EnumConfig;
import carpool.exception.PseudoException;
import carpool.exception.validation.ValidationException;
import carpool.exception.location.LocationNotFoundException;
import carpool.exception.message.MessageNotFoundException;
import carpool.exception.message.MessageOwnerNotMatchException;
import carpool.exception.transaction.TransactionAccessViolationException;
import carpool.exception.transaction.TransactionNotFoundException;
import carpool.exception.transaction.TransactionOwnerNotMatchException;
import carpool.exception.transaction.TransactionStateViolationException;
import carpool.exception.user.UserNotFoundException;
import carpool.exception.validation.ValidationException;
import carpool.model.*;
public class TransactionDaoService{
/**
* get all the transactions from database
* @throws LocationNotFoundException
*/
public static ArrayList<Transaction> getAllTransactions() throws TransactionNotFoundException, UserNotFoundException, MessageNotFoundException, LocationNotFoundException {
return CarpoolDaoTransaction.getAllTranscations();
}
/**
* get the full transaction by id
* @param transactionId
* @return the full transaction object constructed by the full constructor, return null if any error occurs
* @throws LocationNotFoundException
*/
private static Transaction getTransactionById(int transactionId) throws TransactionNotFoundException, UserNotFoundException, MessageNotFoundException, LocationNotFoundException {
return CarpoolDaoTransaction.getTransactionById(transactionId);
}
/**
* get the transaction by id from API call, adding safety by checking userId ownership, since detailed transactions should be viewed by provider or customer only
* @throws LocationNotFoundException
*/
public static Transaction getUserTransactionById(int transactionId, int userId) throws TransactionNotFoundException, TransactionOwnerNotMatchException, UserNotFoundException, MessageNotFoundException, LocationNotFoundException{
Transaction transaction = getTransactionById(transactionId);
if (transaction.getProviderId() != userId && transaction.getCustomerId() != userId){
throw new TransactionOwnerNotMatchException();
}
return transaction;
}
/**
* created a new Transaction in SQL
* @return the full Transaction that was just created in database, use the complete constructor for this, including provider, customer, message
* @throws ValidationException
* @throws LocationNotFoundException
*/
public static Transaction createNewTransaction(Transaction newTransaction) throws MessageNotFoundException, UserNotFoundException, ValidationException, LocationNotFoundException{
Transaction t = newTransaction;
Message base = CarpoolDaoMessage.getMessageById(t.getMessageId());
if (t.getType() == EnumConfig.TransactionType.departure){
base.setDeparture_seatsBooked(base.getDeparture_seatsBooked() + t.getDeparture_seatsBooked());
} else{
base.setArrival_seatsBooked(base.getArrival_seatsBooked() + t.getDeparture_seatsBooked());
}
if (base.getDeparture_seatsBooked() > base.getDeparture_seatsNumber() || base.getArrival_seatsBooked() > base.getArrival_seatsNumber()){
throw new ValidationException("交易发起失败,没有那么多空余位置");
}
t = CarpoolDaoTransaction.addTransactionToDatabase(newTransaction);
CarpoolDaoMessage.UpdateMessageInDatabase(base);
//currently transactions are customer -> provider only
Notification n = new Notification(EnumConfig.NotificationEvent.transactionInit, newTransaction.getProviderId(), t.getCustomerId(), t.getMessageId(), t.getTransactionId());
NotificationDaoService.sendNotification(n);
return t;
}
/**
* provider or customer cancels the transaction, changing the state of the transaction from confirm to cancelled
* Expected Condition: current Transaction state in "Constants -> transactonState.init" && userId matches either providerId or messageId
* Action: change state to cancelled, TODO: send notifications, and prompt for explanation
* @throws LocationNotFoundException
*/
public static Transaction cancelTransaction(int transactionId, int userId) throws TransactionNotFoundException, TransactionOwnerNotMatchException, TransactionStateViolationException, MessageNotFoundException, UserNotFoundException, ValidationException, LocationNotFoundException{
Transaction t = CarpoolDaoTransaction.getTransactionById(transactionId);
if(t.getProviderId() == userId || t.getCustomerId() == userId){
if(t.getState() != EnumConfig.TransactionState.init){
throw new TransactionStateViolationException(t.getState(), EnumConfig.TransactionState.init);
}
Message base = CarpoolDaoMessage.getMessageById(t.getMessageId());
if (t.getType() == EnumConfig.TransactionType.departure){
base.setDeparture_seatsBooked(base.getDeparture_seatsBooked() - t.getDeparture_seatsBooked());
} else{
base.setArrival_seatsBooked(base.getArrival_seatsBooked() - t.getDeparture_seatsBooked());
}
if (base.getDeparture_seatsBooked() < 0 || base.getArrival_seatsBooked() < 0){
throw new ValidationException("交易取消失败,涉及座位数不匹配");
}
t.setState(EnumConfig.TransactionState.cancelled);
CarpoolDaoTransaction.updateTransactionInDatabase(t);
CarpoolDaoMessage.UpdateMessageInDatabase(base);
//send notifications
ArrayList<Notification> ns = new ArrayList<Notification>();
ns.add(new Notification(EnumConfig.NotificationEvent.transactionCancelled, t.getProviderId(), t.getCustomerId(), t.getMessageId(), t.getTransactionId()));
ns.add(new Notification(EnumConfig.NotificationEvent.transactionCancelled, t.getCustomerId(), t.getProviderId(), t.getMessageId(), t.getTransactionId()));
NotificationDaoService.sendNotification(ns);
}else{
throw new TransactionOwnerNotMatchException();
}
return t;
}
/**
* TODO send notifications
* initUser or targetUser reports the transaction for investigation, changing the state of the transaction from finishedToEvaluate to underInvestigation
* Expected Condition: current Transaction state in "Constants -> transactonState.finishedToEvaluate" && userId matches either initUser or targetUser
* Action: change the transactionState finishedToEvaluate -> underInvestigation
* @throws LocationNotFoundException
*/
public static Transaction reportTransaction(int transactionId, int userId) throws TransactionNotFoundException, TransactionOwnerNotMatchException, TransactionStateViolationException, UserNotFoundException, MessageNotFoundException, LocationNotFoundException{
Transaction t = CarpoolDaoTransaction.getTransactionById(transactionId);
if(t.getProviderId() == userId || t.getCustomerId() == userId){
if(t.getState() != EnumConfig.TransactionState.finished){
throw new TransactionStateViolationException(t.getState(), EnumConfig.TransactionState.finished);
}else{
t.setState(EnumConfig.TransactionState.underInvestigation);
CarpoolDaoTransaction.updateTransactionInDatabase(t);
//send notifications
ArrayList<Notification> ns = new ArrayList<Notification>();
ns.add(new Notification(EnumConfig.NotificationEvent.transactionCancelled, t.getProviderId(), t.getCustomerId(), t.getMessageId(), t.getTransactionId()));
ns.add(new Notification(EnumConfig.NotificationEvent.transactionCancelled, t.getCustomerId(), t.getProviderId(), t.getMessageId(), t.getTransactionId()));
NotificationDaoService.sendNotification(ns);
}
}else{
throw new TransactionOwnerNotMatchException();
}
return t;
}
private static void updateUserScore(User user, int score){
user.setAverageScore(Math.round((user.getAverageScore() * user.getTotalTranscations() + score) / user.getTotalTranscations()));
}
/**
* initUser or targetUser evaluates the transaction, given the transaction is in finished state
* @return the changed transaction, constructed by the full constructor
* @throws LocationNotFoundException
*/
public static Transaction evaluateTransaction(int transactionId, int userId, int score) throws TransactionNotFoundException, TransactionOwnerNotMatchException, TransactionAccessViolationException, TransactionStateViolationException, MessageNotFoundException, UserNotFoundException, ValidationException, LocationNotFoundException{
Transaction t = CarpoolDaoTransaction.getTransactionById(transactionId);
if(t.getState() != EnumConfig.TransactionState.finished){
throw new TransactionStateViolationException(t.getState(), EnumConfig.TransactionState.finished);
}else{
try {
if(userId == t.getProviderId()){
//check if the user has already evaluated
if(t.getProviderEvaluation() != 0){
throw new TransactionAccessViolationException();
}
t.setProviderEvaluation(score);
User customer = CarpoolDaoUser.getUserById(t.getCustomerId());
updateUserScore(customer, score);
CarpoolDaoTransaction.updateTransactionInDatabase(t);
CarpoolDaoUser.UpdateUserInDatabase(customer);
}else if(userId == t.getCustomerId()){
if(t.getCustomerEvaluation() != 0){
throw new TransactionAccessViolationException();
}
t.setCustomerEvaluation(score);
User provider = CarpoolDaoUser.getUserById(t.getProviderId());
updateUserScore(provider, score);
CarpoolDaoTransaction.updateTransactionInDatabase(t);
CarpoolDaoUser.UpdateUserInDatabase(provider);
}else{
throw new TransactionOwnerNotMatchException();
}
ArrayList<Notification> ns = new ArrayList<Notification>();
ns.add(new Notification(EnumConfig.NotificationEvent.transactionCancelled, t.getProviderId(), t.getCustomerId(), t.getMessageId(), t.getTransactionId()));
ns.add(new Notification(EnumConfig.NotificationEvent.transactionCancelled, t.getCustomerId(), t.getProviderId(), t.getMessageId(), t.getTransactionId()));
NotificationDaoService.sendNotification(ns);
} catch (UserNotFoundException e) {
e.printStackTrace();
throw new TransactionOwnerNotMatchException();
}
}
return t;
}
public static ArrayList<Transaction> sortTransactions(ArrayList<Transaction> tlist){
Collections.sort(tlist, new Comparator<Transaction>() {
@Override public int compare(final Transaction t1, final Transaction t2) {
return DateUtility.toSQLDateTime(t1.getMessage().getDeparture_time()).compareTo(DateUtility.toSQLDateTime(t2.getMessage().getDeparture_time()));
}
});
return tlist;
}
//
// /**
// * TODO (admin?) deletes the transaction from database (for testing and admin use only)
// * first retrieve the transaction from db using the given transaction id
// * decrement both initUser and targetUsers' total transaction number
// * if not found, throw TransactionNotFoundException
// * then check if the retrieved transaction's initUserId or targetUserId matches userId parameter, if not, throw TransactionOwnerNotMatchException
// * @param transactionId
// * @param userId
// * @return true if transaction exists and deleted
// * @throws PseudoException
// */
// public static boolean deleteTransaction(int transactionId, int userId) throws PseudoException{
// Transaction t = DaoTransaction.getTransactionById(transactionId);
// try {
// User initUser = UserDaoService.getUserById(t.getInitUserId());
// User targetUser = UserDaoService.getUserById(t.getTargetUserId());
// if(initUser.getUserId()==userId || targetUser.getUserId()==userId){
// //only finished transactions can be deleted
// if(t.getState()!=Constants.transactionState.success && t.getState()!=Constants.transactionState.success_initUserEvaluated && t.getState()!=Constants.transactionState.success_noEvaluation && t.getState()!=Constants.transactionState.success_targetUserEvaluated){
// throw new TransactionStateViolationException(t.getState(), Constants.transactionState.success);
// }else{
// initUser.setTotalTranscations(initUser.getTotalTranscations()-1);
// targetUser.setTotalTranscations(targetUser.getTotalTranscations()-1);
// DaoTransaction.deleteTransactionFromDatabase(transactionId);
// UserDaoService.updateUser(initUser);
// UserDaoService.updateUser(targetUser);
// }
// }else{
// throw new TransactionOwnerNotMatchException();
// }
// } catch (UserNotFoundException e) {
// e.printStackTrace();
// }
// return true;
// }
//
//
// /**TODO API
// * admin found a problem with a transaction, and moving it to cancelled
// * Expected Condition: current Transaction state in "Constants -> transactonState.underInvestigation"
// * Action: change the transactionState underInvestigation -> cancelled
// * @param transactionId
// * @return the changed transaction, constructed by the full constructor
// * @throws TransactionNotFoundException throw if the transaction is not found in the first place
// * @throws TransactionStateViolationException(currentState, expected state) throw if the current state of the transaction is not "underInvestigation"
// */
// public static Transaction investigationCancelTransaction(int transactionId) throws TransactionNotFoundException, TransactionStateViolationException{
// Transaction t = DaoTransaction.getTransactionById(transactionId);
// if(t.getState()==Constants.transactionState.underInvestigation){
// t.setState(Constants.transactionState.cancelled);
// DaoTransaction.UpdateTransactionInDatabase(t);
// }else{
// throw new TransactionStateViolationException(t.getState(), Constants.transactionState.underInvestigation);
// }
// return t;
// }
//
// /**TODO API
// * admin did not find a problem with a transaction, and moving it to back to finishedToEvaluated
// * Expected Condition: current Transaction state in "Constants -> transactonState.underInvestigation"
// * Action: change the transactionState underInvestigation -> finishedToEvaluate
// * @param transactionId
// * @param userId
// * @return the changed transaction, constructed by the full constructor
// * @throws TransactionNotFoundException throw if the transaction is not found in the first place
// * @throws TransactionStateViolationException(currentState, expected state) throw if the current state of the transaction is not "underInvestigation"
// */
// public static Transaction investigationReleaseTransaction(int transactionId) throws TransactionNotFoundException, TransactionStateViolationException{
// Transaction t = DaoTransaction.getTransactionById(transactionId);
// if(t.getState()==Constants.transactionState.underInvestigation){
// t.setState(Constants.transactionState.finishedToEvaluate);
// DaoTransaction.UpdateTransactionInDatabase(t);
// // send Transaction released notification
// Notification n = new Notification(-1, Constants.notificationType.on_transaction, Constants.notificationEvent.transactionReleased,
// 0, "", 0, t.getTransactionId(),t.getInitUserId(),
// "Your transaction XXX has been released", DateUtility.getCurTimeInstance(), false, false);
// NotificationDaoService.createNewNotification(n);
// n.setTargetUserId(t.getTargetUserId());
// NotificationDaoService.createNewNotification(n);
// }else{
// throw new TransactionStateViolationException(t.getState(), Constants.transactionState.underInvestigation);
// }
// return t;
// }
}