package shiping;
import java.io.IOException;
import java.util.*;
import databean.Cost;
import databean.FulfilledOrder;
import databean.Order;
import databean.Stock;
import output.FufilledOrderWriter;
import output.UnfulfilledOrderWriter;
import input.CostReader;
import input.OrderReader;
import input.StockReader;
public class Shipping {
private static final String LAST_CALL = "LAST_CALL";
/**
* Entry point for Shipping
* @param orderEntryStreamIn stream of incoming new orders
* @param shippingCostsIn a stream of shipping costs
* @param StockReader a stream of inventory for each region ??????
* @param orderShipmentStreamOut a stream to output completed shipments
* @param lockerShipmentStreamOut a stream to output completed locker shipments
* @param unfulfilledOrderEntryStreamOut a stream to output unfulfilled orders
* @throws IOException
*/
public void shipping(OrderReader orderReader, StockReader stockReader,
CostReader costReader, FufilledOrderWriter fufilledOrderWriter,
UnfulfilledOrderWriter unfulfilledOrderWriter)throws IOException{
//把所有的库存Stock 对象 (在java data bean里)先存到Map里
//(why Map?) 因为map是key value结构 所以可以吧 储存 (key- item id,
//value -item Object 的List!!)
//why hashtable ? Hashtable is synchronized
//
Map<String, List<Stock>> inventories = new Hashtable<String, List<Stock>>();
while(stockReader.hasnext()){
Stock inventory=stockReader.next();
if(inventories.containsKey(inventory.getItemId())){
//key -item id ,value 是stock object的list
inventories.get(inventory.getItemId()).add(inventory);
}else{
List<Stock> list=new LinkedList<Stock>();
list.add(inventory);
inventories.put(inventory.getItemId(), list);
}
}
//把所有的Cost对象 存在一个新的map里
//eg 东到西多少cost 中到西 多少cost
//依旧是key-value 结构 key是 destination value是一个list
//比如 key是 东,东这个key对应的list就会储存从所有 从cost文档里读出来的
// cost信息--which destination is 东
Map<String,List<Cost>> costs=new Hashtable<String,List<Cost>>();
while(costReader.hasnext()){
Cost cost=costReader.next();
if (costs.containsKey(cost.getTo())) {
costs.get(cost.getTo()).add(cost);
}else{
List<Cost> list=new LinkedList<Cost>();
list.add(cost);
costs.put(cost.getTo(), list);
}
//下面这段代码是干嘛的呢 就是说 在cost file里 只有东 到 西 2天 15刀
//但是实际上 西到东 2天也是15刀 也要把这个信息存到map里
if(cost.getFrom().equals(cost.getTo())){
continue;
}else{
Cost costReverse= new Cost();
costReverse.setFrom(cost.getTo());
costReverse.setTo(cost.getFrom());
costReverse.setCost(cost.getCost());
costReverse.setTime(cost.getTime());
if(costs.containsKey(costReverse.getTo())){
costs.get(costReverse.getTo()).add(costReverse);
}else{
List<Cost> list =new LinkedList<Cost>();
list.add(costReverse);
costs.put(costReverse.getTo(), list);
}
}
// Get the orders of each day and sort them by quantity to ensure we can deliver as many orders as possible
// 先fulfill小订单 再fulfill大订单 这样可以在有限的库存情况下 fulfill经量多的order
//在order的文档里 一个order可以有多个 item 但是一条order记录只有一个item
//eg: order number 001 item number 34 quantity 5
// order number 001 item number 66 quantity 1
while(orderReader.hasnext()){
//返回一天的order
List<Order> orders=getOrderByDay(orderReader);
// 把一天的order从小到大sort
Collections.sort(orders,new SortOrderByQuantity());
//每次while循环跑一次 就是可以处理 当天的orders
//现在 开始一个个遍历一天的orders 来处理当天的所有order
for(Order order:orders){
if(order.getOrderId().equals(LAST_CALL)){
//处理locker 这个版本的题里没有 但是shiya有
// continue
}
//To check if we have enough product in warehouse
int totoalInventory=0;
//输出没库存 不能fulfill的order
if(!inventories.containsKey(order.getItemId())){
unfulfilledOrderWriter.write(order);
continue;
}
//inveotories 是key:item value: List<Stock> 所以这里遍历的是每个product的stock list
for(Stock stock:inventories.get(order.getItemId())){
totoalInventory+=stock.getQuantity(); //是一个item的total quantity
}
//如果这一个order已经比总库存大了 那么当然没法fulfill
if(order.getQuantity()>totoalInventory){
unfulfilledOrderWriter.write(order);
}else{//可以fulfill的order 那就把order转化成 fulfilled order
// 当然 需要计算出 cost 和从那个仓库发货 和需要几天
int itemToShip=order.getQuantity();
// 计算cost
List<Cost> shipCostList=costs.get(order.getTo());
List<Cost> onTimeship=getOnTimeShipping(shipCostList, order.getTimeRequirement());
//检查是否有onTimeship
if(onTimeship.size()>0){
FulfilledOrder fulfilledOrder=new FulfilledOrder();
fulfilledOrder.setCost(onTimeship.get(0).getCost()*itemToShip); //获取最便宜的复合要求的cost
fulfilledOrder.setDeliverTime(onTimeship.get(0).getTime());
fulfilledOrder.setFrom(onTimeship.get(0).getFrom());
fulfilledOrder.setItemId(order.getItemId());
fulfilledOrder.setOrderId(order.getOrderId());
fulfilledOrder.setQuantity(order.getQuantity());
fulfilledOrder.setTimeRequirement(order.getTimeRequirement());
fulfilledOrder.setTo(order.getTo());
fufilledOrderWriter.write(fulfilledOrder);
//已经送出了 要去对应送出仓库减库存
List<Stock> delivered=inventories.get(order.getItemId());
for(Stock stock:delivered){
if(stock.getLocation().equals(onTimeship.get(0).getFrom())){
stock.setQuantity(stock.getQuantity()-order.getQuantity());
}
break;
}
}else{ //你能走到这个if块 也是说明 有库存的 所以此时 就算没有onTimeShip 也要送
List<Cost> delayedship=getDelayedShipping(shipCostList);
if(delayedship.size()>0){
FulfilledOrder fulfilledOrder=new FulfilledOrder();
fulfilledOrder.setCost(delayedship.get(0).getCost()*itemToShip); //获取最便宜的复合要求的cost
fulfilledOrder.setDeliverTime(delayedship.get(0).getTime());
fulfilledOrder.setFrom(delayedship.get(0).getFrom());
fulfilledOrder.setItemId(order.getItemId());
fulfilledOrder.setOrderId(order.getOrderId());
fulfilledOrder.setQuantity(order.getQuantity());
fulfilledOrder.setTimeRequirement(order.getTimeRequirement());
fulfilledOrder.setTo(order.getTo());
fufilledOrderWriter.write(fulfilledOrder);
List<Stock> delivered=inventories.get(order.getItemId());
for(Stock stock:delivered){
if(stock.getLocation().equals(delayedship.get(0).getFrom())){
stock.setQuantity(stock.getQuantity()-order.getQuantity());
}
break;
}
}else{ // 如果能到这一块 说明 没有合适的运输方式 送不了
unfulfilledOrderWriter.write(order);
}
}
// 如果是需要locker的 就可以通过 destination 来判断
}
}
}}
}
//从order reader里读一天的 order 碰到last call就断掉 这样orders里正好是一天
private static List<Order> getOrderByDay (OrderReader orderReader) {
List<Order> orders = new ArrayList<Order>();
while (orderReader.hasnext()) {
Order currrentOrder = orderReader.next();
orders.add(currrentOrder);
if (currrentOrder.getOrderId().equals(LAST_CALL)) {
break;
}
}
return orders;
}
//输入的参数 :符合To的所有cost object
//输出的参数 :在里面符合 ship requirment day 的cost list,按运费从小到大排序
private static List<Cost> getOnTimeShipping(List<Cost> costs,int requiredDays){
List<Cost> list=new ArrayList<Cost>();
for(Cost cost:costs){
if(cost.getTime()<=requiredDays){
list.add(cost);
}
}
// 然后在符合条件的cost里按照运费价格从小到大
Collections.sort(list, new SortCostByCost());
return list;
}
private static List<Cost> getDelayedShipping(List<Cost> costs){
// 先选时间短的 相同天数下 选价钱低的
Collections.sort(costs, new SortCostByDateCost());
return costs;
}
private static final class SortOrderByQuantity implements Comparator<Order>{
@Override
public int compare(Order o1, Order o2) {
return o1.getQuantity()-o2.getQuantity();
}
}
private static final class SortCostByCost implements Comparator<Cost>{
@Override
public int compare(Cost o1, Cost o2) {
// TODO Auto-generated method stub
return o1.getCost()-o2.getCost();
}
}
private static final class SortCostByDateCost implements Comparator<Cost>{
@Override
public int compare(Cost o1, Cost o2) {
if(o1.getTime()-o2.getTime()==0){
return o1.getCost()-o2.getCost();
}else{
return o1.getTime()-o2.getTime();
}
}
}
}