package com.dev.swms.server.model.inventory;

import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

import com.dev.swms.server.model.base.ItemKey;
import com.dev.swms.server.model.base.Location;
import com.dev.swms.server.model.base.LocationType;
import com.dev.swms.server.model.base.PackageUnit;
import com.dev.swms.server.model.base.WarehouseArea;
import com.dev.swms.server.model.base.Worker;
import com.dev.swms.server.model.receiving.MoveDocDetail;
import com.dev.swms.server.model.shipping.CageInfo;
import com.dev.swms.server.model.shipping.PickTicketDetail;
import com.dev.swms.server.model.shipping.WaveDocDetail;
import com.dev.swms.server.utils.DoubleUtils;
import com.dev.energy.server.exception.BusinessException;
import com.dev.energy.server.model.EntityFactory;
import com.dev.energy.server.model.VersionalEntity;

public class Task extends VersionalEntity {
	private static final long serialVersionUID = 1L;
	/** 任务号 */
	private String code;
	/** 关联发货单明细 */
	private PickTicketDetail pickTicketDetail;
	/** 关联移位单明细 */
	private MoveDocDetail moveDocDetail;
	/** 关联波次明细 */
	private WaveDocDetail waveDocDetail;
	/** 关联库内作业子件明细 */
	private ProcessDocBOMDetail processDocBOMDetail;
	/** 任务类型(收货上架、质检上架、加工上架、退拣上架、移位上架、补货上架、移位下架、质检返还) */
	private String type;
	/** 相关单号 */
	private String billCode;
	/** 操作人员 */
	private Worker worker;
	/** 货品批次属性 */
	private ItemKey itemKey;
	/** 存货日期 */
	private Date storageDate;
	/** 订单日期 */
	private Date orderDate;
	
	/** 所属库区 */
	private WarehouseArea zone;//扣库存仓库
	
	/** 所属库区 */
	private WarehouseArea outZone;
	
	/** SOI */
	private String SOI;
	/** 源库位 */
	private Location srcLoc;
	/** 目标库位 */
	private Location dstLoc;
	/** 源托盘 */
	private Stock srcLP;
	/** 源托盘号 */
	private String srcLPCode;
	/** 目标托盘 */
	private Stock dstLP;
	/** 目标托盘号 */
	private String dstLPCode;
	/** 库存状态码 */
	private String inventoryStatus;
	/** 包装单位 */
	private PackageUnit packageUnit;
	/** 计划移位数量(包装数量) */
	private double planQuantity;
	/** 计划移位数量(MU) */
	private double planQuantityMU;
	/** 实际备货数量(MU) */
	private double bhQuantityMU;
	/** 实际移位数量(MU) */
	private double movedQuantityMU;
	/** 作业日志记录 */
	private Set<TaskLog> logs = new HashSet<TaskLog>();
	/** 创建时间 */
	private Date createTime = new Date();
	/** 发运时间 */
	private Date shipTime;
	/** 任务状态 分为：1.冻结 2.正常 默认为正常状态*/
	private String taskStatus = TaskStatus.NORMAL;
	/** 作业时间 */
	private Date operateTime;
	/** 笼车信息 */
	private CageInfo cageInfo;
	
	private String barCode;//条形码
	
	private double weight;//收货重量
	
	private double volume;//体积
	/**跳过*/
	private int skip;
	/** 备货单号 */
	private String bhCode;
	/** 补货作业人员 */
	private Worker worker1;
	/** 拣货作业人员 */
	private Worker worker2;
	/** 移位作业人员 */
	private Worker worker3;
	/** 作业人员 */
	private Worker worker4;
	private Boolean beBh=Boolean.FALSE;
	
	
	
	public double getBhQuantityMU() {
		return bhQuantityMU;
	}

	public void setBhQuantityMU(double bhQuantityMU) {
		this.bhQuantityMU = bhQuantityMU;
	}

	public Boolean getBeBh() {
		return beBh;
	}

	public void setBeBh(Boolean beBh) {
		this.beBh = beBh;
	}

	public WarehouseArea getOutZone() {
		return outZone;
	}

	public void setOutZone(WarehouseArea outZone) {
		this.outZone = outZone;
	}

	public WarehouseArea getZone() {
		return zone;
	}

	public void setZone(WarehouseArea zone) {
		this.zone = zone;
	}

	public String getBhCode() {
		return bhCode;
	}

	public void setBhCode(String bhCode) {
		this.bhCode = bhCode;
	}

	public Date getShipTime() {
		return shipTime;
	}

	public void setShipTime(Date shipTime) {
		this.shipTime = shipTime;
	}

	public int getSkip() {
		return skip;
	}

	public void setSkip(int skip) {
		this.skip = skip;
	}

	public Worker getWorker1() {
		return worker1;
	}

	public void setWorker1(Worker worker1) {
		this.worker1 = worker1;
	}

	public Worker getWorker2() {
		return worker2;
	}

	public void setWorker2(Worker worker2) {
		this.worker2 = worker2;
	}

	public Worker getWorker3() {
		return worker3;
	}

	public void setWorker3(Worker worker3) {
		this.worker3 = worker3;
	}

	public Worker getWorker4() {
		return worker4;
	}

	public void setWorker4(Worker worker4) {
		this.worker4 = worker4;
	}

	public String getBarCode() {
		return barCode;
	}

	public void setBarCode(String barCode) {
		this.barCode = barCode;
	}

	public double getWeight() {
		return weight;
	}

	public void setWeight(double weight) {
		this.weight = weight;
	}

	public double getVolume() {
		return volume;
	}

	public void setVolume(double volume) {
		this.volume = volume;
	}

	protected Task() {
		super();
	}
	
	public String getSrcLPCode() {
		return srcLPCode;
	}

	public void setSrcLPCode(String srcLPCode) {
		this.srcLPCode = srcLPCode;
	}

	public String getDstLPCode() {
		return dstLPCode;
	}

	public void setDstLPCode(String dstLPCode) {
		this.dstLPCode = dstLPCode;
	}

	public CageInfo getCageInfo() {
		return cageInfo;
	}

	public void setCageInfo(CageInfo cageInfo) {
		this.cageInfo = cageInfo;
	}

	public Date getStorageDate() {
		return storageDate;
	}

	public void setStorageDate(Date storageDate) {
		this.storageDate = storageDate;
	}

	public String getSOI() {
		return SOI;
	}

	public void setSOI(String soi) {
		SOI = soi;
	}

	public String getBillCode() {
		return billCode;
	}

	public void setBillCode(String billCode) {
		this.billCode = billCode;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public Location getDstLoc() {
		return dstLoc;
	}

	public void setDstLoc(Location dstLoc) {
		this.dstLoc = dstLoc;
	}

	public Stock getDstLP() {
		return dstLP;
	}

	public void setDstLP(Stock dstLP) {
		this.dstLP = dstLP;
	}

	public ItemKey getItemKey() {
		return itemKey;
	}

	public void setItemKey(ItemKey itemKey) {
		this.itemKey = itemKey;
	}

	public Set<TaskLog> getLogs() {
		return logs;
	}

	public void setLogs(Set<TaskLog> logs) {
		this.logs = logs;
	}

	public MoveDocDetail getMoveDocDetail() {
		return moveDocDetail;
	}

	public void setMoveDocDetail(MoveDocDetail moveDocDetail) {
		this.moveDocDetail = moveDocDetail;
	}

	public double getPlanQuantityMU() {
		return planQuantityMU;
	}

	public void setPlanQuantityMU(double planQuantityMU) {
		this.planQuantityMU = planQuantityMU;
		if (this.getPackageUnit() != null) {
			if (this.getPackageUnit().getPrecision() == 0) {
				this.setPlanQuantity(Math.ceil(this.planQuantityMU/this.getPackageUnit().getConvertFigure()));
			} else {
				this.setPlanQuantity(DoubleUtils.formatByPrecision(this.planQuantityMU
						/ this.getPackageUnit().getConvertFigure(), this.getPackageUnit().getPrecision()));
			}
		}
	}

	public double getMovedQuantityMU() {
		return movedQuantityMU;
	}

	public void setMovedQuantityMU(double movedQuantityMU) {
		this.movedQuantityMU = movedQuantityMU;
	}

	public PackageUnit getPackageUnit() {
		return packageUnit;
	}

	public void setPackageUnit(PackageUnit packageUnit) {
		this.packageUnit = packageUnit;
	}

	public PickTicketDetail getPickTicketDetail() {
		return pickTicketDetail;
	}

	public void setPickTicketDetail(PickTicketDetail pickTicketDetail) {
		this.pickTicketDetail = pickTicketDetail;
	}

	public double getPlanQuantity() {
		return planQuantity;
	}

	public void setPlanQuantity(double planQuantity) {
		this.planQuantity = planQuantity;
	}

	public Location getSrcLoc() {
		return srcLoc;
	}

	public void setSrcLoc(Location srcLoc) {
		this.srcLoc = srcLoc;
	}

	public Stock getSrcLP() {
		return srcLP;
	}

	public void setSrcLP(Stock srcLP) {
		this.srcLP = srcLP;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getInventoryStatus() {
		return inventoryStatus;
	}

	public void setInventoryStatus(String inventoryStatus) {
		this.inventoryStatus = inventoryStatus;
	}

	public boolean equals(final Object other) {
		if (!(other instanceof Task))
			return false;
		Task castOther = (Task) other;
		return new EqualsBuilder().append(code, castOther.getCode()).isEquals();
	}

	public int hashCode() {
		return new HashCodeBuilder().append(code).toHashCode();
	}

	public boolean canMove(Location dstLocation) {
		if (dstLocation == null || dstLocation.bePutAwayLock()) {
			throw new BusinessException("putaway.destLocation.error");
		}
		if (LocationType.STORAGE.equals(dstLocation.getType())) {
			return true;
		} else {
			throw new BusinessException("putaway.destLocation.error");
		}
	}
	
	/**
	 * @param quantity 基本单位数量
	 */
	public void unallocatePick(double quantity) {
		this.planQuantityMU -= quantity;
		this.planQuantity = DoubleUtils.formatByPrecision(this.planQuantityMU
				/this.packageUnit.getConvertFigure(), this.packageUnit.getPrecision());
		if(this.getPickTicketDetail()!=null){
			this.getPickTicketDetail().unallocate(quantity);
		}
	}

	/**
	 * @param quantity 基本单位数量
	 */
	public void unallocateMove(double quantity) {
		this.planQuantityMU -= quantity;
		this.planQuantity = DoubleUtils.formatByPrecision(this.planQuantityMU
				/this.packageUnit.getConvertFigure(), this.packageUnit.getPrecision());
		if(this.getMoveDocDetail()!=null){
			this.getMoveDocDetail().unallocate(quantity);
		}
	}

	/**
	 * @param quantity 基本单位数量
	 */
	public void unallocateWaveDoc(double quantity){
		this.planQuantityMU -= quantity;
		this.planQuantity = DoubleUtils.formatByPrecision(this.planQuantityMU
				/this.packageUnit.getConvertFigure(), this.packageUnit.getPrecision());
		if(this.getWaveDocDetail()!=null){
			this.getWaveDocDetail().unallocate(quantity);
		}
	}
	
	/**
	 * @param quantity 基本单位数量
	 */
	public void unallocateProcessDoc(double quantity){
		this.planQuantityMU -= quantity;
		this.planQuantity = DoubleUtils.formatByPrecision(this.planQuantityMU
				/this.packageUnit.getConvertFigure(), this.packageUnit.getPrecision());
		if(this.getProcessDocBOMDetail()!=null){
			this.getProcessDocBOMDetail().unallocate(quantity);
		}
	}
	
	/**
	 * 任务移位确认
	 * @param itemKey
	 * @param srcLoc
	 * @param srcLp
	 * @param dstLoc
	 * @param dstLp
	 * @param status
	 * @param storageDate
	 * @param soi
	 * @param unit 移位包装
	 * @param pickedQuantity 包装数量
	 * @param worker
	 */
	public TaskLog pickConfirm(ItemKey itemKey, Location srcLoc, Stock srcLp,
			Location dstLoc, Stock dstLp, String status, Date storageDate, String soi, PackageUnit unit, 
			double pickedQuantity, Worker worker) {
		this.movedQuantityMU += pickedQuantity;//*unit.getConvertFigure();
		TaskLog log=addTaskLog(itemKey, srcLoc, srcLp, dstLoc, 
				dstLp, status, storageDate, soi, unit, pickedQuantity,this.weight, worker, "移位确认");
		int figure=1;//unit.getConvertFigure()
		if(this.getPickTicketDetail() != null){
			this.getPickTicketDetail().pickConfirm(pickedQuantity*figure,weight);
		}
		if(this.getWaveDocDetail() != null){
			this.getWaveDocDetail().pickConfirm(pickedQuantity*figure);
		}
		if(this.getProcessDocBOMDetail() != null){
			this.getProcessDocBOMDetail().pickConfirm(pickedQuantity*figure);
		}
		if(this.getMoveDocDetail() != null) {
			this.getMoveDocDetail().moveTo(pickedQuantity*figure);
		}
		if (this.getOperateTime() == null) {
			this.setOperateTime(new Date());
		}
		return log;
	}
	
	private TaskLog addTaskLog(ItemKey itemKey, Location srcLoc, Stock srcLp, Location dstLoc,
			Stock dstLp, String status, Date storageDate, String soi, PackageUnit packageUnit, 
			double quantity, double weight_log,Worker worker, String description) {
		TaskLog tasklog = EntityFactory.getEntity(TaskLog.class);
		tasklog.setTask(this);
		tasklog.setItemKey(itemKey);
		tasklog.setDstLoc(dstLoc);
		tasklog.setSrcLoc(srcLoc);
		tasklog.setSrcLP(srcLp);
		tasklog.setSrcLPCode(srcLp==null?null:srcLp.getLP());
		tasklog.setDstLP(dstLp);
		tasklog.setDstLPCode(dstLp==null?null:dstLp.getLP());
		tasklog.setInventoryStatus(status);
		tasklog.setStorageDate(storageDate);
		tasklog.setSOI(soi);
		tasklog.setWeight(weight_log);
		tasklog.setBarCode(this.getBarCode());
		tasklog.setPackageUnit(packageUnit);
		tasklog.setMovedQuantity(quantity);
		tasklog.setWorker(worker);
		tasklog.setRecordTime(new Date());
		tasklog.setDescription(description);
		if (this.getLogs() == null) {
			this.setLogs(new HashSet<TaskLog>());
		}
		this.getLogs().add(tasklog);
		return tasklog;
	}

	public WaveDocDetail getWaveDocDetail() {
		return waveDocDetail;
	}

	public void setWaveDocDetail(WaveDocDetail waveDocDetail) {
		this.waveDocDetail = waveDocDetail;
	}

	public ProcessDocBOMDetail getProcessDocBOMDetail() {
		return processDocBOMDetail;
	}

	public void setProcessDocBOMDetail(ProcessDocBOMDetail processDocBOMDetail) {
		this.processDocBOMDetail = processDocBOMDetail;
	}

	public Date getOrderDate() {
		return orderDate;
	}

	public void setOrderDate(Date orderDate) {
		this.orderDate = orderDate;
	}

	public void pickBak(double movedQuantity) {
		this.movedQuantityMU -= movedQuantity;
		this.planQuantityMU -= movedQuantity;
//		if (this.getPackageUnit().getPrecision() > 0) {
//			this.planQuantity -= DoubleUtils.formatByPrecision((this.planQuantityMU-this.movedQuantityMU) 
//					/ this.packageUnit.getConvertFigure(), this.getPackageUnit().getPrecision());
//		} else {
//			this.planQuantity -= Math.floor((this.planQuantityMU-this.movedQuantityMU) 
//					/ this.packageUnit.getConvertFigure());
//		}
		
		this.planQuantity -= Math.floor((this.planQuantityMU-this.movedQuantityMU));
		
		this.getPickTicketDetail().pickBack(movedQuantity);
	}

	public Worker getWorker() {
		return worker;
	}

	public void setWorker(Worker worker) {
		this.worker = worker;
	}
	
	public Map<Integer,String> getLotInfoValue(){
		return itemKey.getLotInfoValue();
	}
	
	public boolean isBeAllowed2ChangePutLoc() {
		return itemKey.getItem().getCompany().isBeAllowed2ChangePutLoc();
	}
	
	public boolean isBeAllowed2ChangePickLoc() {
		return itemKey.getItem().getCompany().isBeAllowed2ChangePickLoc();
	}
	
	public boolean isEmptyPickTicketDetail(){
		return pickTicketDetail == null;
	}
	
	public boolean isEmptyWaveDocDetail(){
		return waveDocDetail == null;
	}
	
	public boolean isWaveWorkModel(){
		return waveDocDetail.isWaveWorkModel();
	}

	public Date getCreateTime() {
		return createTime;
	}

	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}

	public String getTaskStatus() {
		return taskStatus;
	}

	public void setTaskStatus(String taskStatus) {
		this.taskStatus = taskStatus;
	}

	public Date getOperateTime() {
		return operateTime;
	}

	public void setOperateTime(Date operateTime) {
		this.operateTime = operateTime;
	}
}
