/**
 * 
 */
package de.bstly.board.businesslogic;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import de.bstly.board.model.Comment;
import de.bstly.board.model.Entry;
import de.bstly.board.model.Flag;
import de.bstly.board.model.QComment;
import de.bstly.board.model.QFlag;
import de.bstly.board.model.support.FlaggedStatus;
import de.bstly.board.model.support.Types;
import de.bstly.board.repository.CommentRepository;
import de.bstly.board.repository.FlagRepository;

/**
 * The Class FlagManager.
 */
@Component
public class FlagManager {

	@Autowired
	private FlagRepository flagRepository;
	@Autowired
	private SettingsManager settingsManager;
	@Autowired
	private EntryManager entryManager;
	@Autowired
	private CommentManager commentManager;
	@Autowired
	private CommentRepository commentRepository;

	private QFlag qFlag = QFlag.flag;
	private QComment qComment = QComment.comment;

	/**
	 * Gets the.
	 *
	 * @param author the author
	 * @param target the target
	 * @param targetType the target type
	 * @return the flag
	 */
	public Flag get(String author, Long target, Types targetType) {
		return flagRepository.findOne(qFlag.author.eq(author).and(qFlag.targetType.eq(targetType))
				.and(qFlag.target.eq(target))).orElse(null);
	}

	/**
	 * Save.
	 *
	 * @param flag the flag
	 * @return the flag
	 */
	public Flag save(Flag flag) {
		return flagRepository.save(flag);
	}

	/**
	 * Delete.
	 *
	 * @param flag the flag
	 */
	public void delete(Flag flag) {
		flagRepository.delete(flag);
	}

	/**
	 * Delete by target.
	 *
	 * @param target the target
	 * @param targetType the target type
	 */
	public void deleteByTarget(Long target, Types targetType) {
		for (Flag flag : flagRepository
				.findAll(qFlag.target.eq(target).and(qFlag.targetType.eq(targetType)))) {
			delete(flag);
		}
	}

	/**
	 * Gets the flags.
	 *
	 * @param target the target
	 * @param targetType the target type
	 * @return the flags
	 */
	public long getFlags(Long target, Types targetType) {
		return flagRepository.count(qFlag.target.eq(target).and(qFlag.targetType.eq(targetType)));
	}

	/**
	 * Check flag status.
	 *
	 * @param target the target
	 * @param targetType the target type
	 */
	public void checkFlagStatus(Long target, Types targetType) {
		switch (targetType) {
		case comment:
			checkCommentFlagStatus(target);
			break;
		case entry:
			checkEntryFlagStatus(target);
			break;
		case user:
			break;
		default:
			break;
		}
	}

	/**
	 * Check comment flag status.
	 *
	 * @param target the target
	 */
	public void checkCommentFlagStatus(Long target) {
		Assert.isTrue(commentManager.exists(target), "Comment not exists: '"
				+ target
				+ "'!");
		Comment comment = commentManager.get(target);

		if (getFlags(target, Types.comment) >= settingsManager.getFlahThresh()) {
			if (!FlaggedStatus.FLAGGED.equals(comment.getFlaggedStatus())) {
				flagComment(comment);
			}
		} else if (FlaggedStatus.FLAGGED.equals(comment.getFlaggedStatus())) {
			unflagComment(comment);
		}
	}

	/**
	 * Flag comment.
	 *
	 * @param comment the comment
	 */
	protected void flagComment(Comment comment) {
		comment.setFlaggedStatus(FlaggedStatus.FLAGGED);
		comment = commentManager.save(comment);
		hideSubcomments(comment);
	}

	/**
	 * Hide subcomments.
	 *
	 * @param comment the comment
	 */
	protected void hideSubcomments(Comment comment) {
		for (Comment subcomment : commentRepository.findAll(qComment.parent.eq(comment.getId())
				.and(qComment.flaggedStatus.eq(FlaggedStatus.NORMAL)))) {
			subcomment.setFlaggedStatus(FlaggedStatus.HIDDEN);
			subcomment = commentManager.save(subcomment);
			hideSubcomments(subcomment);
		}
	}

	/**
	 * Unflag comment.
	 *
	 * @param comment the comment
	 */
	protected void unflagComment(Comment comment) {
		comment.setFlaggedStatus(FlaggedStatus.NORMAL);
		comment = commentManager.save(comment);
		unhideSubcomments(comment);
	}

	/**
	 * Unhide subcomments.
	 *
	 * @param comment the comment
	 */
	protected void unhideSubcomments(Comment comment) {
		for (Comment subcomment : commentRepository.findAll(qComment.parent.eq(comment.getId())
				.and(qComment.flaggedStatus.eq(FlaggedStatus.HIDDEN)))) {
			subcomment.setFlaggedStatus(FlaggedStatus.NORMAL);
			subcomment = commentManager.save(subcomment);
			hideSubcomments(subcomment);
		}
	}

	/**
	 * Check entry flag status.
	 *
	 * @param target the target
	 */
	public void checkEntryFlagStatus(Long target) {
		Assert.isTrue(entryManager.exists(target), "Entry not exists: '"
				+ target
				+ "'!");
		Entry entry = entryManager.get(target);
		if (getFlags(target, Types.entry) >= settingsManager.getFlahThresh()) {
			if (!FlaggedStatus.FLAGGED.equals(entry.getFlaggedStatus())) {
				entry.setFlaggedStatus(FlaggedStatus.FLAGGED);
				entryManager.save(entry);
			}
		} else if (FlaggedStatus.FLAGGED.equals(entry.getFlaggedStatus())) {
			entry.setFlaggedStatus(FlaggedStatus.NORMAL);
			entryManager.save(entry);
		}
	}

	/**
	 * Unflag.
	 *
	 * @param target the target
	 * @param targetType the target type
	 */
	public void unflag(Long target, Types targetType) {
		deleteByTarget(target, targetType);
		checkFlagStatus(target, targetType);
	}

}
