/**
* This source code belongs to Moon Zang, the author. To use it for
* commercial/business purpose, please contact DeepNightTwo@gmail.com
*
* @author Moon Zang
*
*/
package costrecord.jdo;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import javax.jdo.PersistenceManager;
public class CostRecordManager {
// private static final Logger log =
// Logger.getLogger(CostRecordManager.class
// .getName());
public static boolean addCostRecord(Long houseID, Long roleID,
CostRoleWeight[] weights, double money, String memo) {
Cost cost = new Cost();
cost.setPayerID(roleID);
cost.setMoneyAmount(money);
cost.setMemo(memo);
cost.setDate(new Date());
cost.setHouseID(houseID);
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(cost);
if (weights != null) {
for (CostRoleWeight weight : weights) {
weight.setCostID(cost.getId());
pm.makePersistent(weight);
}
}
} finally {
pm.close();
}
return true;
}
public static boolean disableRecord(Long recordID) {
PersistenceManager pm = PMF.get().getPersistenceManager();
Cost cost = pm.getObjectById(Cost.class, recordID);
try {
cost.setActive(false);
cost.setOngoing(false);
pm.makePersistent(cost);
} finally {
pm.close();
}
return true;
}
@SuppressWarnings("unchecked")
public static boolean archiveRecord(Long houseID) {
PersistenceManager pm = PMF.get().getPersistenceManager();
String query = "select from " + Cost.class.getName()
+ " where isOngoing == true && isActive == true && houseID == "
+ houseID;
List<Cost> costs = (List<Cost>) pm.newQuery(query).execute();
if (costs == null) {
return true;
}
Date date = new Date();
try {
for (Cost cost : costs) {
cost.setArchivedDate(date);
cost.setOngoing(false);
}
} finally {
pm.close();
}
return true;
}
/**
*
* @param isOngoing
* for history if value is false
* @param isActive
* should always be true
* @return
*/
@SuppressWarnings("unchecked")
public static List<Cost> getAllCost(Long houseID, boolean isOngoing,
boolean isActive) {
PersistenceManager pm = PMF.get().getPersistenceManager();
String query = "select from " + Cost.class.getName()
+ " where isOngoing == " + isOngoing + " && isActive == "
+ isActive + " && houseID == " + houseID;
List<Cost> costs = (List<Cost>) pm.newQuery(query).execute();
if (costs == null) {
costs = new ArrayList<Cost>();
}
return costs;
}
public static List<Cost> getCostWithRole(Long houseID) {
List<Cost> costs = CostRecordManager.getAllCost(houseID, true, true);
for (Cost cost : costs) {
cost.setRole(RoleManager.getRole(cost.getPayerID()));
}
return costs;
}
@SuppressWarnings("unchecked")
public static List<Cost> getCostPaiedByRole(Long houseID, Long roleID) {
PersistenceManager pm = PMF.get().getPersistenceManager();
String query = "select from " + Cost.class.getName()
+ " where isOngoing == true && isActive == true && houseID == "
+ houseID + " && payerID == " + roleID;
List<Cost> costs = (List<Cost>) pm.newQuery(query).execute();
if (costs == null) {
costs = new ArrayList<Cost>();
}
return costs;
}
@SuppressWarnings("unchecked")
public static CostRoleWeight[] getWeigtsForCost(Long costID) {
PersistenceManager pm = PMF.get().getPersistenceManager();
String query = "select from " + CostRoleWeight.class.getName()
+ " where costID == " + costID;
List<CostRoleWeight> weightsForCost = (List<CostRoleWeight>) pm
.newQuery(query).execute();
if (weightsForCost == null) {
return null;
}
CostRoleWeight[] weightsForCostArr = new CostRoleWeight[weightsForCost
.size()];
return weightsForCost.toArray(weightsForCostArr);
}
public static List<String> countCost(List<Cost> costs,
List<CostRecordRole> roles) {
class EveryonePaied {
public CostRecordRole role;
public double money;
public EveryonePaied(CostRecordRole role, double money) {
this.role = role;
this.money = money;
}
}
int roleCount = roles.size();
List<String> costAnalysis = new ArrayList<String>();
List<EveryonePaied> lessPaied = new ArrayList<EveryonePaied>();
List<EveryonePaied> morePaied = new ArrayList<EveryonePaied>();
HashMap<Long, Double> paied = new HashMap<Long, Double>();
HashMap<Long, Double> shouldPay = new HashMap<Long, Double>();
CostRoleWeight[] weightsForAll = new CostRoleWeight[roleCount];
for (int i = 0; i < roleCount; i++) {
CostRecordRole role = roles.get(i);
paied.put(role.getId(), 0.0);
shouldPay.put(role.getId(), 0.0);
weightsForAll[i] = new CostRoleWeight();
weightsForAll[i].setRoleID(role.getId());
weightsForAll[i].setWeight(1);
}
for (Cost cost : costs) {
Long roleID = cost.getRole().getId();
double money = cost.getMoneyAmount();
// add to paid map
Double value = paied.get(roleID);
if (value == null) {
paied.put(roleID, 0.0);
value = 0.0;
}
paied.put(roleID, value + money);
// add to each shouldPay map
CostRoleWeight[] weights = getWeigtsForCost(cost.getId());
if (weights == null || weights.length == 0) {
weights = weightsForAll;
}
double totalWeight = 0;
for (CostRoleWeight weight : weights) {
totalWeight += weight.getWeight();
}
if (totalWeight == 0) {
weights = weightsForAll;
}
for (CostRoleWeight weight : weights) {
double shouldPayCost = weight.getWeight() * money / totalWeight;
Double shouldPayTotalValue = shouldPay.get(weight.getRoleID());
if (shouldPayTotalValue == null) {
shouldPay.put(weight.getRoleID(), 0.0);
shouldPayTotalValue = 0.0;
}
shouldPay.put(weight.getRoleID(), shouldPayTotalValue
+ shouldPayCost);
}
}
for (CostRecordRole role : roles) {
double shouldPayMoney = shouldPay.get(role.getId());
double paidMoney = paied.get(role.getId());
double dist = paidMoney - shouldPayMoney;
if (dist > 0) {
morePaied.add(new EveryonePaied(role, dist));
} else {
lessPaied.add(new EveryonePaied(role, Math.abs(dist)));
}
}
int current = 0;
int max = morePaied.size();
boolean stillToPay = true;
for (EveryonePaied ep : lessPaied) {
double moneyToPay = ep.money;
for (int i = current; (i < max) && stillToPay; i++) {
EveryonePaied more = morePaied.get(i);
if (moneyToPay > more.money) {
current++;
moneyToPay -= more.money;
costAnalysis.add(ep.role.getUserName() + " should pay "
+ formatMoney(more.money) + " to "
+ more.role.getUserName());
} else {
more.money -= moneyToPay;
costAnalysis.add(ep.role.getUserName() + " should pay "
+ formatMoney(moneyToPay) + " to "
+ more.role.getUserName());
}
}
}
return costAnalysis;
}
private static double formatMoney(double money) {
money += 0.005;
return ((int) (money * 100)) / 100.0;
}
}