package com.mason.server.controller;

import java.security.Principal;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.mason.server.model.DbUser;
import com.mason.server.model.Log;
import com.mason.server.model.Project;
import com.mason.server.model.ProjectAccess;
import com.mason.server.dao.jdo.LogDAO;
import com.mason.server.dao.jdo.ProjectAccessDAO;
import com.mason.server.dao.jdo.ProjectDAO;
import com.mason.server.dao.jdo.UserDAO;
import com.mason.server.exception.ResourceNotFoundException;
import com.mason.server.validator.ProjectValidator;

@Controller
@RequestMapping("/{usernameSlug}")
public class ProjectController { 

	private static ProjectDAO projectDAO = new ProjectDAO();
	private static UserDAO userDAO = new UserDAO();
	private static LogDAO logDAO = new LogDAO();
	private static ProjectAccessDAO projectAccessDAO = new ProjectAccessDAO();

	@RequestMapping(value = "/project/add", method = RequestMethod.GET)
	public String getProjectAddPage(ModelMap model) {
		model.addAttribute(new Project());
		return "project/projectAdd";
	}

	@RequestMapping(value = "/project/add", method = RequestMethod.POST)
	public String add(@PathVariable String usernameSlug, Project project, BindingResult result) {

		ProjectValidator pv = new ProjectValidator();
		pv.validate(project, result);

		if (result.hasErrors()) {
			return "projectAdd";
		}

		project = processProject(project, usernameSlug);

		project = projectDAO.add(project);
		
		ProjectAccess pa = new ProjectAccess();
		pa.setUserId(userDAO.getByUsername(usernameSlug).getId());
		pa.setProjectId(project.getId());
		pa.setRole(ProjectAccess.Role.OWNER);
		
		projectAccessDAO.add(pa);
		logDAO.add(new Log(project.getId(), Project.class.getSimpleName(),
				Log.Action.CREATE));
		return "redirect:/" + usernameSlug ;
	}
	

	private Project processProject(Project project, String username) {
		// instellen van de owner
		project.setOwnerId(userDAO.getByUsername(username).getId());

		// description trimming
		project.setDescription(project.getDescription().trim());

		// process slug
		int i = 1;
		String description = project.getDescription().toLowerCase()
				.replaceAll(" ", "_");
		String slug = description;
		Project p = projectDAO.getBySlug(slug, project.getOwnerId());
		while (p != null && p.getId() != project.getId()) {
			slug = description + i;
			i++;
			project = projectDAO.getBySlug(slug, project.getOwnerId());
		}
		project.setSlug(slug);
		return project;
	}

	@RequestMapping(value = "/{projectSlug}/update", method = RequestMethod.GET)
	public String getProjectUpdatePage(@PathVariable String usernameSlug,
			@PathVariable String projectSlug, ModelMap model, Principal principal) {

		DbUser user = userDAO.getByUsername(principal.getName());
		Project p = getProjectBySlug(projectSlug, user.getId());
		ProjectAccess pa = projectAccessDAO.getAccessUserToProject(p.getId(), user.getId());
		
		if (pa == null || pa.getRole() == ProjectAccess.Role.NONE ) {
			return "redirect:/denied";
		}
		
		model.addAttribute("project", ProjectController.projectDAO.getBySlug(
				projectSlug, userDAO.getByUsername(usernameSlug).getId()));
		return "project/projectUpdate";
	}

	@RequestMapping(value = "/{projectSlug}/update", method = RequestMethod.POST)
	public String update(@PathVariable String usernameSlug, Project project,
			ModelMap model, BindingResult result, Principal principal) {

		if (project == null) {
			throw new ResourceNotFoundException("project: " + usernameSlug);
		}

		DbUser user = userDAO.getByUsername(principal.getName());
		ProjectAccess pa = projectAccessDAO.getAccessUserToProject(project.getId(), user.getId());
		
		if (pa == null || pa.getRole() == ProjectAccess.Role.NONE ) {
			return "redirect:/denied";
		}

		ProjectValidator pv = new ProjectValidator();
		pv.validate(project, result);

		if (result.hasErrors()) {
			return "projectUpdate";
		}

		project = processProject(project, usernameSlug);

		project = projectDAO.update(project);

		logDAO.add(new Log(project.getId(), Project.class.getSimpleName(),
				Log.Action.UPDATE));

		return "redirect:/" + usernameSlug ;
	}

	@RequestMapping(value = "/{projectSlug}/delete", method = RequestMethod.GET)
	public String getProjectDeletePage(@PathVariable String usernameSlug,
			@PathVariable String projectSlug, Model model, Principal principal) {

		DbUser user = userDAO.getByUsername(principal.getName());
		Project p = getProjectBySlug(projectSlug, user.getId());
		ProjectAccess pa = projectAccessDAO.getAccessUserToProject(p.getId(), user.getId());
		
		if (pa == null || pa.getRole() == ProjectAccess.Role.NONE ) {
			return "redirect:/denied";
		}
		
		model.addAttribute("project", ProjectController.projectDAO.getBySlug(
				projectSlug, userDAO.getByUsername(usernameSlug).getId()));
		return "project/projectDelete";
	}

	@RequestMapping(value = "/{projectSlug}/delete", method = RequestMethod.POST)
	public String delete(@PathVariable String usernameSlug,
			@PathVariable String projectSlug, Model model, Principal principal) {

		DbUser user = userDAO.getByUsername(principal.getName());
		Project p = getProjectBySlug(projectSlug, user.getId());
		ProjectAccess pa = projectAccessDAO.getAccessUserToProject(p.getId(), user.getId());
		
		if (pa == null || pa.getRole() == ProjectAccess.Role.NONE ) {
			return "redirect:/denied";
		}
		
		Project project = projectDAO.getBySlug(projectSlug, userDAO
				.getByUsername(usernameSlug).getId());
		projectDAO.delete(project);
		logDAO.add(new Log(project.getId(), Project.class.getSimpleName(),
				Log.Action.DELETE));
		projectAccessDAO.deleteAllByProjectId(project.getId());
		return "redirect:/" + usernameSlug ;
	}

	@RequestMapping(value = "/{projectSlug}/access/set", method = RequestMethod.POST)
	public String add(@PathVariable String usernameSlug, @PathVariable String projectSlug, ProjectAccess projectAccess, BindingResult result, Principal principal) {

		//aangemelde gebruiker
		DbUser loggedInUser = userDAO.getByUsername(principal.getName()); 
		
		//eigenaar van het project
		DbUser ownerUser = userDAO.getByUsername(usernameSlug); 
		
		//Project
		Project project = getProjectBySlug(projectSlug, ownerUser.getId()); 
		ProjectAccess pa = projectAccessDAO.getAccessUserToProject(project.getId(), loggedInUser.getId());
		
		//controle als aangemelde gebruiker rechten geeft
		if (pa == null || pa.getRole() == ProjectAccess.Role.NONE ) {
			return "redirect:/denied";
		}

		//gebruiker aan wie de rechten gegeven worden
		DbUser user = userDAO.getByUsername(projectAccess.getUsername()); 

		//controle als de gebruiker wel bestaat
		if (user == null) {
			return "projectAccess/projectAccessOverview";
		}
		
		//ophalen van de rechten van deze gebruiker voor dit project
		pa = projectAccessDAO.getAccessUserToProject(project.getId(), user.getId());
		
		//als de gebruiker nog geen rechten geeft binnen dit project, dan nieuwe rechten aanmaken
		if (pa == null && projectAccess.getRole() != ProjectAccess.Role.NONE) {
			System.out.println("new role");
			projectAccess.setUserId(user.getId());
			projectAccess = projectAccessDAO.add(projectAccess);
			logDAO.add(new Log(projectAccess.getId(), ProjectAccess.class.getSimpleName(),
					Log.Action.UPDATE));
		} else {
			//rechten niet aanpassen als de gebruiker eigenaar is van het project
			if (pa.getRole() != ProjectAccess.Role.OWNER ) {
				if (projectAccess.getRole() == ProjectAccess.Role.NONE) {
					System.out.println("delete role");
					System.out.println(pa.getId());
					if (projectAccessDAO.deleteById(pa.getId()) ) {
						System.out.println("ok");
					}
					logDAO.add(new Log(pa.getId(), ProjectAccess.class.getSimpleName(),
							Log.Action.DELETE));
				} else {
					System.out.println("update role");
					pa.setRole(projectAccess.getRole());
					projectAccess = projectAccessDAO.update(pa);
					logDAO.add(new Log(pa.getId(), ProjectAccess.class.getSimpleName(),
							Log.Action.UPDATE));
				}

			}
		}
		
		return "redirect:/" + usernameSlug + "/" + projectSlug + "/access";
	}

	public static Project getProjectBySlug(String projectSlug, long ownerId) {
		Project p = projectDAO.getBySlug(projectSlug, ownerId);

		if (p == null) {
			throw new ResourceNotFoundException("Project:" + projectSlug
					+ " OwnerId:" + ownerId);
		}

		return p;
	}

}