package com.salesmanager.core.business.services.catalog.category;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import com.salesmanager.core.business.constants.Constants;
import com.salesmanager.core.business.exception.ServiceException;
import com.salesmanager.core.business.repositories.catalog.category.CategoryRepository;
import com.salesmanager.core.business.services.catalog.product.ProductService;
import com.salesmanager.core.business.services.common.generic.SalesManagerEntityServiceImpl;
import com.salesmanager.core.model.catalog.category.Category;
import com.salesmanager.core.model.catalog.category.CategoryDescription;
import com.salesmanager.core.model.catalog.product.Product;
import com.salesmanager.core.model.merchant.MerchantStore;
import com.salesmanager.core.model.reference.language.Language;
@Service("categoryService")
public class CategoryServiceImpl extends SalesManagerEntityServiceImpl<Long, Category> implements CategoryService {
private CategoryRepository categoryRepository;
@PersistenceContext(unitName = "shopizerContainer")
private EntityManager em;
@Inject
private ProductService productService;
@Inject
public CategoryServiceImpl(CategoryRepository categoryRepository) {
super(categoryRepository);
this.categoryRepository = categoryRepository;
}
public void create(Category category) throws ServiceException {
super.create(category);
StringBuilder lineage = new StringBuilder();
Category parent = category.getParent();
if(parent!=null && parent.getId()!=null && parent.getId()!=0) {
lineage.append(parent.getLineage()).append("/").append(parent.getId());
category.setDepth(parent.getDepth()+1);
} else {
lineage.append("/");
category.setDepth(0);
}
category.setLineage(lineage.toString());
super.update(category);
}
@Override
public List<Object[]> countProductsByCategories(MerchantStore store,
List<Long> categoryIds) throws ServiceException {
return categoryRepository.countProductsByCategories(store, categoryIds);
}
@Override
public List<Category> listByCodes(MerchantStore store, List<String> codes,
Language language) {
return categoryRepository.findByCodes(store.getId(), codes, language.getId());
}
@Override
public List<Category> listByIds(MerchantStore store, List<Long> ids,
Language language) {
return categoryRepository.findByIds(store.getId(), ids, language.getId());
}
@Override
public Category getByLanguage(long categoryId, Language language) {
return categoryRepository.findById(categoryId, language.getId());
}
@Override
public void saveOrUpdate(Category category) throws ServiceException {
//save or update (persist and attach entities
if(category.getId()!=null && category.getId()>0) {
super.update(category);
} else {
super.save(category);
}
}
@Override
public List<Category> listByLineage(MerchantStore store, String lineage) throws ServiceException {
try {
return categoryRepository.findByLineage(store.getId(), lineage);
} catch (Exception e) {
throw new ServiceException(e);
}
}
@Override
public List<Category> listByLineage(String storeCode, String lineage) throws ServiceException {
try {
return categoryRepository.findByLineage(storeCode, lineage);
} catch (Exception e) {
throw new ServiceException(e);
}
}
@Override
public List<Category> listBySeUrl(MerchantStore store, String seUrl) throws ServiceException{
try {
return categoryRepository.listByFriendlyUrl(store.getId(), seUrl);
} catch (Exception e) {
throw new ServiceException(e);
}
}
@Override
public Category getBySeUrl(MerchantStore store,String seUrl) {
return categoryRepository.findByFriendlyUrl(store.getId(), seUrl);
}
@Override
public Category getByCode(MerchantStore store, String code) throws ServiceException {
try {
return categoryRepository.findByCode(store.getId(), code);
} catch (Exception e) {
throw new ServiceException(e);
}
}
@Override
public Category getByCode(String storeCode, String code) throws ServiceException {
try {
return categoryRepository.findByCode(storeCode, code);
} catch (Exception e) {
throw new ServiceException(e);
}
}
@Override
public Category getById(Long id) {
return categoryRepository.findOne(id);
}
@Override
public List<Category> listByParent(Category category) throws ServiceException {
try {
return categoryRepository.listByStoreAndParent(null, category);
} catch (Exception e) {
throw new ServiceException(e);
}
}
@Override
public List<Category> listByStoreAndParent(MerchantStore store, Category category) throws ServiceException {
try {
return categoryRepository.listByStoreAndParent(store, category);
} catch (Exception e) {
throw new ServiceException(e);
}
}
@Override
public List<Category> listByParent(Category category, Language language) {
Assert.notNull(category, "Category cannot be null");
Assert.notNull(language, "Language cannot be null");
Assert.notNull(category.getMerchantStore(), "category.merchantStore cannot be null");
return categoryRepository.findByParent(category.getId(), language.getId());
}
@Override
public void addCategoryDescription(Category category, CategoryDescription description)
throws ServiceException {
try {
category.getDescriptions().add(description);
description.setCategory(category);
update(category);
} catch (Exception e) {
throw new ServiceException(e);
}
}
//@Override
public void delete(Category category) throws ServiceException {
//get category with lineage (subcategories)
StringBuilder lineage = new StringBuilder();
lineage.append(category.getLineage()).append(category.getId()).append(Constants.SLASH);
List<Category> categories = this.listByLineage(category.getMerchantStore(), lineage.toString());
Category dbCategory = this.getById( category.getId() );
if(dbCategory != null && dbCategory.getId().longValue() == category.getId().longValue() ) {
categories.add(dbCategory);
Collections.reverse(categories);
List<Long> categoryIds = new ArrayList<Long>();
for(Category c : categories) {
categoryIds.add(c.getId());
}
List<Product> products = productService.getProducts(categoryIds);
org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);//need to refresh the session to update all product categories
for(Product product : products) {
session.evict(product);//refresh product so we get all product categories
Product dbProduct = productService.getById(product.getId());
Set<Category> productCategories = dbProduct.getCategories();
if(productCategories.size()>1) {
for(Category c : categories) {
productCategories.remove(c);
productService.update(dbProduct);
}
if(product.getCategories()==null || product.getCategories().size()==0) {
productService.delete(dbProduct);
}
} else {
productService.delete(dbProduct);
}
}
Category categ = this.getById(category.getId());
categoryRepository.delete(categ);
}
}
@Override
public CategoryDescription getDescription(Category category, Language language) {
for (CategoryDescription description : category.getDescriptions()) {
if (description.getLanguage().equals(language)) {
return description;
}
}
return null;
}
@Override
public void addChild(Category parent, Category child) throws ServiceException {
if(child==null || child.getMerchantStore()==null) {
throw new ServiceException("Child category and merchant store should not be null");
}
try {
if(parent==null) {
//assign to root
child.setParent(null);
child.setDepth(0);
//child.setLineage(new StringBuilder().append("/").append(child.getId()).append("/").toString());
child.setLineage("/");
} else {
Category p = this.getById(parent.getId());//parent
String lineage = p.getLineage();
int depth = p.getDepth();//TODO sometimes null
child.setParent(p);
child.setDepth(depth+1);
child.setLineage(new StringBuilder().append(lineage).append(p.getId()).append("/").toString());
}
update(child);
StringBuilder childLineage = new StringBuilder();
childLineage.append(child.getLineage()).append(child.getId()).append("/");
List<Category> subCategories = listByLineage(child.getMerchantStore(),childLineage.toString());
//ajust all sub categories lineages
if(subCategories!=null && subCategories.size()>0) {
for(Category subCategory : subCategories) {
if(child.getId()!=subCategory.getId()) {
addChild(child, subCategory);
}
}
}
} catch (Exception e) {
throw new ServiceException(e);
}
}
@Override
public List<Category> listByDepth(MerchantStore store, int depth) {
return categoryRepository.findByDepth(store.getId(), depth);
}
@Override
public List<Category> listByDepth(MerchantStore store, int depth, Language language) {
return categoryRepository.findByDepth(store.getId(), depth, language.getId());
}
@Override
public List<Category> getByName(MerchantStore store, String name, Language language) throws ServiceException {
try {
return categoryRepository.findByName(store.getId(), name, language.getId());
} catch (Exception e) {
throw new ServiceException(e);
}
}
@Override
public List<Category> listByStore(MerchantStore store)
throws ServiceException {
try {
return categoryRepository.findByStore(store.getId());
} catch (Exception e) {
throw new ServiceException(e);
}
}
@Override
public List<Category> listByStore(MerchantStore store, Language language)
throws ServiceException {
try {
return categoryRepository.findByStore(store.getId(), language.getId());
} catch (Exception e) {
throw new ServiceException(e);
}
}
}