package de.thomasjacob.improve.presentation.issue.edit;

import de.thomasjacob.improve.logic.DaoLocator;
import de.thomasjacob.improve.logic.issue.HistoryEntry;
import de.thomasjacob.improve.logic.issue.Issue;
import de.thomasjacob.improve.logic.issue.IssueDao;
import de.thomasjacob.improve.logic.issue.NotificationMailer;
import de.thomasjacob.improve.logic.project.Project;
import de.thomasjacob.improve.logic.project.ProjectDao;
import de.thomasjacob.improve.logic.user.User;
import de.thomasjacob.improve.logic.user.UserDao;
import de.thomasjacob.improve.presentation.ImproveAction;
import de.thomasjacob.improve.presentation.login.LoginManager;
import de.thomasjacob.webcore.TechnicalException;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;


public class IssueRHAction extends ImproveAction
{
	/*
	 * (non-Javadoc)
	 *
	 * @see de.thomasjacob.webcore.presentation.BaseAction#executeChecked(org.apache.struts.action.ActionMapping,
	 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest,
	 * javax.servlet.http.HttpServletResponse)
	 */
	protected ActionForward executeChecked(ActionMapping mapping, ActionForm form, HttpServletRequest request,
		HttpServletResponse response) throws TechnicalException
	{
		HttpSession session = request.getSession();

		User loggedInUser = LoginManager.getInstance(session).getUser();
		if (loggedInUser == null)
		{
			return mapping.findForward("login");
		}

		IssueForm issueForm = (IssueForm) form;
		int issueId = issueForm.getIssueId().equals("") ? 0 : Integer.parseInt(issueForm.getIssueId());

		if (request.getParameter("Save") != null)
		{
			if (!validateAndAddErrors(form, request, mapping).isEmpty())
			{
				request.setAttribute("doNotLoad", Boolean.TRUE);
				return mapping.findForward("details");
			}

			if (issueId != 0 && issueForm.getDeveloperId().equals("0"))
			{
				getActionErrors(request)
					.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("IssueRHAction.userRequired"));
				request.setAttribute("doNotLoad", Boolean.TRUE);
				return mapping.findForward("details");
			}

			if (issueId != 0 && issueForm.getComment().equals(""))
			{
				getActionErrors(request)
					.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("IssueRHAction.commentRequired"));
				request.setAttribute("doNotLoad", Boolean.TRUE);
				return mapping.findForward("details");
			}

			IssueDao issueDao = DaoLocator.getInstance().getIssueDao();
			ProjectDao projectDao = DaoLocator.getInstance().getProjectDao();
			UserDao userDao = DaoLocator.getInstance().getUserDao();

			Issue issue = null;
			if (issueId == 0)
			{
				issue = new Issue();
			}
			else
			{
				issue = issueDao.getIssueById(issueId);
			}

			Project project = projectDao.getProjectById(Integer.parseInt(issueForm.getProjectId()));
			boolean mayEdit = issue.getId() == 0 ? loggedInUser.mayReportIssue(project) : loggedInUser
				.mayEditIssue(project);
			boolean mayProcess = loggedInUser.mayProcess(issue, false);

			User developer;
			if (!issueForm.getDeveloperId().equals(""))
			{
				developer = userDao.getUserById(Integer.parseInt(issueForm.getDeveloperId()));
				if (mayEdit && !developer.mayProcess(issue, true))
				{
					getActionErrors(request).add(ActionMessages.GLOBAL_MESSAGE,
						new ActionMessage("IssueRHAction.invalidDeveloper"));
					request.setAttribute("doNotLoad", Boolean.TRUE);
					return mapping.findForward("details");
				}
			}
			else
			{
				developer = null;
			}

			List projects;
			if (issue.getId() != 0)
			{
				projects = DaoLocator.getInstance().getProjectDao().findEnabledManagedProjects(loggedInUser);
			}
			else
			{
				projects = DaoLocator.getInstance().getProjectDao().findEnabledReportableProjects(loggedInUser);
			}

			if (mayEdit && !projects.contains(project))
			{
				getActionErrors(request).add(ActionMessages.GLOBAL_MESSAGE,
					new ActionMessage("IssueRHAction.invalidProject"));
				request.setAttribute("doNotLoad", Boolean.TRUE);
				return mapping.findForward("details");
			}

			if (mayEdit || mayProcess)
			{
				int newStatus;
				if (issue.getId() == 0)
				{
					newStatus = Issue.STATUS_NEW;
				}
				else
				{
					newStatus = Integer.parseInt(issueForm.getStatus());
					if (mayProcess && !mayEdit && newStatus != Issue.STATUS_OPEN && newStatus != Issue.STATUS_PROCESSED)
					{
						newStatus = Issue.STATUS_OPEN;
					}
				}

				HistoryEntry historyEntry = new HistoryEntry();
				historyEntry.setEditor(loggedInUser);
				historyEntry.setStatus(newStatus);
				issue.getHistoryEntries().add(historyEntry);

				if (mayEdit)
				{
					issue.setProject(project);
					issue.setName(issueForm.getName());
					issue.setDescription(issueForm.getDescription());
					issue.setPriority(Integer.parseInt(issueForm.getPriority()));
					issue.setType(Integer.parseInt(issueForm.getType()));

					if (issue.getId() != 0)
					{
						historyEntry.setComment(issueForm.getComment());
						issue.setDeveloper(developer);
					}
					else
					{
						historyEntry.setComment("Issue created");
						issue.setReporter(loggedInUser);
					}
				}
				else if (mayProcess)
				{
					historyEntry.setComment(issueForm.getComment());
				}

				issue.setStatus(newStatus);

				issueDao.saveInTransaction(issue);
				request.setAttribute("issueId", new Integer(issue.getId()));
				issueForm.setComment("");

				sendNotifications(request, issue, loggedInUser);

				getActionMessages(request).add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("IssueRHAction.saved"));
			}
		}
		else if (request.getParameter("Back") != null)
		{
			return mapping.findForward("overview");
		}

		return mapping.findForward("details");
	}

	private void sendNotifications(HttpServletRequest request, Issue issue, User loggedInUser) throws TechnicalException
	{
		// Collect users that receive a notification mail
		Set users = new HashSet();

		// Managers receive a mail
		users.addAll(DaoLocator.getInstance().getUserDao().findEnabledManagers(issue.getProject()));

		// The reporter receives a mail, if he is no guest
		if (!issue.getReporter().isGuest())
		{
			users.add(issue.getReporter());
		}

		// The developer receives a mail
		if (issue.getDeveloper() != null)
		{
			users.add(issue.getDeveloper());
		}

		// The editor that saved the issue does not need to receive a mail
		users.remove(loggedInUser);

		User[] userArray = (User[]) users.toArray(new User[users.size()]);

		String serverUrl = request.getScheme() + "://" + request.getServerName();
		if (request.getServerPort() != (request.isSecure() ? 443 : 80))
		{
			serverUrl += ":" + request.getServerPort();
		}
		serverUrl += request.getContextPath();

		NotificationMailer.getInstance().sendNotification(userArray, issue, loggedInUser, serverUrl);
	}
}
