
package com.cognifide.apm.checks.actions.exclude;

import com.cognifide.apm.api.actions.Action;
import com.cognifide.apm.api.actions.ActionResult;
import com.cognifide.apm.api.actions.Context;
import com.cognifide.apm.api.exceptions.ActionExecutionException;
import com.cognifide.apm.checks.utils.ActionUtils;
import com.cognifide.apm.checks.utils.MessagingUtils;
import java.util.ArrayList;
import java.util.List;
import javax.jcr.RepositoryException;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;

public class CheckExcludes implements Action {

  private final List<String> authorizableIds;

  private final String groupId;

  public CheckExcludes(final String groupId, final List<String> authorizableIds) {
    this.groupId = groupId;
    this.authorizableIds = authorizableIds;
  }

  @Override
  public ActionResult simulate(Context context) {
    return process(context, false);
  }

  @Override
  public ActionResult execute(final Context context) {
    return process(context, true);
  }

  private ActionResult process(final Context context, boolean execute) {

    ActionResult actionResult = context.createActionResult();
    Group group = tryGetGroup(context, actionResult);
    if (group == null) {
      return actionResult;
    }

    List<String> errors = new ArrayList<>();

    boolean checkFailed = checkMembers(context, actionResult, group, errors);

    if (execute && checkFailed) {
      actionResult.logError(ActionUtils.ASSERTION_FAILED_MSG);
      return actionResult;
    }

    ActionUtils.logErrors(errors, actionResult);

    return actionResult;
  }

  private boolean checkMembers(final Context context, final ActionResult actionResult, final Group group,
      final List<String> errors) {
    boolean checkFailed = false;
    for (String authorizableId : authorizableIds) {
      try {
        Authorizable authorizable = context.getAuthorizableManager().getAuthorizableIfExists(authorizableId);
        if (authorizable == null) {
          actionResult.logWarning(MessagingUtils.authorizableNotExists(authorizableId));
          continue;
        }
        if (group.isMember(authorizable)) {
          actionResult.logError(authorizable.getID() + " belongs to group " + groupId);
          checkFailed = true;
        }
      } catch (RepositoryException e) {
        errors.add(MessagingUtils.createMessage(e));
      }
    }
    return checkFailed;
  }

  private Group tryGetGroup(final Context context, final ActionResult actionResult) {
    Group group;

    try {
      group = context.getAuthorizableManager().getGroup(groupId);
    } catch (RepositoryException e) {
      actionResult.logError(MessagingUtils.createMessage(e));
      return null;
    } catch (ActionExecutionException e) {
      actionResult.logError(MessagingUtils.createMessage(e));
      return null;
    }
    return group;
  }

}
