/*
 * Yobi, Project Hosting SW
 *
 * Copyright 2013 NAVER Corp.
 * http://yobi.io
 *
 * @Author Changsung Kim
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package controllers;

import controllers.annotation.IsAllowed;
import models.Issue;
import models.IssueComment;
import models.User;
import models.enumeration.Operation;
import org.codehaus.jackson.node.ObjectNode;
import play.libs.Json;
import play.mvc.Call;
import play.mvc.With;
import models.Project;
import play.mvc.Result;
import play.mvc.Controller;
import play.db.ebean.Transactional;
import actions.AnonymousCheckAction;
import models.enumeration.ResourceType;
import controllers.annotation.IsCreatable;
import utils.Constants;
import utils.RouteUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * The Controller which plays a role in voting in the issue.
 */
@With(AnonymousCheckAction.class)
public class VoteApp extends Controller {

    /**
     * Votes the issue.
     *
     * The vote of current user is added to the issue having {@code issueNumber}.
     *
     * @param ownerName
     * @param projectName
     * @param issueNumber
     * @return
     */
    @Transactional
    @With(AnonymousCheckAction.class)
    @IsAllowed(Operation.READ)
    public static Result vote(String ownerName, String projectName, Long issueNumber) {

        Project project = Project.findByOwnerAndProjectName(ownerName, projectName);
        Issue issue = Issue.findByNumber(project, issueNumber);

        issue.addVoter(UserApp.currentUser());

        Call call = routes.IssueApp.issue(ownerName, projectName, issueNumber);

        return redirect(call);
    }

    /**
     * Cancels the vote.
     *
     * It is canceled that the vote of current user is in the issue having {@code issueNumber}.
     *
     * @param ownerName
     * @param projectName
     * @param issueNumber
     * @return
     */
    @Transactional
    @With(AnonymousCheckAction.class)
    @IsAllowed(Operation.READ)
    public static Result unvote(String ownerName, String projectName, Long issueNumber) {
        Project project = Project.findByOwnerAndProjectName(ownerName, projectName);
        Issue issue = Issue.findByNumber(project, issueNumber);

        issue.removeVoter(UserApp.currentUser());

        Call call = routes.IssueApp.issue(ownerName, projectName, issueNumber);

        return redirect(call);
    }

    @Transactional
    @With(AnonymousCheckAction.class)
    @IsAllowed(Operation.READ)
    public static Result voteComment(String user, String project, Long number, Long commentId) {
        IssueComment issueComment = IssueComment.find.byId(commentId);
        if (issueComment == null) {
            return notFound("issue.comment.error.vote");
        }

        issueComment.addVoter(UserApp.currentUser());

        return redirect(RouteUtil.getUrl(issueComment));
    }

    @Transactional
    @With(AnonymousCheckAction.class)
    @IsAllowed(Operation.READ)
    public static Result unvoteComment(String user, String project, Long number, Long commentId) {
        IssueComment issueComment = IssueComment.find.byId(commentId);
        if (issueComment == null) {
            return notFound("issue.comment.error.unvote");
        }

        if (!issueComment.voters.contains(UserApp.currentUser())) {
            return notFound("issue.comment.error.have.not.voted");
        }

        issueComment.removeVoter(UserApp.currentUser());

        return redirect(RouteUtil.getUrl(issueComment));
    }

    public static List<User> getVotersForAvatar(List<User> voters, int size){
        return getSubList(voters, 0, size);
    }

    public static List<User> getVotersForName(List<User> voters, int fromIndex, int size){
        return getSubList(voters, fromIndex, fromIndex + size);
    }

    public static List<User> getVotersExceptCurrentUser(List<User> voters){
        List<User> result = new ArrayList<User>(voters);

        while(result.contains(UserApp.currentUser())){
            result.remove(UserApp.currentUser());
        }

        return result;
    }

    /**
     * Get subList of voters within its size.
     *
     * @param fromIndex
     * @param toIndex
     * @return
     */
    private static List<User> getSubList(List<User> voters, int fromIndex, int toIndex) {
        try {
            return voters.subList(
                    Math.max(0, fromIndex),
                    Math.min(voters.size(), toIndex)
            );
        } catch(IndexOutOfBoundsException e){
            play.Logger.warn("Failed to get subList of voters", e);
            return new ArrayList<User>();
        }
    }

}

@@ -1672,46 +1672,8 @@
 nal%0A
-    @With(AnonymousCheckAction.class)%0A
     
@@ -1691,32 +1691,32 @@
 Operation.READ)%0A
+
     public stati
@@ -2370,46 +2370,8 @@
 nal%0A
-    @With(AnonymousCheckAction.class)%0A
     
@@ -2830,46 +2830,8 @@
 nal%0A
-    @With(AnonymousCheckAction.class)%0A
     
@@ -3240,32 +3240,32 @@
 mment));%0A    %7D%0A%0A
+
     @Transaction
@@ -3271,46 +3271,8 @@
 nal%0A
-    @With(AnonymousCheckAction.class)%0A
     

Remove @With annotations applied duplicately