/*
 * Copyright 2016 EPAM Systems
 * 
 * 
 * This file is part of EPAM Report Portal.
 * https://github.com/epam/ReportPortal
 * 
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Report Portal is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */ 

package com.epam.ta.reportportal.core.item.history;

import static com.epam.ta.reportportal.ws.model.ErrorType.TEST_ITEM_NOT_FOUND;
import static com.epam.ta.reportportal.ws.model.ErrorType.UNABLE_LOAD_TEST_ITEM_HISTORY;
import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MAX_HISTORY_DEPTH_BOUND;
import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MAX_HISTORY_SIZE_BOUND;
import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MIN_HISTORY_DEPTH_BOUND;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import com.epam.ta.reportportal.commons.DbUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.epam.ta.reportportal.commons.Predicates;
import com.epam.ta.reportportal.commons.validation.BusinessRule;
import com.epam.ta.reportportal.database.dao.ProjectRepository;
import com.epam.ta.reportportal.database.dao.TestItemRepository;
import com.epam.ta.reportportal.database.entity.Launch;
import com.epam.ta.reportportal.database.entity.Project;
import com.epam.ta.reportportal.database.entity.item.TestItem;
import com.epam.ta.reportportal.ws.converter.builders.TestItemResourceBuilder;
import com.epam.ta.reportportal.ws.model.ErrorType;
import com.epam.ta.reportportal.ws.model.TestItemHistoryElement;
import com.epam.ta.reportportal.ws.model.TestItemResource;
import com.google.common.collect.Lists;

/**
 * Default implementation of {@link TestItemsHistoryHandler}.
 * 
 * @author Aliaksei_Makayed
 * 
 */
@Service
public class TestItemsHistoryHandlerImpl implements TestItemsHistoryHandler {

	private TestItemRepository testItemRepository;

	private ProjectRepository projectRepository;

	private TestItemResourceBuilder itemBuilder;

	private ITestItemsHistoryService historyServiceStrategy;

	@Autowired
	public void setTestItemRepository(TestItemRepository testItemRepository) {
		this.testItemRepository = testItemRepository;
	}

	@Autowired
	public void setProjectRepository(ProjectRepository projectRepository) {
		this.projectRepository = projectRepository;
	}

	@Autowired
	public void setItemBuilder(TestItemResourceBuilder itemBuilder) {
		this.itemBuilder = itemBuilder;
	}

	@Autowired
	public void setTestItemHistoryService(ITestItemsHistoryService testItemHistoryService) {
		this.historyServiceStrategy = testItemHistoryService;
	}

	@Override
	public List<TestItemHistoryElement> getItemsHistory(String projectName, String[] startPointsIds, int historyDepth,
			boolean showBrokenLaunches) {

		Project project = projectRepository.findOne(projectName);
		BusinessRule.expect(project, Predicates.notNull()).verify(ErrorType.PROJECT_NOT_FOUND, projectName);

		Predicate<Integer> greaterThan = t -> t > MIN_HISTORY_DEPTH_BOUND;
		Predicate<Integer> lessThan = t -> t < MAX_HISTORY_DEPTH_BOUND;
		String historyDepthMessage = "Items history depth should be greater than '" + MIN_HISTORY_DEPTH_BOUND + "' and lower than '"
				+ MAX_HISTORY_DEPTH_BOUND + "'";
		BusinessRule.expect(historyDepth, greaterThan.and(lessThan)).verify(UNABLE_LOAD_TEST_ITEM_HISTORY, historyDepthMessage);

		BusinessRule.expect(startPointsIds.length, t -> t < MAX_HISTORY_SIZE_BOUND).verify(UNABLE_LOAD_TEST_ITEM_HISTORY,
				"History size should be less than '" + MAX_HISTORY_SIZE_BOUND + "' test items.");

		List<String> listIds = Lists.newArrayList(startPointsIds);

		List<TestItem> itemsForHistory = historyServiceStrategy.loadItems(listIds);
		historyServiceStrategy.validateItems(itemsForHistory, listIds, projectName);

		List<Launch> launches = historyServiceStrategy.loadLaunches(historyDepth, itemsForHistory.get(0).getLaunchRef(), projectName,
				showBrokenLaunches);
		List<String> historyLaunchesIds = DbUtils.toIds(launches);

		List<TestItem> history = testItemRepository.loadItemsHistory(itemsForHistory, historyLaunchesIds,
				loadParentIds(itemsForHistory.get(0), historyLaunchesIds));

		Map<String, List<TestItem>> groupedItems = history.stream().collect(Collectors.groupingBy(TestItem::getLaunchRef));
		return launches.stream()
				.map(launch -> buildHistoryElement(launch, groupedItems.get(launch.getId()))).collect(Collectors.toList());
	}

	TestItemHistoryElement buildHistoryElement(Launch launch, List<TestItem> testItems) {
		List<TestItemResource> resources = new ArrayList<>();
		if (testItems != null) {
			resources = testItems.stream().map(item -> itemBuilder.addTestItem(item, launch.getStatus().name()).build())
					.collect(Collectors.toList());
		}
		TestItemHistoryElement testItemHistoryElement = new TestItemHistoryElement();
		testItemHistoryElement.setLaunchId(launch.getId());
		testItemHistoryElement.setLaunchNumber(launch.getNumber().toString());
		testItemHistoryElement.setStartTime(String.valueOf(launch.getStartTime().getTime()));
		testItemHistoryElement.setResources(resources);
		testItemHistoryElement.setLaunchStatus(launch.getStatus().name());
		return testItemHistoryElement;
	}

	private List<String> loadParentIds(TestItem testItem, List<String> launchesIds) {
		// root item doesn't have parents
		if (testItem == null || testItem.getParent() == null) {
			return null;
		}
		TestItem parent = testItemRepository.findOne(testItem.getParent());
		BusinessRule.expect(parent, Predicates.notNull()).verify(TEST_ITEM_NOT_FOUND,
				"Unable to find parent for '" + testItem.getId() + "' with ID '" + parent.getId() + "'.");
		List<TestItem> history = testItemRepository.loadItemsHistory(Lists.newArrayList(parent), launchesIds, null);
		return DbUtils.toIds(history);
	}
}
@@ -777,18 +777,17 @@
 s/%3E.%0A */
- 
 %0A
+
 %0Apackage
@@ -1074,220 +1074,9 @@
 nts.
-MAX_HISTORY_DEPTH_BOUND;%0Aimport static com.epam.ta.reportportal.ws.model.ValidationConstraints.MAX_HISTORY_SIZE_BOUND;%0Aimport static com.epam.ta.reportportal.ws.model.ValidationConstraints.MIN_HISTORY_DEPTH_BOUND
+*
 ;%0A%0Ai
@@ -1225,57 +1225,8 @@
 s;%0A%0A
-import com.epam.ta.reportportal.commons.DbUtils;%0A
 impo
@@ -1332,16 +1332,65 @@
 rvice;%0A%0A
+import com.epam.ta.reportportal.commons.DbUtils;%0A
 import c
@@ -4744,21 +4744,16 @@
 stream()
-%0A%09%09%09%09
 .map(lau
@@ -6051,20 +6051,26 @@
 %22 + 
-parent.getId
+testItem.getParent
 () +

Fix npe