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

import java.lang.reflect.InvocationTargetException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

import com.dev.swms.client.ui.javabean.JB_Location_RC_IV;
import com.dev.swms.server.model.inventory.Inventory;
import com.dev.swms.server.model.inventory.Stock;
import com.dev.swms.server.service.GlobalParamUtils;
import com.dev.swms.server.utils.DoubleUtils;
import com.dev.energy.server.exception.BusinessException;
import com.dev.energy.server.model.VersionalEntity;

public class Location extends VersionalEntity {
	private static final long serialVersionUID = 93619763875888775L;
	public static final String EMPTY = "EMPTY";
	public static final String STORE = "STORE";
	public static final String PICK = "PICK";
	public static final String VALID = "";
	public static final String INVALID = "INVALID";
	public static final String PASS = "PASS";
	public static final String NO_PASS = "NO_PASS";
	public static final String WAIT_ADD = "WAIT_ADD";
	public static final String WAIT_UPDATE = "WAIT_UPDATE";
	/** 所属仓库 */
	private Warehouse warehouse;
	/** 库位代码 */
	private String code;
	/** 库位名称 */
	private String name;
	/** 库区 */
	private WarehouseArea zone;
	/** 过道 */
	private int aisle;
	/** 排 */
	private int line;
	/** 层 */
	private int row;
	/** 列 */
	private int col;
	/** 库位类型 */
	private String type;
	/** 包含库存 */
	private Set<Inventory> inventories;
	/** 库位序号 */
	private int sortIndex;
	/** 是否有效 */
	private boolean disabled = false;
	/** 库位盘点锁 */
	private String countLock = "";
	/** 入锁 */
	private String inLock = "";
	/** 出锁 */
	private String outLock = "";
	/** 库位承载类型 */
	private Stowage stowage;
	/** 是否允许产品混放 */
	private boolean mixItem = false;
	/** 是否允许批次混放 */
	private boolean mixLot = false;
	/** 当前存放的货品ID */
	private Long currentItem;
	/** 当前存放的批次属性ID */
	private Long currentLot;
	/** 待上架总重量 */
	private double queuedWeight;
	/** 待上架总体积 */
	private double queuedVolume;
	/** 待上架总数量 */
	private double queuedQuantity;
	/** 待上架总托盘数 */
	private int queuedLP;
	/** 库位总重量 */
	private double totalWeight;
	/** 库位总体积 */
	private double totalVolume;
	/** 库位总数量 */
	private double totalQuantity;
	/** 库位总托盘数 */
	private int totalLP;
	/** 库位占用比率 */
	private double usedRate;
	/** 拆箱级别 */
	private int muPick;
	/** 最后盘点日期 */
	private Date cycleDate;
	/** 库位出入状态 */
	private String status;
	/** 货架类型
	 *  普通货架
	 *  单通道货架
	 *  双通道货架
	 *  重力式货架 */
	private String rackType;
	/** 作业模式 */
	private String taskMode;
	/** 退拣库位---发货库位和退拣库位货品退拣库位 */
	private Location pickBackLoc;
	/** 所属库位定位分类ID集合:"<12><23>..." */
	private String positionIds;
	/** 已分配托盘号 */
	private String allocateLP;
	
	/** 定位分类 */
	private Position position;	
	
	/** 备注 */
	private String remarks;
	/** 出锁 */
	private String barCode;
	/** 缓存库位关联 */
	private String hckwCode;
	
	/** 缓存库位关联 */
	private Location hckw;
	
	/** 修改库位 */
	private String updateCode;
	
	/** 库位状态*/
	private String flagStatus=Location.WAIT_ADD;

	
	
	public String getUpdateCode() {
		return updateCode;
	}
	public void setUpdateCode(String updateCode) {
		this.updateCode = updateCode;
	}
	public String getFlagStatus() {
		return flagStatus;
	}
	public void setFlagStatus(String flagStatus) {
		this.flagStatus = flagStatus;
	}
	public String getHckwCode() {
		return hckwCode;
	}
	public void setHckwCode(String hckwCode) {
		this.hckwCode = hckwCode;
	}
	public Location getHckw() {
		return hckw;
	}
	public void setHckw(Location hckw) {
		this.hckw = hckw;
	}
	public String getBarCode() {
		return barCode;
	}
	public void setBarCode(String barCode) {
		this.barCode = barCode;
	}
	public Position getPosition() {
		return position;
	}
	public void setPosition(Position position) {
		this.position = position;
	}
	public String getAllocateLP() {
		return allocateLP;
	}
	public void setAllocateLP(String allocateLP) {
		this.allocateLP = allocateLP;
	}
	public String getPositionIds() {
		return positionIds;
	}
	public void setPositionIds(String positionIds) {
		this.positionIds = positionIds;
	}
	public Location getPickBackLoc() {
		return pickBackLoc;
	}
	public void setPickBackLoc(Location pickBackLoc) {
		this.pickBackLoc = pickBackLoc;
	}
	public String getTaskMode() {
		return taskMode;
	}
	public void setTaskMode(String taskMode) {
		this.taskMode = taskMode;
	}
	public String getRackType() {
		return rackType;
	}
	public void setRackType(String rackType) {
		this.rackType = rackType;
	}
	public Date getCycleDate() {
		return cycleDate;
	}
	public int getQueuedLP() {
		return queuedLP;
	}
	public String getStatus() {
		return status;
	}
	public void setStatus(String status) {
		this.status = status;
	}
	public void setQueuedLP(int queuedLP) {
		this.queuedLP = queuedLP;
	}
	public int getTotalLP() {
		return totalLP;
	}
	public void setTotalLP(int totalLP) {
		this.totalLP = totalLP;
	}
	public void setCycleDate(Date cycleDate) {
		this.cycleDate = cycleDate;
	}
	
	public int getMuPick() {
		return muPick;
	}
	public void setMuPick(int muPick) {
		this.muPick = muPick;
	}
	public Location() {
		super();
	}
	
	
	
	public double getUsedRate() {
		return usedRate;
	}
	public void setUsedRate(double usedRate) {
		this.usedRate = usedRate;
	}
	public double getQueuedQuantity() {
		return queuedQuantity;
	}
	public void setQueuedQuantity(double queuedQuantity) {
		this.queuedQuantity = queuedQuantity;
	}
	public double getTotalQuantity() {
		return totalQuantity;
	}
	public void setTotalQuantity(double totalQuantity) {
		this.totalQuantity = totalQuantity;
	}
	public double getTotalVolume() {
		return totalVolume;
	}
	public void setTotalVolume(double totalVolume) {
		this.totalVolume = totalVolume;
	}
	public double getTotalWeight() {
		return totalWeight;
	}
	public void setTotalWeight(double totalWeight) {
		this.totalWeight = totalWeight;
	}
	public Long getCurrentItem() {
		return currentItem;
	}
	public void setCurrentItem(Long currentItem) {
		this.currentItem = currentItem;
	}
	public Long getCurrentLot() {
		return currentLot;
	}
	public void setCurrentLot(Long currentLot) {
		this.currentLot = currentLot;
	}
	public boolean isMixItem() {
		return mixItem;
	}
	public void setMixItem(boolean mixItem) {
		this.mixItem = mixItem;
	}
	public boolean isMixLot() {
		return mixLot;
	}
	public void setMixLot(boolean mixLot) {
		this.mixLot = mixLot;
	}
	public boolean isDisabled() {
		return disabled;
	}
	public void setDisabled(boolean disabled) {
		this.disabled = disabled;
	}
	public int getSortIndex() {
		return sortIndex;
	}
	public void setSortIndex(int sortIndex) {
		this.sortIndex = sortIndex;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getQueuedVolume() {
		return queuedVolume;
	}
	public void setQueuedVolume(double queuedVolume) {
		this.queuedVolume = queuedVolume;
	}
	public double getQueuedWeight() {
		return queuedWeight;
	}
	public void setQueuedWeight(double queuedWeight) {
		this.queuedWeight = queuedWeight;
	}
	public Stowage getStowage() {
		return stowage;
	}
	public void setStowage(Stowage stowage) {
		this.stowage = stowage;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	public Warehouse getWarehouse() {
		return warehouse;
	}
	public void setWarehouse(Warehouse warehouse) {
		this.warehouse = warehouse;
	}
	public WarehouseArea getZone() {
		return zone;
	}
	public void setZone(WarehouseArea zone) {
		this.zone = zone;
	}
	public Set<Inventory> getInventories() {
		return inventories;
	}
	public void setInventories(Set<Inventory> inventories) {
		this.inventories = inventories;
	}
	public int getAisle() {
		return aisle;
	}
	public void setAisle(int aisle) {
		this.aisle = aisle;
	}
	public int getLine() {
		return line;
	}
	public void setLine(int line) {
		this.line = line;
	}
	public int getCol() {
		return col;
	}
	public void setCol(int col) {
		this.col = col;
	}
	public int getRow() {
		return row;
	}
	public void setRow(int row) {
		this.row = row;
	}
	public String getInLock() {
		return inLock;
	}
	public void setInLock(String inLock) {
		this.inLock = inLock;
	}
	public String getOutLock() {
		return outLock;
	}
	public void setOutLock(String outLock) {
		this.outLock = outLock;
	}	
	public String getCountLock() {
		return countLock;
	}
	public void setCountLock(String countLock) {
		this.countLock = countLock;
	}

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

	public int hashCode() {
		return new HashCodeBuilder().append(warehouse).append(code)
				.toHashCode();
	}
	
	/**
	 * 检查库位是否锁了
	 * @return
	 */
	public boolean beLocked() {
		if (this.beInLock() || this.beOutLock() || this.beCountLock()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 检查库位是否不允许上架或者上架分配
	 * @return
	 */
	public boolean bePutAwayLock() {
		if (this.beInLock() || this.beCountLock()) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * 检查库位是否不允许捡货或者捡货分配
	 * @return
	 */
	public boolean bePickLock() {
		if (this.beInLock() || this.beCountLock()) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * 检查库位是否处于入锁状态
	 * @return
	 */
	public boolean beInLock() {
		if (!StringUtils.isEmpty(this.inLock)) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * 检查库位是否处于出锁状态
	 * @return
	 */
	public boolean beOutLock() {
		if (!StringUtils.isEmpty(this.outLock)) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * 检查库位是否处于盘点状态
	 * @return
	 */
	public boolean beCountLock() {
		if (!StringUtils.isEmpty(this.countLock)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 库位上架预分配
	 * 
	 * @param quantity
	 * @param packageUnit
	 */
	public void allocate(ItemKey itemKey, double quantity, PackageUnit unit, Stock LP) {
		this.queuedQuantity += DoubleUtils.formatByPrecision(quantity, unit.getPrecision());
		this.queuedWeight += DoubleUtils.formatByPrecision(quantity* unit.getWeight(),unit.getPrecision());
		//GlobalParamUtils.formatDecimalByType(quantity* unit.getWeight(), "maintainTableDecimal");
		this.queuedVolume += DoubleUtils.formatByPrecision(quantity* unit.getVolume(),unit.getPrecision());
		//GlobalParamUtils.formatDecimalByType(quantity* unit.getVolume(), "maintainTableDecimal");
		this.currentLot = itemKey.getId();
		this.currentItem = itemKey.getItem().getId();
		
		if (StringUtils.isEmpty(this.allocateLP)) {
			this.allocateLP = "";
		}
		if (LP != null) {
			if (this.allocateLP.indexOf("<"+LP.getId()+">") == -1) {
				this.allocateLP += ("<"+LP.getId()+">");
			}
		}
		
		this.queuedLP = StringUtils.countMatches(this.allocateLP, "<");

		this.refreshRate();
	}

	/**
	 * 取消库位上架分配
	 * 
	 * @param quantity
	 * @param packageUnit
	 */
	public void unAllocate(double quantity, PackageUnit unit, Stock LP) {
		this.queuedQuantity -= DoubleUtils.formatByPrecision(quantity, unit.getPrecision());
//		if (GlobalParamUtils.formatDecimalByType(this.queuedQuantity,
//				"maintainTableDecimal") <= 0) {
//			this.queuedVolume = 0;
//			this.queuedWeight = 0;
//		} else {
//			this.queuedWeight -= GlobalParamUtils.formatDecimalByType(quantity
//					* unit.getWeight(), "maintainTableDecimal");
//			this.queuedVolume -= GlobalParamUtils.formatDecimalByType(quantity
//					* unit.getVolume(), "maintainTableDecimal");
//		}
		
		if (LP != null) {
			if (!StringUtils.isEmpty(this.allocateLP) && this.allocateLP.indexOf("<"+LP.getId()+">") != -1) {
				this.allocateLP = StringUtils.remove(this.allocateLP, "<"+LP.getId()+">");
			}
		}

		this.queuedLP = StringUtils.countMatches(this.allocateLP, "<");
		if (this.queuedQuantity <= 0 && this.totalQuantity <= 0) {
			this.currentItem = null;
			this.currentLot = null;
		}

		this.refreshRate();
	}
	
	/**
	 * 计算当前库位的占用比率
	 * 
	 * @return 带两位小数的占用比例值
	 */
	public double refreshRate() {
//		double rate = 0;
//		if (!LocationType.STORAGE.equals(this.getType())&&!LocationType.TRANSIT.equals(this.getType())) {
//			return rate;
//		}
//		/**zongxing.zeng
//		 * 计算库位占用比率时要综合考虑数量、重量、体积、托盘数，取其中的最大值
//		 */
//		if (this.getStowage() != null) {
//			if(this.getStowage().getWeight()!=0.0){
//				rate = (queuedWeight + totalWeight)/ this.getStowage().getWeight() * 100;
//			}
//			if(this.getStowage().getVolume()!=0.0){
//				if(((queuedVolume + totalVolume)/ this.getStowage().getVolume() * 100)>rate)
//					rate = (queuedVolume + totalVolume)/ this.getStowage().getVolume() * 100;
//			}
//			if(this.getStowage().getQuantity()!=0.0){
//				if(((queuedQuantity + totalQuantity)/ this.getStowage().getQuantity() * 100)>rate)
//					rate = (queuedQuantity + totalQuantity)/ this.getStowage().getQuantity() * 100;
//			}
//			if(this.getStowage().getLpLimit()!=0.0){
//				if(((queuedLP + totalLP)*1.0 / this.getStowage().getLpLimit() * 100)>rate)
//					rate = (queuedLP + totalLP)*1.0 / this.getStowage().getLpLimit() * 100;
//			}
//			
//			this.usedRate = Double.valueOf(
//					new DecimalFormat(".##").format(rate)).doubleValue();
//		}
//		
//		if (this.queuedQuantity <= 0 && this.totalQuantity <= 0) {
//			this.currentItem = null;
//			this.currentLot = null;
//		}
//		
		return this.usedRate;
	}
	
	public void refreshTotal() {
//		if (!LocationType.STORAGE.equals(this.getType())&&!LocationType.TRANSIT.equals(this.getType())) {
//			return;
//		}
//		this.totalQuantity = 0;
//		this.totalWeight = 0;
//		this.totalVolume = 0;
//		Set<Stock> lps = new HashSet<Stock>();
//		for (Inventory inventory : this.getInventories()) {
//			if (inventory.getQtyOfMasterPack() > 0) {
//				this.setCurrentItem(inventory.getItemKeyInventory().getItemKey().getItem().getId());
//				this.setCurrentLot(inventory.getItemKeyInventory().getItemKey().getId());
//				
//				this.totalQuantity += inventory.getQuantity();
//				this.totalWeight += inventory.getQuantity() * inventory.getPackageUnit().getWeight();
//				this.totalVolume += inventory.getQuantity() * inventory.getPackageUnit().getVolume();
//				if (inventory.getLP() != null) {
//					lps.add(inventory.getLP());
//				}
//			}
//		}
//		this.setTotalLP(lps.size());
//		
//		if (this.totalQuantity == 0 && this.queuedQuantity == 0) {
//			this.setCurrentItem(null);
//			this.setCurrentLot(null);
//		}
//		
//		//调整库位状态
//		if (this.totalQuantity <= 0) {
//			this.status = Location.EMPTY;
//		}
//		
//		//更新托盘排序号
//		if (this.totalLP > 0) {
//			refreshStock(lps);
//		}
//		
//		//更新库满度
//		refreshRate();
	}
	
	/**
	 * 根据库满度和上架货物的包装计算当前库位能上架的最大数量
	 * @return
	 */
	public double canPutAwayQuantity(PackageUnit packageUnit){
//		double fullRate = this.getStowage().getFullRate();//库满度
//		double quantity = 999999999.0;
//		if (!LocationType.STORAGE.equals(this.getType())) {
//			return .0;
//		}
//		//如果this.getStowage().getQuantity()为0 ,则表示不接收数量的限制
//		if(this.getStowage().getQuantity()!=0.0)
//			quantity = this.getStowage().getQuantity()*(fullRate/100)-this.queuedQuantity-this.totalQuantity;
//		
//		if((Double)packageUnit.getWeight()!=null && packageUnit.getWeight()!=0.0 
//				&& this.getStowage().getWeight()!=0.0){
//			double qty = (this.getStowage().getWeight()*(fullRate/100)-this.queuedWeight-this.totalWeight)/packageUnit.getWeight();
//			if(qty<quantity){
//				quantity = qty;
//			}
//		}
//		if((Double)packageUnit.getVolume()!=null && packageUnit.getVolume()!=0.0 
//				&& this.getStowage().getVolume()!=0.0){
//			double qty = (this.getStowage().getVolume()*(fullRate/100)-this.queuedVolume-this.totalVolume)/packageUnit.getVolume();
//			if(qty<quantity){
//				quantity = qty;
//			}
//		}
//		if(quantity<0.0)
//			return .0;
//		return ((Double)quantity).intValue();
		return 0d;
	}
	/**
	 * 按照库满度计算还能放多少个托盘
	 * @return
	 */
	public int canPutAwayLPQuantity(){
		double fullRate = this.getStowage().getFullRate();//库满度
		if (!LocationType.STORAGE.equals(this.getType())) {
			return 0;
		}
		if(this.getStowage().getLpLimit()==0)
			return 999999;
		return new Double(this.getStowage().getLpLimit()*(fullRate/100)-this.queuedLP-this.totalLP).intValue();
	}
	
	/**
	 * 库位增加托盘或减少托盘后要更新对应托盘的排序号
	 */
	@SuppressWarnings("unchecked")
	private void refreshStock(Set<Stock> stocks) {
		//普通货架不做处理
		if (RackType.NORMAL.equals(this.rackType)) {
			return;
		}
		if (stocks == null || this.stowage == null) {
			return;
		}
		if (stocks.size() > this.stowage.getLpLimit() 
				&& this.stowage.getLpLimit() > 0) {
			throw new BusinessException("location.lp.outOfRange");
		}
		if (RackType.DOUBLE.equals(this.rackType)) {
			if (getStockMaxIndex(stocks) > this.stowage.getLpLimit()) {
				throw new BusinessException("location.lp.outOfRange");
			}
		}
		
		List<Stock> ss = new ArrayList<Stock>();
		for (Stock st : stocks) {
			if (st.getInventoryQty() > 0) {
				ss.add(st);
			} else {
				st.setLocationIndex(0);
			}
		}
		Collections.sort(ss, new BeanComparator("locationIndex"));
		
		if (RackType.SINGLE.equals(this.rackType)) {
			//单通道货架
			for (int i=0; i<ss.size(); i++) {
				ss.get(i).setLocationIndex(i+1);
			}
		} else if (RackType.DOUBLE.equals(this.rackType)) {
			//双通道货架
			for (Stock stk : ss) {
				if (stk.getLocationIndex() == 0) {
					stk.setLocationIndex(getStockMaxIndex(stocks)+1);
				}
			}
		} else if (RackType.GRAVITY.equals(this.rackType)) {
			//重力式货架
			for (Stock stk : ss) {
				if (stk.getLocationIndex() == 0) {
					stk.setLocationIndex(getStockMaxIndex(stocks)+1);
				}
			}
			for (int i=0; i<ss.size(); i++) {
				ss.get(i).setLocationIndex(i+1);
			}
		}
	}
	
	private int getStockMaxIndex(Set<Stock> stocks) {
		int i = 0;
		for (Stock stk : stocks) {
			if (stk.getLocationIndex() > i) {
				i = stk.getLocationIndex();
			}
		}
		return i;
	}
	
	/**
	 * 检查指定货品或批次是否能够放置到当前库位
	 * @param itemId
	 * @param itemKeyId
	 * @return true---允许放置 false---不允许放置
	 */
	public boolean beMixAble(Long itemId, Long itemKeyId) {
		if (!this.isMixItem() && this.getCurrentItem() != null) {
			if (!itemId.equals(this.getCurrentItem())) {
				return false;
			}
		}
		if (!this.isMixLot() && this.getCurrentLot() != null) {
			if (!itemKeyId.equals(this.getCurrentLot())) {
				return false;
			}
		}
		return true;
	}

	public JB_Location_RC_IV construct_JB_Location(){
		JB_Location_RC_IV liv = new JB_Location_RC_IV();
		try {
			BeanUtils.copyProperties(liv,this);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		liv.setRate(this.usedRate/this.stowage.getFullRate());
		liv.setFullRate(this.stowage.getFullRate());
		liv.setLength(this.stowage.getLength());
		liv.setWidth(this.stowage.getWidth());
		liv.setHeight(this.stowage.getHeight());
		liv.setTotalWeight(this.stowage.getWeight());
		liv.setTotalQuantity(this.stowage.getQuantity());
		liv.setTotalVolume(this.stowage.getVolume());
		liv.setTotalLP(this.stowage.getLpLimit());
		return liv;
	}
	
	public int getAllowLPCount() {
		return this.getStowage().getLpLimit() - this.getTotalLP() - this.getQueuedLP();
	}
	
	public void addLP() {
		this.queuedLP--;
		this.totalLP++;
	}
	
	public void removeLP() {
		this.totalLP--;
	}
	public String getRemarks() {
		return remarks;
	}
	public void setRemarks(String remarks) {
		this.remarks = remarks;
	}
	
	
}
