/*******************************************************************************
 * Copyright (c) 2015 Stichting Yona Foundation This Source Code Form is subject to the terms of the Mozilla Public License, v.
 * 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
 *******************************************************************************/
package nu.yona.server.goals.service;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import nu.yona.server.goals.entities.ActivityCategory;

@Service
public class ActivityCategoryService
{
	private static final Logger logger = LoggerFactory.getLogger(ActivityCategoryService.class);

	public ActivityCategoryDTO getActivityCategory(UUID id)
	{
		ActivityCategory activityCategoryEntity = getEntityByID(id);
		return ActivityCategoryDTO.createInstance(activityCategoryEntity);
	}

	@Cacheable(value = "activityCategorySet", key = "instance")
	public Set<ActivityCategoryDTO> getAllActivityCategories()
	{
		Set<ActivityCategoryDTO> activityCategories = new HashSet<ActivityCategoryDTO>();
		for (ActivityCategory activityCategory : ActivityCategory.getRepository().findAll())
		{
			activityCategories.add(ActivityCategoryDTO.createInstance(activityCategory));
		}
		return activityCategories;
	}

	@CacheEvict(value = "activityCategorySet", key = "instance")
	@Transactional
	public ActivityCategoryDTO addActivityCategory(ActivityCategoryDTO activityCategoryDTO)
	{
		logger.info("Adding activity category '{}'", activityCategoryDTO.getName());
		return ActivityCategoryDTO
				.createInstance(ActivityCategory.getRepository().save(activityCategoryDTO.createActivityCategoryEntity()));
	}

	@CacheEvict(value = "activityCategorySet", key = "instance")
	@Transactional
	public ActivityCategoryDTO updateActivityCategory(UUID id, ActivityCategoryDTO activityCategoryDTO)
	{
		ActivityCategory originalEntity = getEntityByID(id);
		return ActivityCategoryDTO.createInstance(updateActivityCategory(originalEntity, activityCategoryDTO));
	}

	private ActivityCategory updateActivityCategory(ActivityCategory activityCategoryTargetEntity,
			ActivityCategoryDTO activityCategorySourceDTO)
	{
		logger.info("Updating activity category '{}'", activityCategorySourceDTO.getName());
		return ActivityCategory.getRepository()
				.save(activityCategorySourceDTO.updateActivityCategory(activityCategoryTargetEntity));
	}

	@CacheEvict(value = "activityCategorySet", key = "instance")
	@Transactional
	public void deleteActivityCategory(UUID id)
	{
		ActivityCategory.getRepository().delete(id);
	}

	private void deleteActivityCategory(ActivityCategory activityCategoryEntity)
	{
		logger.info("Deleting activity category '{}'", activityCategoryEntity.getName());
		ActivityCategory.getRepository().delete(activityCategoryEntity);
	}

	private ActivityCategory getEntityByID(UUID id)
	{
		ActivityCategory entity = ActivityCategory.getRepository().findOne(id);
		if (entity == null)
		{
			throw ActivityCategoryNotFoundException.notFound(id);
		}
		return entity;
	}

	private Set<ActivityCategory> getAllActivityCategoryEntities()
	{
		Set<ActivityCategory> activityCategories = new HashSet<ActivityCategory>();
		for (ActivityCategory activityCategory : ActivityCategory.getRepository().findAll())
		{
			activityCategories.add(activityCategory);
		}
		return activityCategories;
	}

	@CachePut(value = "activityCategorySet", key = "instance")
	@Transactional
	public void importActivityCategories(Set<ActivityCategoryDTO> activityCategoryDTOs)
	{
		Set<ActivityCategory> activityCategoriesInRepository = getAllActivityCategoryEntities();
		deleteRemovedActivityCategories(activityCategoriesInRepository, activityCategoryDTOs);
		addOrUpdateNewActivityCategories(activityCategoryDTOs, activityCategoriesInRepository);
	}

	private void addOrUpdateNewActivityCategories(Set<ActivityCategoryDTO> activityCategoryDTOs,
			Set<ActivityCategory> activityCategoriesInRepository)
	{
		Map<String, ActivityCategory> activityCategoriesInRepositoryMap = activityCategoriesInRepository.stream()
				.collect(Collectors.toMap(ac -> ac.getName(), ac -> ac));

		for (ActivityCategoryDTO activityCategoryDTO : activityCategoryDTOs)
		{
			ActivityCategory activityCategoryInRepository = activityCategoriesInRepositoryMap.get(activityCategoryDTO.getName());
			if (activityCategoryInRepository == null)
			{
				addActivityCategory(activityCategoryDTO);
			}
			else
			{
				if (!activityCategoryInRepository.getSmoothwallCategories().equals(activityCategoryDTO.getSmoothwallCategories()))
				{
					updateActivityCategory(activityCategoryInRepository, activityCategoryDTO);
				}
			}
		}
	}

	private void deleteRemovedActivityCategories(Set<ActivityCategory> activityCategoriesInRepository,
			Set<ActivityCategoryDTO> activityCategoryDTOs)
	{
		Map<String, ActivityCategoryDTO> activityCategoryDTOsMap = activityCategoryDTOs.stream()
				.collect(Collectors.toMap(ac -> ac.getName(), ac -> ac));

		activityCategoriesInRepository.stream().filter(ac -> !activityCategoryDTOsMap.containsKey(ac.getName()))
				.forEach(this::deleteActivityCategory);
	}
}

@@ -1346,32 +1346,33 @@
 et%22, key = %22
+'
 instance
 %22)%0A%09public S
@@ -1355,24 +1355,25 @@
 = %22'instance
+'
 %22)%0A%09public S
@@ -1766,32 +1766,33 @@
 et%22, key = %22
+'
 instance
 %22)%0A%09@Transac
@@ -1771,32 +1771,33 @@
 key = %22'instance
+'
 %22)%0A%09@Transaction
@@ -2162,32 +2162,33 @@
 et%22, key = %22
+'
 instance
 %22)%0A%09@Transac
@@ -2167,32 +2167,33 @@
 key = %22'instance
+'
 %22)%0A%09@Transaction
@@ -2884,32 +2884,33 @@
 et%22, key = %22
+'
 instance
 %22)%0A%09@Transac
@@ -2889,32 +2889,33 @@
 key = %22'instance
+'
 %22)%0A%09@Transaction
@@ -3853,24 +3853,25 @@
  key = %22
+'
 instance
 %22)%0A%09@Tra
@@ -3862,16 +3862,17 @@
 instance
+'
 %22)%0A%09@Tra

YD-143 Fix key expression