package org.iri_research.renkan.repositories;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.iri_research.renkan.models.Project;
import org.iri_research.renkan.models.ProjectRevision;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;
import static org.springframework.data.mongodb.core.query.Query.query;
import static org.springframework.data.mongodb.core.query.Criteria.where;

import org.springframework.data.mongodb.core.mapreduce.GroupBy;
import org.springframework.data.mongodb.core.mapreduce.GroupByResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Update;

@Component
public class ProjectsRepositoryImpl implements ProjectsRepositoryCustom {
	
	@Autowired
	private ProjectsRepository projectsRepository;

	@Autowired
	private NodesRepository nodesRepository;

	@Autowired
	private EdgesRepository edgesRepository;
	
	@Autowired
	private ProjectRevisionsRepository projectRevisionsRepository;

	
	private class GroupResult {
		public String space_id;
		public int count;		
	}
	
	@Autowired
	private MongoTemplate mongoTemplate;
	
	@Override
	public int getRevCounter(String projectId)  {		
		Project p = this.mongoTemplate.findAndModify(query(where("id").is(projectId)), new Update().inc("rev_counter", 1), Project.class);
		
		if(p == null) {
			return -1;
		}
		return p.getRevCounter();
	}
	

	@Override
	public Map<String, Integer> getCountBySpace(Collection<String> spaceIds) {

		Criteria filter = null;
		
		if(spaceIds != null) {
			filter = Criteria.where("space_id").in(spaceIds);
		}
		
		GroupByResults<GroupResult> groupResult = this.mongoTemplate.group(
				filter,
				this.mongoTemplate.getCollectionName(Project.class),
				GroupBy.key("space_id").initialDocument("{ count: 0 }").reduceFunction("function(doc, prev) { prev.count += 1; }"),
				GroupResult.class);
		
		HashMap<String, Integer> res = new HashMap<>();
		for (GroupResult gr : groupResult) {
			res.put(gr.space_id, new Integer(gr.count));
		}
		
		return res;
		
	}
	
	@Override
	public Map<String, Integer> getCountBySpace() {
		return this.getCountBySpace(null);
	}


	@Override
	public Project copy(Project p, String newTitle) {
		
		Project res = new Project(p);
		res.setTitle(newTitle);
		this.nodesRepository.save(res.getNodes());
		this.edgesRepository.save(res.getEdges());
		
		return this.projectsRepository.save(res);
	}

	@Override
	public void deleteRecursive(String projectId) {		
		this.deleteRecursive(this.projectsRepository.findOne(projectId));		
	}

	@Override
	public void deleteRecursive(Project project) {
		this.deleteRecursive(Arrays.asList(new Project[] {project}));
	}

	@Override
	public void deleteRecursive(Iterable<? extends Project> projects) {
		
		for(Project p: projects) {
			if( p == null) {
				continue;
			}
			
			ProjectRevision pr = this.projectRevisionsRepository.getProjectRevision(p, this.projectsRepository.getRevCounter(p.getId()));
			this.projectRevisionsRepository.save(pr);
			
			//delete edges
			this.edgesRepository.delete(p.getEdges());
			//delete nodes
			this.nodesRepository.delete(p.getNodes());
			//delete project
			this.projectsRepository.delete(p);
		}
	}
}
