package com.dev.swms.server.service.count.pojo;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.dev.swms.server.model.base.Item;
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.Structure;
import com.dev.swms.server.model.base.Worker;
import com.dev.swms.server.model.count.CountDetail;
import com.dev.swms.server.model.count.CountDetailCompany;
import com.dev.swms.server.model.count.CountDetailItem;
import com.dev.swms.server.model.count.CountDetailLocation;
import com.dev.swms.server.model.count.CountLocation;
import com.dev.swms.server.model.count.CountMethod;
import com.dev.swms.server.model.count.CountPlan;
import com.dev.swms.server.model.count.CountRecord;
import com.dev.swms.server.model.count.CountStatus;
import com.dev.swms.server.model.count.CountType;
import com.dev.swms.server.model.count.CreatCountPlanPackage;
import com.dev.swms.server.model.inventory.Inventory;
import com.dev.swms.server.model.rules.ItemStorageRule;
import com.dev.swms.server.service.base.ItemManager;
import com.dev.swms.server.service.count.CountPlanManager;
import com.dev.swms.server.service.inventory.InventoryManager;
import com.dev.swms.server.service.sequence.BussinessCodeManager;
import com.dev.swms.server.web.filter.WarehouseHolder;
import com.dev.energy.client.ui.table.RowData;
import com.dev.energy.server.exception.BusinessException;
import com.dev.energy.server.model.Entity;
import com.dev.energy.server.model.EntityFactory;
import com.dev.energy.server.service.pojo.DefaultBaseManager;
import com.dev.energy.server.util.LocalizedMessage;
import com.dev.energy.server.web.security.UserHolder;

@SuppressWarnings("unchecked")
public class DefaultCountPlanManager extends DefaultBaseManager implements
	CountPlanManager {
	protected final InventoryManager inventoryManager;
	protected final ItemManager itemManager;
	protected final BussinessCodeManager bussinessCodeManager;
	
	public DefaultCountPlanManager(BussinessCodeManager manager, InventoryManager manager2, ItemManager manager3) {
		super();
		bussinessCodeManager = manager;
		inventoryManager = manager2;
		itemManager = manager3;
	}
	
	/*
	* s (non-Javadoc)
	* @see com.dev.swms.server.service.count.CountPlanManager#active(java.lang.Long)
	*/
	public void active(RowData rowData) {
		Long countPlanId = (Long) rowData.getColumnValue(0);
		CountPlan countPlan = commonDao.load(CountPlan.class, countPlanId);
		if (countPlan.active()) {
			//循环盘点
			if (CountMethod.ITEM.equals(countPlan.getCountMethod()) 
					|| CountMethod.MOVED_ITEM.equals(countPlan.getCountMethod())
					|| CountMethod.ABC.equals(countPlan.getCountMethod())) {
				//按货品盘点
				for (CountDetail countDetail : countPlan.getDetails()) {
					Item item = ((CountDetailItem) countDetail).getItem();
					createCountRecordByItem(countPlan, item);
				}
			} else {
				//按库位动碰盘点&&按库位盘点
				for (CountDetail countDetail : countPlan.getDetails()) {
					Location location = ((CountDetailLocation) countDetail).getLocation();
					if(!location.beLocked()){
						createCountRecordByLocation(countPlan, location);							
					} else {
						continue;
					}
				}
			}
			LocalizedMessage.addMessage("countPlan.active.success", new String[] {countPlan.getCode()});
		} else {
			throw new BusinessException("countPlan.active.failed");
		}
	}
	
	/**
	* 对照所有库存生成盘点表
	*
	*/
	private void createAllCountRecords(CountPlan countPlan) {
		Set<Location> locations = countPlan.getWarehouse().getLocations();
		for (Location location : locations) {
			if (!LocationType.COUNT.equals(location.getType())) {
				createCountRecordByLocation(countPlan, location);
				//盘点锁定库位
				location.setCountLock(countPlan.getCode());
			}
		}
	}
	
	
	/**
	* 查找库存表中相同货品的库存，生成盘点表
	* @param item 待盘点货品
	*/
	@SuppressWarnings("unchecked")
	private void createCountRecordByItem(CountPlan countPlan, Item item) {
		Set<Inventory> inventories = new HashSet<Inventory>();
		inventories.addAll(commonDao.findByNamedQuery("getAllInventoryByWarehouseItem", 
				new String[] {"warehouseId", "itemId"}, 
				new Object[] {countPlan.getWarehouse().getId(), item.getId()}));
//		for (Inventory inventory : inventories) {
//			if (inventory.isLocked() || inventory.getQueuedQuantity() > 0) {
//				return;
//			}
//		}
		System.out.println(inventories.size());
		item.setCycleDate(new Date());
		createCountRecordByInventories(countPlan, inventories);
	}
	
	/**
	* 查找库存表中相同货主的库存，生成盘点表
	* @param company 待盘点货主
	*/
	@SuppressWarnings("unchecked")
	private void createCountRecordByCompany(CountPlan countPlan, Structure company) {
		Set<Inventory> inventories = new HashSet<Inventory>();
		inventories.addAll(commonDao.findByNamedQuery("getAllInventoryByWarehouseCompany", new String[] {"warehouseId", "companyId"}, new Object[] {countPlan.getWarehouse().getId(), company.getId()}));
		for (Inventory inventory : inventories) {
			if (inventory.isLocked()|| inventory.getQueuedQuantity()>0) {
				throw new BusinessException("inventory.locked");
			}
		}
		createCountRecordByInventories(countPlan, inventories);
	}
	
	/**
	* 查找库存表中相同库位的库存，生成盘点表
	* @param location 待盘点库位
	*/
	private void createCountRecordByLocation(CountPlan countPlan, Location location) {
		Set<Inventory> inventories = location.getInventories();
		Set<Inventory> companyInventories = new HashSet();
		for (Inventory inventory : inventories) {
			if (inventory.isLocked()|| inventory.getQueuedQuantity()>0) {
				continue;
			}
			if(inventory.getItemKeyInventory().getItemKey().getItem().getCompany().equals(countPlan.getCompany())){
				companyInventories.add(inventory);
			}
		}
		location.setCycleDate(countPlan.getPlanDate());
		createCountRecordByInventories(countPlan, companyInventories);
	}
	
	private void createCountRecordByInventories(CountPlan countPlan, Set<Inventory> inventories) {
		Map<CountRecord, Double> records = new HashMap<CountRecord, Double>();
		Set<Location> locs = new HashSet<Location>();
		for (Inventory inventory : inventories) {
			if (!LocationType.COUNT.equals(inventory.getLocation().getType())) {
				locs.add(inventory.getLocation());
				CountRecord record = new CountRecord(countPlan, inventory.getItemKeyInventory().getItemKey(), inventory.getLocation(), inventory.getLP(), inventory.getPackageUnit());
				if (!records.containsKey(record)) {
					records.put(record, inventory.getQtyOfMasterPack());
				} else {
					records.put(record, records.get(record)+inventory.getQtyOfMasterPack());
				}
			}
		}
		//根据Map生成records
		for (Map.Entry<CountRecord, Double> entry : records.entrySet()) {
			CountRecord countRecord = entry.getKey();
			countRecord.setQuantityMU(entry.getValue());
			countRecord.setCountQuantity(entry.getValue());
			countRecord.setDeltaQuantity(0);
			commonDao.store(countRecord);
		}
		
		//锁定所在库位
		countPlan.lockLocations(locs, countPlan.getCode());
	}
	
	/*
	*  (non-Javadoc)
	* @see com.dev.swms.server.service.count.CountPlanManager#inactive(java.lang.Long)
	*/
	public void inactive(RowData rowData) {
		Long countPlanId = (Long) rowData.getColumnValue(0);
		CountPlan countPlan = commonDao.load(CountPlan.class, countPlanId);
		if (countPlan.inactive()) {
			LocalizedMessage.addMessage("countPlan.inactive.success", new String[] {countPlan.getCode()});
		} else {
			throw new BusinessException("countPlan.inactive.failed");
		}
	}
	
	/*
	*  (non-Javadoc)
	* @see com.dev.swms.server.service.count.CountPlanManager#cancel(java.lang.Long)
	*/
	public void cancel(RowData rowData) {
		Long countPlanId = (Long) rowData.getColumnValue(0);
		CountPlan countPlan = commonDao.load(CountPlan.class, countPlanId);
		if (countPlan.cancel()) {
			LocalizedMessage.addMessage("countPlan.cancel.success", new String[] {countPlan.getCode()});
		} else {
			throw new BusinessException("countPlan.cancel.failed");
		}
	}
	
	/*
	*  (non-Javadoc)
	* @see com.dev.swms.server.service.count.CountPlanManager#close(java.lang.Long)
	*/
	public void close(RowData rowData) {
		Long countPlanId = (Long) rowData.getColumnValue(0);
		CountPlan countPlan = commonDao.load(CountPlan.class, countPlanId);
		if (countPlan.close()) {
			LocalizedMessage.addMessage("countPlan.close.success", new String[] {countPlan.getCode()});
		} else {
			throw new BusinessException("countPlan.close.failed");
		}
	}
	
	/*
	*  (non-Javadoc)
	* @see com.dev.swms.server.service.count.CountPlanManager#delete(java.lang.Long)
	*/
	public void delete(RowData rowData) {
		Long countPlanId = (Long) rowData.getColumnValue(0);
		CountPlan countPlan = commonDao.load(CountPlan.class, countPlanId);
		if (CountStatus.OPEN.equals(countPlan.getStatus())) {
			commonDao.delete(countPlan);
			LocalizedMessage.addMessage("countPlan.delete.success", new String[] {countPlan.getCode()});
		} else {
			throw new BusinessException("countPlan.delete.failed");
		}
	}
	
	/*
	*  (non-Javadoc)
	* @see com.dev.swms.server.service.count.CountPlanManager#adjust(java.lang.Long)
	*/
	public void adjust(Long countPlanId) {
		CountPlan countPlan = commonDao.load(CountPlan.class, countPlanId);
		if (!CountStatus.COUNT.equals(countPlan.getStatus())){
			throw new BusinessException("countPlan.status.error");
		}
		for (CountRecord countRecord : countPlan.getRecords()) {
			if (countRecord.getDeltaQuantity() != 0) {
				inventoryManager.countAdjust(countRecord);
			}
		}
		countPlan.setStatus(CountStatus.ADJUST);
		commonDao.store(countPlan);
		if (countPlan.close()) {
			LocalizedMessage.addMessage("countPlan.adjust.success", new String[] {countPlan.getCode()});
		} else {
			throw new BusinessException("countPlan.close.failed");
		}		
//		LocalizedMessage.addMessage("countPlan.adjust.success", new String[] {countPlan.getCode()});
	}
	
	
	/*
	*  (non-Javadoc)
	* @see com.dev.swms.server.service.count.CountPlanManager#record(java.lang.Long, com.dev.swms.server.model.count.CountRecord)
	*/
	public void record(Long countPlanId, CountRecord countRecord) {
		CountPlan countPlan = commonDao.load(CountPlan.class, countPlanId);
		if (countPlan.getCountDate() == null) {
			countPlan.setCountDate(new Date());
			countPlan.setStatus(CountStatus.COUNT);
			commonDao.store(countPlan);
		}
		Item item = this.commonDao.load(Item.class,countRecord.getItemKey().getItem().getId());
		countRecord.getItemKey().setItem(item);
		ItemKey dbItemKey = itemManager.getItemKey(countRecord.getItemKey(), Boolean.TRUE,null);
		
		CountRecord record = (CountRecord) commonDao.findByNamedQueryUniqueResult("getRecordByUK", 
				new String[] {"countPlanId", "itemKeyId", "locationId", "LP", "packageUnitId"},
				new Object[] {countPlanId, dbItemKey.getId(), countRecord.getLocation().getId(), countRecord.getLP(), countRecord.getPackageUnit().getId()});
		if (record == null) {
			if (countRecord.getCountQuantity()<0) {
				throw new BusinessException("countRecord.quantity.error");
			}
			CountRecord dbRecord = EntityFactory.getEntity(CountRecord.class);
			Location location = commonDao.load(Location.class, countRecord.getLocation().getId());
			PackageUnit packageUnit = commonDao.load(PackageUnit.class, countRecord.getPackageUnit().getId());
			dbRecord.setLocation(location);
			dbRecord.setLP(countRecord.getLP());
			dbRecord.setPackageUnit(packageUnit);
			dbRecord.setItemKey(dbItemKey);
			dbRecord.setQuantityMU(countRecord.getQuantityMU());
			dbRecord.record(countRecord.getCountQuantity() * packageUnit.getConvertFigure());
			dbRecord.setOperator(UserHolder.getUser().getName());
			dbRecord.setOccurTime(new Date());
			countPlan.addRecord(dbRecord);
			commonDao.store(countPlan);
		} else {
			record.record(countRecord.getCountQuantity() * record.getPackageUnit().getConvertFigure());
			if (record.getCountQuantity()<0) {
				throw new BusinessException("countRecord.quantity.error");
			} else if (record.getQuantity()==0 && record.getDeltaQuantity()==0) {
				countPlan.getRecords().remove(record);
			}
			commonDao.store(countPlan);
		}
		LocalizedMessage.addMessage("countPlan.addrecord.success");
	}
	
	/*
	*  (non-Javadoc)
	* @see com.dev.swms.server.service.count.CountPlanManager#addDetailLocations(java.lang.Long, java.util.List)
	*/
	public void addDetailLocations(Long countPlanId, List<Long> locationIds) {
		CountPlan countPlan = commonDao.load(CountPlan.class, countPlanId);
		for (Long id : locationIds) {
			CountDetailLocation detail = new CountDetailLocation();
			detail.setCountPlan(countPlan);
			detail.setLocation(commonDao.load(Location.class, id));
			countPlan.getDetails().add(detail);
		}
		commonDao.store(countPlan);
	}
	
	/*
	*  (non-Javadoc)
	* @see com.dev.swms.server.service.count.CountPlanManager#addDetailCompanys(java.lang.Long, java.util.List)
	*/
	public void addDetailCompanys(Long countPlanId, List<Long> companyIds) {
		CountPlan countPlan = commonDao.load(CountPlan.class, countPlanId);
		for (Long id : companyIds) {
			CountDetailCompany detail = new CountDetailCompany();
			detail.setCountPlan(countPlan);
			detail.setCompany(commonDao.load(Structure.class, id));
			countPlan.getDetails().add(detail);
		}
		commonDao.store(countPlan);
	}
	
	/*
	*  (non-Javadoc)
	* @see com.dev.swms.server.service.count.CountPlanManager#addDetailItems(java.lang.Long, java.util.List)
	*/
	public void addDetailItems(Long countPlanId, List<Long> itemIds) {
		CountPlan countPlan = commonDao.load(CountPlan.class, countPlanId);
		for (Long id : itemIds) {
			CountDetailItem detail = new CountDetailItem();
			detail.setCountPlan(countPlan);
			detail.setItem(commonDao.load(Item.class, id));
			countPlan.getDetails().add(detail);
		}
		commonDao.store(countPlan);
	}
	
	/*
	*  (non-Javadoc)
	* @see com.dev.swms.server.service.count.CountPlanManager#deleteDetails(java.lang.Long, java.util.List)
	*/
	public void deleteDetails(Long countPlanId, List<Long> countDetailIds) {
		CountPlan countPlan = commonDao.load(CountPlan.class, countPlanId);
		countPlan.getDetails().removeAll(commonDao.loadAll(CountDetail.class, countDetailIds.toArray(new Long[0])));
		commonDao.store(countPlan);
	}
	
	@SuppressWarnings("unchecked")
	public void adjust(Long countPlanId, Map records) {
		for(Iterator it = records.entrySet().iterator();it.hasNext();){
			Map.Entry entry = (Entry) it.next();
			Long recordId = (Long) entry.getKey();
			List value = (List) entry.getValue();
			Double countQuantity = Double.valueOf(String.valueOf(value.get(0)));
			if (countQuantity < 0) {
				throw new BusinessException("countRecord.quantity.NoneNegativeNumber.required");
			}
			CountRecord record = commonDao.load(CountRecord.class, recordId);
			record.record(countQuantity-record.getCountQuantity());
			commonDao.store(record);
		}
		CountPlan countPlan = commonDao.load(CountPlan.class, countPlanId);
		if (countPlan.getCountDate() == null) {
			countPlan.setCountDate(new Date());
			countPlan.setStatus(CountStatus.COUNT);
			commonDao.store(countPlan);
		}
		LocalizedMessage.addMessage("countPlan.record.success");
	}
	
	/*
	*  (non-Javadoc)
	* @see com.dev.swms.server.service.count.CountPlanManager#storeCountPlan(com.dev.swms.server.model.count.CountPlan)
	*/
	public void storeCountPlan(CountPlan countPlan) {
		if(countPlan.isNew()){
			countPlan.setWarehouse(WarehouseHolder.getWarehouse());
			countPlan.setStatus("OPEN");
			countPlan.setCode(bussinessCodeManager.generateCountPlanCode(new HashMap()));
		}
		this.commonDao.store(countPlan);
	}

	public void newStoreCountPlan(CreatCountPlanPackage creatCountPlanPackage) {
		if (creatCountPlanPackage.getCountMethod().equals(CountMethod.LOCATION)) {
			//创建按库位的盘点计划
			locationCountPlan(creatCountPlanPackage.getLocationCompanyId(), 
					creatCountPlanPackage.getToCountLocsCounts());
		} else if (creatCountPlanPackage.getCountMethod().equals(CountMethod.ITEM)) {
			//创建按货品的盘点计划
			itemCountPlan(creatCountPlanPackage.getItemCompanyId(),
					creatCountPlanPackage.getItemIds(), CountMethod.ITEM);
		} else if (creatCountPlanPackage.getCountMethod().equals(CountMethod.MOVED_LOCATION)
				|| creatCountPlanPackage.getCountMethod().equals(CountMethod.MOVED_ITEM)){
			//创建按动碰盘点的盘点计划
			movedCountPlan(creatCountPlanPackage.getMovedCompanyId(),
					creatCountPlanPackage.getCountMethod(),
					creatCountPlanPackage.getStartDate(),
					creatCountPlanPackage.getEndDate());
		} else if (creatCountPlanPackage.getCountMethod().equals(CountMethod.ABC)) {
			//创建按ABC分类盘点的盘点计划
			abcCountPlan(creatCountPlanPackage.getAbcCompanyId(),
					creatCountPlanPackage.getToCountItemsCounts());
		}
	}
	
	/**
	 * 创建按ABC分类盘点的盘点计划
	 * @param companyId
	 * @param quantity
	 */
	@SuppressWarnings("unchecked")
	private void abcCountPlan(Long companyId, double quantity) {
		//根据货主获取该货主所有的货品存放规则
		List<ItemStorageRule> rules = commonDao.findByNamedQuery("getItemStorageRuleByCompanyId", 
				new String[]{"companyId", "warehouseId"}, 
				new Object[]{companyId, WarehouseHolder.getWarehouse().getId()});
		//创建一个List存储不符合条件的货品, 当符合的货品数量不足时使用
		List<Long> exceptRules = new ArrayList<Long>();
		//如果该货主所有货品没有对应的货品存放规则, 则不能创建盘点计划
		if (rules == null || rules.isEmpty()) {
			throw new BusinessException("no.abcType.to.count");
		}
		List<Long> itemIds = new ArrayList<Long>();
		boolean noABCRule = true;
		for (ItemStorageRule rule : rules) {
			//又货品存放规则得到对应的货品, 然后判断是否符合盘点条件, 如果符合则加入到待盘点货品List中, 等待创建盘点计划
			Item item = rule.getItem();
			exceptRules.add(item.getId());
			//如果该货主所有货品未设置ABC分类, 则不能创建盘点计划
			if (rule.getAbcType() == null) {
				continue;
			} else {
				noABCRule = false;
				Calendar cycleDate = Calendar.getInstance();
				if(null != item.getCycleDate()){
					cycleDate.setTime(item.getCycleDate());
					cycleDate.set(Calendar.DAY_OF_MONTH, cycleDate.get(Calendar.DAY_OF_MONTH) + rule.getAbcType().getCycleDay());
				}else{
					cycleDate.setTime(new Date());
				}
				Calendar currentDate = Calendar.getInstance();
				currentDate.setTime(new Date());
				if (cycleDate.before(currentDate)  && existedItemKeyInventories(item.getId())) {
					itemIds.add(item.getId());
				}
				//当待盘点货品数量到达要求数量后, 创建盘点计划
				if (itemIds.size() == quantity) {
					newABCCountPlan(companyId, itemIds);
					return;
				}
			}
		}
		if (noABCRule) {
			throw new BusinessException("no.AbcTypeCountRule");
		}
		//当待盘点货品总数不足要求盘点数量时, 则按照货品最后盘点日期按先后顺序依次取足然后创建盘点计划
		exceptRules.removeAll(itemIds);
		for (ItemStorageRule rule : rules) {
			if (!itemIds.contains(rule.getItem().getId()) 
					&& existedItemKeyInventories(rule.getItem().getId())) {
				itemIds.add(rule.getItem().getId());
			}
			if (itemIds.size() == quantity) {
				newABCCountPlan(companyId, itemIds);
				return;
			}
		}
		//该货主所有货品都参与盘点后仍然不足要求数量, 则按照所有货品数量进行创建盘点计划
		newABCCountPlan(companyId, itemIds);
	}
	
	/**
	 * 判断存在ABC分类盘点规则的货品是否有库存可供盘点
	 * @param itemId
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public boolean existedItemKeyInventories(Long itemId) {
		List<Inventory> inventories = commonDao.findByNamedQuery("getAllInventoryByWarehouseAndItem", 
				new String[]{"itemId", "warehouseId"}, 
				new Object[]{itemId, WarehouseHolder.getWarehouse().getId()});
		if (inventories == null || inventories.isEmpty()) {
			return false;
		}
		return true;
	}
	
	/**
	 * 创建ABC分类盘点计划
	 * @param companyId
	 * @param itemIds
	 */
	public void newABCCountPlan(Long companyId, List<Long> itemIds) {
		//创建盘点计划
		CountPlan countPlan = new CountPlan();
		countPlan.setWarehouse(WarehouseHolder.getWarehouse());
		countPlan.setCode(bussinessCodeManager.generateCountPlanCode(new HashMap()));
		countPlan.setCountMethod(CountMethod.ABC);
		countPlan.setStatus(CountStatus.OPEN);
		countPlan.setPlanDate(new Date());
		countPlan.setDetails(new HashSet());
		countPlan.setCompany(commonDao.load(Structure.class, companyId));
		for(Long itemId : itemIds) {
			Item item = commonDao.load(Item.class, itemId);
			//增加明细
			CountDetailItem countDetail = new CountDetailItem();
			countDetail.setItem(item);
			countDetail.setCountPlan(countPlan);
			countPlan.getDetails().add(countDetail);
		}
		commonDao.store(countPlan);
	}
	
	/**
	 * 创建按动碰盘点的盘点计划
	 * @param companyId
	 * @param startDate
	 * @param endDate
	 */
	@SuppressWarnings("unchecked")
	private void movedCountPlan(Long companyId, String countMethod, Date startDate, Date endDate) {
		//转换开始时间, 结束时间格式
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String startDates = formatter.format(startDate);
		startDates += " 00:00:00";
		String endDates = formatter.format(endDate);
		endDates += " 23:59:59";
		Date newStartDate = new Date();
		Date newEndDate = new Date();
		try {
			newStartDate = formatter2.parse(startDates);
			newEndDate = formatter2.parse(endDates);
		} catch(Exception ex) {
			return;
		}
		
		Structure company = commonDao.load(Structure.class, companyId);
		if (CountMethod.MOVED_LOCATION.equals(countMethod)) {
			//库位动碰
			Set<Location> locs = new HashSet<Location>();
			locs.addAll(commonDao.findByNamedQuery("getLocationsFromInvLog", 
					new String[]{"warehouse", "startDate", "endDate", "company"}, 
					new Object[]{WarehouseHolder.getWarehouse(), newStartDate, newEndDate, company}));
			if(locs == null || locs.isEmpty()) {
				throw new BusinessException("no.inventory.had.moved");
			} else {
				//创建盘点计划
				CountPlan countPlan = new CountPlan();
				countPlan.setWarehouse(WarehouseHolder.getWarehouse());
				countPlan.setCode(bussinessCodeManager.generateCountPlanCode(new HashMap()));
				countPlan.setCountMethod(CountMethod.MOVED_LOCATION);
				countPlan.setStatus(CountStatus.OPEN);
				countPlan.setPlanDate(new Date());
				countPlan.setDetails(new HashSet());
				countPlan.setCompany(company);
				for(Location location : locs) {
					//增加明细
					CountDetailLocation countDetail = new CountDetailLocation();
					countDetail.setLocation(location);
					countDetail.setCountPlan(countPlan);
					countPlan.getDetails().add(countDetail);
				}
				commonDao.store(countPlan);
			}
		} else {
			
			//货品动碰
			Set<Long> itemIds = new HashSet<Long>();
			itemIds.addAll(commonDao.findByNamedQuery("getItemIdsFromInvLog", 
					new String[]{"warehouse", "startDate", "endDate", "company"}, 
					new Object[]{WarehouseHolder.getWarehouse(), newStartDate, newEndDate, company}));
			if (itemIds == null || itemIds.size() == 0) {
				throw new BusinessException("no.inventory.had.moved");
			} else {
				itemCountPlan(company.getId(), itemIds, CountMethod.MOVED_ITEM);
			}
		}
	}
	
	/**
	 * 创建按货品的盘点计划
	 * @param companyId
	 * @param itemIds
	 */
	private void itemCountPlan(Long companyId, Collection itemIds, String countMethod) {
		//创建盘点计划
		CountPlan countPlan = new CountPlan();
		countPlan.setWarehouse(WarehouseHolder.getWarehouse());
		countPlan.setCode(bussinessCodeManager.generateCountPlanCode(new HashMap()));
		countPlan.setCountMethod(countMethod);
		countPlan.setStatus(CountStatus.OPEN);
		countPlan.setPlanDate(new Date());
		countPlan.setDetails(new HashSet());
		countPlan.setCompany(commonDao.load(Structure.class, companyId));
		if (itemIds != null) {
			for(Object itemId : itemIds) {
				Item item = commonDao.load(Item.class, (Long) itemId);
				//增加明细
				CountDetailItem countDetail = new CountDetailItem();
				countDetail.setItem(item);
				countDetail.setCountPlan(countPlan);
				countPlan.getDetails().add(countDetail);
			}
		}
		commonDao.store(countPlan);
	}
	
	/**
	 * 创建按库位的盘点计划
	 * @param companyId
	 * @param toCountLocsCounts
	 */
	@SuppressWarnings("unchecked")
	private void locationCountPlan(Long companyId, int toCountLocsCounts) {
		Structure company = commonDao.load(Structure.class, companyId);
		
		List<Location> locs = new ArrayList<Location>();
		locs.addAll(getLocationsByCompany(company));
		
		//判断录入的"待盘点库位"数量与符合盘点库位数量之间的关系, 如果符合盘点库位数量不足, 则补足库位进行盘点
		if(locs.size() >= toCountLocsCounts) {
			cycleCountPlan(locs.subList(0, toCountLocsCounts), company);
		} else {
			String locsSql = "SELECT DISTINCT new com.dev.swms.server.model.count.CountLocation(inv.location, inv.location.cycleDate)" +
				" FROM Inventory inv WHERE inv.location.warehouse.id = :warehouseId" + 
				" AND inv.itemKeyInventory.itemKey.item.company.id = :companyId " +
				" AND inv.location.countLock = '' AND inv.location.inLock = '' AND inv.location.outLock = '' AND inv.location.disabled = false" + 
				" AND to_days(current_date()) - to_days(inv.location.cycleDate) <= (select rule.cycleDay from CompanyWorkRule rule " +
				" 	where rule.company.id=:companyId and rule.warehouse.id=inv.location.warehouse.id)" +
				" AND inv.location.type = 'STORAGE' AND inv.status = ''" +
				" ORDER BY inv.location.cycleDate";
			
			//获取已盘点的符合盘点条件的库位
			List<CountLocation> countLocations = commonDao.findByQuery(locsSql, 
					new String[]{"warehouseId", "companyId"}, 
					new Object[]{WarehouseHolder.getWarehouse().getId(), company.getId()});
			
			List<Location> locations = new ArrayList<Location>();
			for(CountLocation cl : countLocations) {
				locations.add(cl.getLocation());
			}
			
			//根据获取的已盘点的符合盘点条件的库位数量进行相应的盘点
			locs.addAll(locations.subList(0, (toCountLocsCounts - locs.size()) < locations.size()
					? toCountLocsCounts - locs.size()
					: locations.size()));
			
			cycleCountPlan(locs, company);
		}
	}
	
	/**
	 * 创建循环盘点计划
	 * @param locations
	 * @param countPlan
	 */
	@SuppressWarnings("unchecked")
	public void cycleCountPlan(List<Location> locations, Structure company) {
		//创建盘点计划
		CountPlan countPlan = new CountPlan();
		countPlan.setWarehouse(WarehouseHolder.getWarehouse());
		countPlan.setCode(bussinessCodeManager.generateCountPlanCode(new HashMap()));
		countPlan.setCountType(CountType.CYCLE);
		countPlan.setCountMethod(CountMethod.LOCATION);
		countPlan.setStatus(CountStatus.OPEN);
		countPlan.setPlanDate(new Date());
		countPlan.setDetails(new HashSet());
		countPlan.setCompany(company);
		//添加details
		for(Location location : locations) {
			CountDetailLocation countDetail = new CountDetailLocation();
			countDetail.setLocation(location);
			countDetail.setCountPlan(countPlan);
			countPlan.getDetails().add(countDetail);
		}
		//if(countPlan.getDetails().size() == 0) {
		//	throw new BusinessException("company.count.noLocation");
		//}
		commonDao.store(countPlan);
	}
	
	/**
	 * 根据盘点客户得到盘点库位
	 * @param company
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Location> getLocationsByCompany(Structure company) {
		List<Location> allLocations = new ArrayList<Location>();
		List<Location> excepLocations = new ArrayList<Location>();
		
		//获取满足条件的盘点库位
		String allLocSql = "SELECT DISTINCT inv.location FROM Inventory inv WHERE inv.location.warehouse.id = :warehouseId "+ 
			"AND inv.location.type = 'STORAGE' AND inv.itemKeyInventory.itemKey.item.company.id = :companyId " +
			"AND inv.location.disabled = false GROUP BY inv.location ORDER BY inv.location.cycleDate ";
		
		String expLocSql = "SELECT DISTINCT inv.location FROM Inventory inv WHERE inv.location.warehouse.id = :warehouseId"+ 
		" AND inv.itemKeyInventory.itemKey.item.company.id = :companyId " +
		" AND (inv.status <> '' OR inv.location.countLock <> '' OR inv.location.inLock <> '' OR inv.location.outLock <> '' OR inv.location.disabled = true" + 
		" OR (to_days(current_date()) - to_days(inv.location.cycleDate) <= (select rule.cycleDay from CompanyWorkRule rule " +
				" 	where rule.company.id=:companyId and rule.warehouse.id=inv.location.warehouse.id)))" +
		" AND inv.location.type = 'STORAGE'";
		
		allLocations.addAll(commonDao.findByQuery(allLocSql, new String[] {"warehouseId", "companyId"}, 
				new Object[] {WarehouseHolder.getWarehouse().getId(), company.getId()}));
		excepLocations.addAll(commonDao.findByQuery(expLocSql, new String[] {"warehouseId", "companyId"}, 
				new Object[] {WarehouseHolder.getWarehouse().getId(), company.getId()}));
		allLocations.removeAll(excepLocations);

		return allLocations;
	}
	
	public String getUnCountLocationsByCompany(Map map) {
		RowData rowData = (RowData) map.get("rowData");
		if (rowData == null) {
			return "";
		}
		Long companyId = (Long) rowData.getColumnValue(0);
		Structure company = this.commonDao.load(Structure.class, Long.valueOf(companyId));
		List<Location> allLocations = getLocationsByCompany(company);
		if (allLocations != null) {
			return String.valueOf(allLocations.size());
		}
		
		return "0";
	}
	
	public boolean isExistCount(Long userId){
		Long count = (Long)commonDao.findByNamedQueryUniqueResult("getCountByUserId",
				new String[]{"userId"}, new Object[]{userId});
		return count != null && count > 0L;
	}
	
	
	protected Worker getWorkerByUserId(Long userId){
		List<Worker> workers = commonDao.findByNamedQuery("getWorkerByUserId",
				new String[]{"userId"},new Object[]{userId});
		if(workers.isEmpty()){
			throw new NullPointerException("操作人员不存在!");
		}
		return workers.get(0);
	}
	
	public void backCounts(List<Long> counts){
		for(Long id : counts){
			CountRecord cr = load(CountRecord.class,id);
			cr.setWorker(null);
		}
	}

	public <T extends Entity> List<T> load(Class<T> clazz, List<Long> id) {
		// TODO Auto-generated method stub
		return null;
	}

	public boolean createCountRecord(Map<String, Object> values) {
		return false;
	}
	
}
