content: package jp.aegif.nemaki.businesslogic.impl;
  
  import java.lang.reflect.Field;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import jp.aegif.nemaki.businesslogic.TypeService;
  import jp.aegif.nemaki.dao.ContentDaoService;
  import jp.aegif.nemaki.model.NemakiPropertyDefinition;
  import jp.aegif.nemaki.model.NemakiPropertyDefinitionCore;
  import jp.aegif.nemaki.model.NemakiPropertyDefinitionDetail;
  import jp.aegif.nemaki.model.NemakiTypeDefinition;
  
  import org.apache.chemistry.opencmis.commons.PropertyIds;
  import org.apache.commons.collections4.CollectionUtils;
  
  public class TypeServiceImpl implements TypeService{
  
  	private ContentDaoService contentDaoService;
  
  	public TypeServiceImpl() {
  
  
  	}
  
  	public TypeServiceImpl(ContentDaoService contentDaoService) {
  		setContentDaoService(contentDaoService);
  	}
  
  	@Override
  	public NemakiTypeDefinition getTypeDefinition(String repositoryId, String typeId) {
  		return contentDaoService.getTypeDefinition(repositoryId, typeId);
  	}
  
  	@Override
  	public List<NemakiTypeDefinition> getTypeDefinitions(String repositoryId) {
  		return contentDaoService.getTypeDefinitions(repositoryId);
  	}
  
  	@Override
  	public NemakiPropertyDefinition getPropertyDefinition(String repositoryId, String detailNodeId) {
  		NemakiPropertyDefinitionDetail detail = getPropertyDefinitionDetail(repositoryId, detailNodeId);
  		NemakiPropertyDefinitionCore core = getPropertyDefinitionCore(repositoryId, detail
  				.getCoreNodeId());
  
  		NemakiPropertyDefinition npd = new NemakiPropertyDefinition(core,
  				detail);
  		return npd;
  	}
  
  	@Override
  	public NemakiPropertyDefinitionCore getPropertyDefinitionCore(String repositoryId, String coreId) {
  		return contentDaoService.getPropertyDefinitionCore(repositoryId, coreId);
  	}
  
  	@Override
  	public NemakiPropertyDefinitionCore getPropertyDefinitionCoreByPropertyId(
  			String repositoryId, String propertyId) {
  		return contentDaoService.getPropertyDefinitionCoreByPropertyId(repositoryId, propertyId);
  	}
  
  	@Override
  	public List<NemakiPropertyDefinitionCore> getPropertyDefinitionCores(String repositoryId) {
  		return contentDaoService.getPropertyDefinitionCores(repositoryId);
  	}
  
  	@Override
  	public NemakiPropertyDefinitionDetail getPropertyDefinitionDetail(
  			String repositoryId, String detailId) {
  		return contentDaoService.getPropertyDefinitionDetail(repositoryId, detailId);
  	}
  
  	@Override
  	public List<NemakiPropertyDefinitionDetail> getPropertyDefinitionDetailByCoreNodeId(
  			String repositoryId, String coreNodeId){
  		return contentDaoService.getPropertyDefinitionDetailByCoreNodeId(repositoryId, coreNodeId);
  	}
  
  	@Override
  	public NemakiTypeDefinition createTypeDefinition(
  			String repositoryId, NemakiTypeDefinition typeDefinition) {
  		return contentDaoService.createTypeDefinition(repositoryId, typeDefinition);
  	}
  
  	@Override
  	public NemakiTypeDefinition updateTypeDefinition(
  			String repositoryId, NemakiTypeDefinition typeDefinition) {
  		return contentDaoService.updateTypeDefinition(repositoryId, typeDefinition);
  	}
  
  	@Override
  	public void deleteTypeDefinition(String repositoryId, String typeId) {
  		NemakiTypeDefinition ntd = getTypeDefinition(repositoryId, typeId);
  
  		//Delete unnecessary property definitions
  		List<String> detailIds = ntd.getProperties();
  		for(String detailId : detailIds){
  			NemakiPropertyDefinitionDetail detail = getPropertyDefinitionDetail(repositoryId, detailId);
  			NemakiPropertyDefinitionCore core = getPropertyDefinitionCore(repositoryId, detail.getCoreNodeId());
  			//Delete a detail
  			contentDaoService.delete(repositoryId, detail.getId());
  
  			//Delete a core only if no details exist
  			List<NemakiPropertyDefinitionDetail> l =
  					contentDaoService.getPropertyDefinitionDetailByCoreNodeId(repositoryId, core.getId());
  			if(CollectionUtils.isEmpty(l)){
  				contentDaoService.delete(repositoryId, core.getId());
  			}
  		}
  
  		//Delete the type definition
  		contentDaoService.deleteTypeDefinition(repositoryId, ntd.getId());
  
  	}
  
  	@Override
  	public NemakiPropertyDefinitionDetail createPropertyDefinition(
  			String repositoryId, NemakiPropertyDefinition propertyDefinition) {
  		NemakiPropertyDefinitionCore _core = new NemakiPropertyDefinitionCore(
  				propertyDefinition);
  
  		// Skip creating a core when it exists
  		List<NemakiPropertyDefinitionCore> cores = getPropertyDefinitionCores(repositoryId);
  		Map<String, NemakiPropertyDefinitionCore> corePropertyIds = new HashMap<String, NemakiPropertyDefinitionCore>();
  		for (NemakiPropertyDefinitionCore npdc : cores) {
  			corePropertyIds.put(npdc.getPropertyId(), npdc);
  		}
  		String coreNodeId = "";
  		if (!corePropertyIds.containsKey(_core.getPropertyId())) {
  			//propertyId uniqueness
  			_core.setPropertyId(buildUniquePropertyId(repositoryId, _core.getPropertyId()));
  			// Create a property core
  			NemakiPropertyDefinitionCore core = contentDaoService
  					.createPropertyDefinitionCore(repositoryId, _core);
  			coreNodeId = core.getId();
  		} else {
  			NemakiPropertyDefinitionCore existing = corePropertyIds.get(_core
  					.getPropertyId());
  			coreNodeId = existing.getId();
  		}
  
  		// Create a detail
  		NemakiPropertyDefinitionDetail _detail = new NemakiPropertyDefinitionDetail(
  				propertyDefinition, coreNodeId);
  		NemakiPropertyDefinitionDetail detail = contentDaoService
  				.createPropertyDefinitionDetail(repositoryId, _detail);
  
  		return detail;
  	}
  
  	@Override
  	public NemakiPropertyDefinitionDetail updatePropertyDefinitionDetail(
  			String repositoryId, NemakiPropertyDefinitionDetail propertyDefinitionDetail) {
  		return contentDaoService.updatePropertyDefinitionDetail(repositoryId, propertyDefinitionDetail);
  	}
  
  
  
  
  
  	private String buildUniquePropertyId(String repositoryId, String propertyId){
  		if(isUniquePropertyIdInRepository(repositoryId, propertyId)){
  			return propertyId;
  		}else{
  			return propertyId + "_" + String.valueOf(System.currentTimeMillis());
  		}
  	}
  
  	private boolean isUniquePropertyIdInRepository(String repositoryId, String propertyId){
  		//propertyId uniqueness
  		List<String> list = getSystemPropertyIds();
  		List<NemakiPropertyDefinitionCore>cores = getPropertyDefinitionCores(repositoryId);
  		if(CollectionUtils.isNotEmpty(cores)){
  			for(NemakiPropertyDefinitionCore core: cores){
  				list.add(core.getPropertyId());
  			}
  		}
  
  		return !list.contains(propertyId);
  	}
  
  	/**
  	 * List up specification-default property ids
  	 *
  	 * @return
  	 */
  	private List<String> getSystemPropertyIds() {
  		List<String> ids = new ArrayList<String>();
  
  		Field[] fields = PropertyIds.class.getDeclaredFields();
  		for (Field field : fields) {
  			try {
  				String cmisId = (String) (field.get(null));
  				ids.add(cmisId);
  			} catch (IllegalArgumentException e) {
  				e.printStackTrace();
  			} catch (IllegalAccessException e) {
  				e.printStackTrace();
  			}
  		}
  		return ids;
  	}
  
  	public void setContentDaoService(ContentDaoService contentDaoService) {
  		this.contentDaoService = contentDaoService;
  	}
  
  
  }
  