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

import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.comparators.ReverseComparator;

import com.dev.swms.server.model.base.Item;
import com.dev.swms.server.model.base.ItemShipInfo;
import com.dev.swms.server.model.base.ItemTypeSetMethod;
import com.dev.swms.server.model.base.Warehouse;
import com.dev.swms.server.model.rules.AbcTypeCountRule;
import com.dev.swms.server.model.rules.CompanyTransRule;
import com.dev.swms.server.model.rules.CompanyTransRuleDetail;
import com.dev.swms.server.model.rules.CompanyWorkRule;
import com.dev.swms.server.model.rules.CustomerWorkRule;
import com.dev.swms.server.model.rules.ItemStorageRule;
import com.dev.swms.server.model.rules.ItemSupplyRule;
import com.dev.swms.server.model.rules.LotRule;
import com.dev.swms.server.model.rules.PresentSaleRule;
import com.dev.swms.server.service.rule.RuleManager;
import com.dev.swms.server.web.filter.WarehouseHolder;
import com.dev.energy.client.utils.StringUtils;
import com.dev.energy.server.exception.BusinessException;
import com.dev.energy.server.service.pojo.DefaultBaseManager;
import com.dev.energy.server.util.LocalizedMessage;

@SuppressWarnings("unchecked")
public class DefaultRuleManager extends DefaultBaseManager implements
		RuleManager {

	public void storeItemStorageRule(ItemStorageRule itemStorageRule) {
		if (itemStorageRule.isNew()) {
			itemStorageRule.setWarehouse(WarehouseHolder.getWarehouse());
		}
		this.store(itemStorageRule);
	}

	public void deleteItemStorageRules(List<Long> ids) {
		this.commonDao.deleteAll(this.commonDao.loadAll(ItemStorageRule.class, ids.toArray(new Long[] {})));
	}
	
	public void deleteLotRules(List<Long> lotRuleIds) {
		String errMsg = "";
		for(Long id : lotRuleIds){
			LotRule lotRule = this.load(LotRule.class,id);
			Long countItem = (Long) commonDao.findByNamedQueryUniqueResult(
					"getItemsByLotRule",new String[] { "lotRule" },new Object[] {lotRule});
		    if(countItem > 0){
		    	errMsg+=lotRule.getCode()+" 的规则使用中;";
		    }
		    else
		    	this.delete(lotRule);
		}
		if(!"".equals(errMsg))
			LocalizedMessage.addLocalizedMessage(errMsg);
		
	}

	/**
	 * 修改目的：判断补货上限是否小于补货下限
	 * 作者:yufei.ge
	 * */
	public void storeItemSupplyRule(ItemSupplyRule itemSupplyRule) {
		if(itemSupplyRule.getMinReplenishment()>itemSupplyRule.getMaxReplenishment()){
	    	throw new BusinessException("itemSupplyRule.quality.error");
			
		}
			
		if (itemSupplyRule.isNew()) {
			itemSupplyRule.setWarehouse(WarehouseHolder.getWarehouse());
		}
		this.store(itemSupplyRule);
	}

	public void deleteItemSupplyRules(List<Long> ids) {
		this.commonDao.deleteAll(this.commonDao.loadAll(ItemSupplyRule.class, ids.toArray(new Long[] {})));
	}

	public void setItemStorageType(List<Long> itemStorageRuleIds, String referTo, String method, String type) {
		for(Long id : itemStorageRuleIds){
			ItemStorageRule rule = this.commonDao.load(ItemStorageRule.class, id);
			if (ItemTypeSetMethod.ItemClass1.equals(method)) {
				type = rule.getItem().getLargeClass();
			} else if (ItemTypeSetMethod.ItemClass2.equals(method)) {
				type = rule.getItem().getCenterClass();
			} else if (ItemTypeSetMethod.ItemClass3.equals(method)) {
				type = rule.getItem().getSmallClass();
			}
			if (StringUtils.isEmpty(type)) {
				type = null;
			}
			
			if ("ABC".equals(referTo)) {
				Long abcType = Long.valueOf(type);
				AbcTypeCountRule atcr = commonDao.load(AbcTypeCountRule.class, abcType);
				rule.setAbcType(atcr);
			} else if ("PUTAWAY".equals(referTo)) {
				rule.setItemPutawayType(type);
			} else if ("PICK".equals(referTo)) {
				rule.setItemPickType(type);
			}
			this.commonDao.store(rule);
		}
	}

	public void storeItemSafeRule(List<Long> ids,Long warehouseId,String minStock,String maxStock) {
		for(Long id:ids){
			ItemStorageRule rule = this.commonDao.load(ItemStorageRule.class, id);
			if (warehouseId != null && warehouseId != 0) {
				rule.setReplenishmentWarehouse(this.commonDao.load(Warehouse.class,warehouseId));
			} else {
				rule.setReplenishmentWarehouse(null);
			}
			rule.setMinStock(Double.valueOf(minStock));
			rule.setMaxStock(Double.valueOf(maxStock));
			this.commonDao.store(rule);
		}
	}

	public void deleteAbcTypeCountRule(List<Long> ids) {
		this.commonDao.deleteAll(this.commonDao.loadAll(AbcTypeCountRule.class, ids.toArray(new Long[] {})));
	}

	public void saveAbcTypeCountRule(AbcTypeCountRule abcTypeCountRule) {
		if (abcTypeCountRule.isNew()) {
			abcTypeCountRule.setWarehouse(WarehouseHolder.getWarehouse());
		}
		this.store(abcTypeCountRule);
	}

	public void setBigTypePutaway(List<Long> ids) {
		for(Long id : ids){
			Item item = this.commonDao.load(Item.class,id);
			for(ItemStorageRule rule : item.getStorageRules()){
				if (rule.getWarehouse().getId().equals(WarehouseHolder.getWarehouse().getId())) {
					if(rule.getItemPutawayType() == null){
						rule.setItemPutawayType(item.getLargeClass());
						this.commonDao.store(rule);
					}
					break;
				}
			}
		}	
	}

	public void setMiddleTypePutaway(List<Long> ids) {
		for(Long id : ids){
			Item item = this.commonDao.load(Item.class,id);
			for(ItemStorageRule rule : item.getStorageRules()){
				if (rule.getWarehouse().getId().equals(WarehouseHolder.getWarehouse().getId())) {
					if(rule.getItemPutawayType() == null){
						rule.setItemPutawayType(item.getCenterClass());
						this.commonDao.store(rule);
					}
					break;
				}
			}
		}
	}

	public void setSmallTypePutaway(List<Long> ids) {
		for(Long id : ids){
			Item item = this.commonDao.load(Item.class,id);
			for(ItemStorageRule rule : item.getStorageRules()){
				if (rule.getWarehouse().getId().equals(WarehouseHolder.getWarehouse().getId())) {
					if(rule.getItemPutawayType() == null){
						rule.setItemPutawayType(item.getSmallClass());
						this.commonDao.store(rule);
					}
					break;
				}
			}
		}
	}

	public void setBigTypePick(List<Long> ids) {
		for(Long id : ids){
			Item item = this.commonDao.load(Item.class,id);
			for(ItemStorageRule rule : item.getStorageRules()){
				if (rule.getWarehouse().getId().equals(WarehouseHolder.getWarehouse().getId())) {
					if(rule.getItemPickType() == null){
						rule.setItemPickType(item.getLargeClass());
						this.commonDao.store(rule);
					}
					break;
				}
			}
		}
	}

	public void setMiddleTypePick(List<Long> ids) {
		for(Long id : ids){
			Item item = this.commonDao.load(Item.class,id);
			for(ItemStorageRule rule : item.getStorageRules()){
				if (rule.getWarehouse().getId().equals(WarehouseHolder.getWarehouse().getId())) {
					if(rule.getItemPickType() == null){
						rule.setItemPickType(item.getCenterClass());
						this.commonDao.store(rule);
					}
					break;
				}
			}
		}
	}

	public void setSmallTypePick(List<Long> ids) {
		for(Long id : ids){
			Item item = this.commonDao.load(Item.class,id);
			for(ItemStorageRule rule : item.getStorageRules()){
				if (rule.getWarehouse().getId().equals(WarehouseHolder.getWarehouse().getId())) {
					if(rule.getItemPickType() == null){
						rule.setItemPickType(item.getSmallClass());
						this.commonDao.store(rule);
					}
					break;
				}
			}
		}
	}

	public void storeCompanyTransRule(CompanyTransRule rule) {
		rule.setWarehouse(WarehouseHolder.getWarehouse());
		this.commonDao.store(rule);
	}

	public void deleteCompanyTransRule(List<Long> ids) {
		for (Long id : ids) {
			CompanyTransRule rule = commonDao.load(CompanyTransRule.class, id);
			commonDao.delete(rule);
		}
	}

	public void deleteCompanyTransRuleDetail(Long ruleId,List<Long> ids) {
		CompanyTransRule rule = this.commonDao.load(CompanyTransRule.class,ruleId);
		for (Long id : ids) {
			CompanyTransRuleDetail detail = commonDao.load(CompanyTransRuleDetail.class, id);
			rule.getDetails().remove(detail);
		}
		this.commonDao.store(rule);
	}

	public void storeCompanyTransRuleDetail(Long ruleId, CompanyTransRuleDetail companyTransRuleDetail) {
		CompanyTransRule rule = this.commonDao.load(CompanyTransRule.class,ruleId);
		if(companyTransRuleDetail.isNew()){
			companyTransRuleDetail.setCompanyTransRule(rule);
			rule.getDetails().add(companyTransRuleDetail);
		}
		this.commonDao.store(companyTransRuleDetail);
		this.commonDao.store(rule);
	}
	
	public void storePresentSaleRule(PresentSaleRule psr,Double quantity,Double presentQty){
		if(psr.isNew()){
			psr.setWarehouse(WarehouseHolder.getWarehouse());
		}
		
		psr.setQuantity(quantity);
		psr.setPresentQty(presentQty);
			
		commonDao.store(psr);
	}
	
	public void deletePresentSalrRules(List<Long> ids){
		for (Long id : ids){
			PresentSaleRule psr  = commonDao.load(PresentSaleRule.class, id);
			commonDao.delete(psr);
		}
	}

	public void saveCompanyWorkRule(CompanyWorkRule rule) {
		if(rule.getLotRule()==null || rule.getLotRule().getId()==null)
			rule.setLotRule(null);
		if (rule.isNew()) {
			rule.setWarehouse(WarehouseHolder.getWarehouse());
		}
		this.commonDao.store(rule);
	}

	public void deleteCompanyWorkRuls(List<Long> ids) {
		for (Long id : ids){
			CompanyWorkRule rule  = commonDao.load(CompanyWorkRule.class, id);
			commonDao.delete(rule);
		}
		
	}

	public void deleteCustomerWorkRuls(List<Long> ids) {
		for (Long id : ids){
			CustomerWorkRule rule  = commonDao.load(CustomerWorkRule.class, id);
			commonDao.delete(rule);
		}
	}

	public void saveCustomerWorkRule(CustomerWorkRule rule) {
		if (rule.isNew()) {
			rule.setWarehouse(WarehouseHolder.getWarehouse());
		}
		this.commonDao.store(rule);
	}

	public void initItemStorageRule() {
		List<Long> itemIds = commonDao.findByQuery(
				"SELECT isr.item.id FROM ItemStorageRule isr WHERE isr.warehouse.id = " + WarehouseHolder.getWarehouse().getId());
		List<Item> items = commonDao.loadAll(Item.class);
		for (Item item : items) {
			if (!itemIds.contains(item.getId())) {
				ItemStorageRule isr = new ItemStorageRule();
				isr.setWarehouse(WarehouseHolder.getWarehouse());
				isr.setItem(item);
				commonDao.store(isr);
			}
		}
	}

	public void adjustAbcType(Long companyId) {
		List<ItemStorageRule> isrs = commonDao.findByQuery(
				"FROM ItemStorageRule isr WHERE isr.warehouse.id = " + WarehouseHolder.getWarehouse().getId()
				+" AND isr.item.company.id = " + companyId);
		for (ItemStorageRule isr : isrs) {
			if (isr.getAbcCountType() != null) {
				isr.setAbcType(isr.getAbcCountType());
			}
		}
	}

	public void analyzeAbcType(Long companyId, Date beginDate, Date endDate) {
		List<AbcTypeCountRule> atcrs = commonDao.findByQuery(
				"FROM AbcTypeCountRule atcr WHERE atcr.warehouse.id = " + WarehouseHolder.getWarehouse().getId()
				+ " AND atcr.company.id = " + companyId + "ORDER BY atcr.lineNo");
		
		String hql = "SELECT new com.dev.swms.server.model.base.ItemShipInfo(bolDetail.itemKey.item.id," +
				" SUM(bolDetail.shipQuantity)," + 
				" SUM(bolDetail.shipQuantity*pu.weight)," + 
				" SUM(bolDetail.shipQuantity*pu.volume))" + 
				" FROM BOLDetail bolDetail" + 
				" LEFT JOIN bolDetail.packageUnit pu" + 
				" LEFT JOIN bolDetail.bol bol" + 
				" LEFT JOIN bolDetail.bol.pickTicket pt" +  
				" WHERE bol.status <> 'OPEN' AND bol.warehouse.id = :warehouseId" + 
				" AND pt.company.id = :companyId" + 
				" AND bol.shipDate >= :beginDate AND bol.shipDate <= :endDate" +
				" GROUP BY bolDetail.itemKey.item.id";

		List<ItemShipInfo> itemShipInfos = commonDao.findByQuery(hql, 
				new String[] {"warehouseId", "companyId", "beginDate", "endDate"}, 
				new Object[] {WarehouseHolder.getWarehouse().getId(), companyId, beginDate, endDate});
		
		List<ItemStorageRule> isrs = commonDao.findByQuery(
				"FROM ItemStorageRule isr WHERE isr.warehouse.id = " + WarehouseHolder.getWarehouse().getId()
				+" AND isr.item.company.id = " + companyId);
		for (ItemStorageRule isr : isrs) {
			for (ItemShipInfo isi : itemShipInfos) {
				if (isi.getItemId().equals(isr.getItem().getId())) {
					isr.setShipQuantity(isi.getShipQuantity());
					isr.setShipWeight(isi.getShipWeight());
					isr.setShipVolume(isi.getShipVolume());
					break;
				}
			}
		}
		Collections.sort(isrs, new ReverseComparator(new BeanComparator("shipVolume")));
		
		Integer itemCount = isrs.size();
		Integer abcCount = 0;
		Integer abcCountN = 0;
		for (int i=0; i<atcrs.size(); i++) {
			AbcTypeCountRule atcr = atcrs.get(i);
			if (i == atcrs.size()-1) {
				abcCount = itemCount - abcCountN;
			} else {
				abcCount = Double.valueOf(Math.floor(itemCount * atcr.getRate() / 100)).intValue();
			}
			
			for (int j=abcCountN; j<abcCountN+abcCount; j++) {
				ItemStorageRule isr = isrs.get(j);
				isr.setAbcCountType(atcr);
				commonDao.store(isr);
			}
			abcCountN += abcCount;
		}
	}

	public void setABCTypeCountRule(ItemStorageRule itemStorageRule) {
		AbcTypeCountRule abcRule = commonDao.load(AbcTypeCountRule.class, itemStorageRule.getAbcType().getId());
		itemStorageRule = commonDao.load(ItemStorageRule.class, itemStorageRule.getId());
		itemStorageRule.setAbcType(abcRule);
	}

}
