// Path: samples-and-tests/acl/app/controllers/AclController.java
// @With(Deadbolt.class)
// public class AclController extends Controller
// {
//     @Util
//     public static String getCurrentUserName()
//     {
//         return Secure.Security.connected();
//     }
// }
// 
// Path: app/controllers/deadbolt/RestrictedResourcesHandler.java
// public interface RestrictedResourcesHandler
// {
//     /**
//      * Check the access of someone, typically the current user, for the named resource.
//      *
//      * <ul>
//      * <li>If {@link AccessResult#NOT_SPECIFIED} is returned and
//      * {@link controllers.deadbolt.RestrictedResource#staticFallback()} is false, access is denied.</li>
//      * <li>If {@link AccessResult#NOT_SPECIFIED} is returned and
//      * {@link controllers.deadbolt.RestrictedResource#staticFallback()} is true, any further Restrict or
//      * Restrictions annotations are processed.  Note that if no Restrict or Restrictions annotations are present,
//      * access will be allowed.</li>
//      * </ul>
//      *
//      * @param resourceNames the names of the resource
//      * @param resourceParameters additional information on the resource
//      * @return {@link AccessResult#ALLOWED} if access is permitted.  {@link AccessResult#DENIED} if access is denied.
//      * {@link AccessResult#NOT_SPECIFIED} if access is not specified.
//      */
//     AccessResult checkAccess(List<String> resourceNames,
//                              Map<String, String> resourceParameters);
// }
// 
// Path: samples-and-tests/acl/app/model/AccessControlPreference.java
// @Entity
// public class AccessControlPreference extends Model
// {
//     public enum AccessChain { FRIENDS, ANYONE };
// 
//     @Enumerated(EnumType.STRING)
//     public AccessChain friendVisibility = AccessChain.ANYONE;
// 
//     @Enumerated(EnumType.STRING)
//     public AccessChain statusVisibility = AccessChain.ANYONE;
// 
//     @Enumerated(EnumType.STRING)
//     public AccessChain photoVisibility = AccessChain.ANYONE;
// }
// 
// Path: samples-and-tests/acl/app/model/AclUser.java
// @Entity
// public class AclUser extends Model implements RoleHolder
// {
//     @Required
//     public String userName;
// 
//     public String fullName;
// 
//     @Required
//     @ManyToOne
//     public AclApplicationRole role;
// 
//     @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE, CascadeType.DETACH})
//     public List<AclUser> friends;
// 
//     @ManyToMany(cascade = CascadeType.ALL)
//     public List<Photo> photos;
// 
//     @ManyToMany(cascade = CascadeType.ALL)
//     public List<StatusUpdate> statusUpdates;
// 
//     @OneToOne(cascade = CascadeType.ALL)
//     public AccessControlPreference accessControlPreference;
// 
//     public AclUser(String userName,
//                    String fullName,
//                    AclApplicationRole role)
//     {
//         this.userName = userName;
//         this.fullName = fullName;
//         this.role = role;
//         this.accessControlPreference = new AccessControlPreference();
//     }
// 
//     public static AclUser getByUserName(String userName)
//     {
//         return find("byUserName", userName).first();
//     }
// 
//     public List<? extends Role> getRoles()
//     {
//         return Arrays.asList(role);
//     }
// 
//     public void addPhoto(Photo photo)
//     {
//         if (photos == null)
//         {
//             photos = new ArrayList<Photo>();
//         }
//         photos.add(photo);
//     }
// 
//     public void addStatusUpdate(StatusUpdate statusUpdate)
//     {
//         if (statusUpdates == null)
//         {
//             statusUpdates = new ArrayList<StatusUpdate>();
//         }
//         statusUpdates.add(statusUpdate);
//     }
// 
//     public void addFriend(AclUser friend)
//     {
//         if (friends == null)
//         {
//             friends = new ArrayList<AclUser>();
//         }
//         friends.add(friend);
//     }
// 
//     public boolean isFriend(AclUser user)
//     {
//         return friends != null && friends.contains(user);
//     }
// 
//     @Override
//     public String toString()
//     {
//         return this.userName;
//     }
// }
// 
// Path: app/models/deadbolt/AccessResult.java
// public enum AccessResult
// {
//     ALLOWED,
//     DENIED,
//     NOT_SPECIFIED
// }


import controllers.AclController;
import controllers.deadbolt.RestrictedResourcesHandler;
import model.AccessControlPreference;
import model.AclUser;
import models.deadbolt.AccessResult;
import play.mvc.Http;
import java.security.AccessController;
import java.util.List;
import java.util.Map;
package security;



/**
 * @author Steve Chaloner (steve@objectify.be)
 */
public abstract class AccessChainHandler implements RestrictedResourcesHandler
{
    public AccessResult checkAccess(List<String> resourceNames,
                                    Map<String, String> resourceParameters)
    {
        String currentUserName = AclController.getCurrentUserName();
        Http.Request request = Http.Request.current();
        String targetUserName = request.params.get("targetUserName");

        AccessResult accessResult = AccessResult.DENIED;
        if (targetUserName == null || currentUserName.equals(targetUserName))
        {
            // current user is viewing own information
            accessResult = AccessResult.ALLOWED;
        }
        else
        {
            AclUser targetUser = AclUser.getByUserName(targetUserName);

            switch (getAccessChain(targetUser.accessControlPreference))
            {
                case FRIENDS:
                    AclUser currentUser = AclUser.getByUserName(currentUserName);
                    accessResult = targetUser.isFriend(currentUser) ? AccessResult.ALLOWED : AccessResult.DENIED;
                    break;
                case ANYONE:
                    accessResult = AccessResult.ALLOWED;
                    break;
            }
        }

        return accessResult;
    }

// Path: samples-and-tests/acl/app/controllers/AclController.java
// @With(Deadbolt.class)
// public class AclController extends Controller
// {
//     @Util
//     public static String getCurrentUserName()
//     {
//         return Secure.Security.connected();
//     }
// }
// 
// Path: app/controllers/deadbolt/RestrictedResourcesHandler.java
// public interface RestrictedResourcesHandler
// {
//     /**
//      * Check the access of someone, typically the current user, for the named resource.
//      *
//      * <ul>
//      * <li>If {@link AccessResult#NOT_SPECIFIED} is returned and
//      * {@link controllers.deadbolt.RestrictedResource#staticFallback()} is false, access is denied.</li>
//      * <li>If {@link AccessResult#NOT_SPECIFIED} is returned and
//      * {@link controllers.deadbolt.RestrictedResource#staticFallback()} is true, any further Restrict or
//      * Restrictions annotations are processed.  Note that if no Restrict or Restrictions annotations are present,
//      * access will be allowed.</li>
//      * </ul>
//      *
//      * @param resourceNames the names of the resource
//      * @param resourceParameters additional information on the resource
//      * @return {@link AccessResult#ALLOWED} if access is permitted.  {@link AccessResult#DENIED} if access is denied.
//      * {@link AccessResult#NOT_SPECIFIED} if access is not specified.
//      */
//     AccessResult checkAccess(List<String> resourceNames,
//                              Map<String, String> resourceParameters);
// }
// 
// Path: samples-and-tests/acl/app/model/AccessControlPreference.java
// @Entity
// public class AccessControlPreference extends Model
// {
//     public enum AccessChain { FRIENDS, ANYONE };
// 
//     @Enumerated(EnumType.STRING)
//     public AccessChain friendVisibility = AccessChain.ANYONE;
// 
//     @Enumerated(EnumType.STRING)
//     public AccessChain statusVisibility = AccessChain.ANYONE;
// 
//     @Enumerated(EnumType.STRING)
//     public AccessChain photoVisibility = AccessChain.ANYONE;
// }
// 
// Path: samples-and-tests/acl/app/model/AclUser.java
// @Entity
// public class AclUser extends Model implements RoleHolder
// {
//     @Required
//     public String userName;
// 
//     public String fullName;
// 
//     @Required
//     @ManyToOne
//     public AclApplicationRole role;
// 
//     @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE, CascadeType.DETACH})
//     public List<AclUser> friends;
// 
//     @ManyToMany(cascade = CascadeType.ALL)
//     public List<Photo> photos;
// 
//     @ManyToMany(cascade = CascadeType.ALL)
//     public List<StatusUpdate> statusUpdates;
// 
//     @OneToOne(cascade = CascadeType.ALL)
//     public AccessControlPreference accessControlPreference;
// 
//     public AclUser(String userName,
//                    String fullName,
//                    AclApplicationRole role)
//     {
//         this.userName = userName;
//         this.fullName = fullName;
//         this.role = role;
//         this.accessControlPreference = new AccessControlPreference();
//     }
// 
//     public static AclUser getByUserName(String userName)
//     {
//         return find("byUserName", userName).first();
//     }
// 
//     public List<? extends Role> getRoles()
//     {
//         return Arrays.asList(role);
//     }
// 
//     public void addPhoto(Photo photo)
//     {
//         if (photos == null)
//         {
//             photos = new ArrayList<Photo>();
//         }
//         photos.add(photo);
//     }
// 
//     public void addStatusUpdate(StatusUpdate statusUpdate)
//     {
//         if (statusUpdates == null)
//         {
//             statusUpdates = new ArrayList<StatusUpdate>();
//         }
//         statusUpdates.add(statusUpdate);
//     }
// 
//     public void addFriend(AclUser friend)
//     {
//         if (friends == null)
//         {
//             friends = new ArrayList<AclUser>();
//         }
//         friends.add(friend);
//     }
// 
//     public boolean isFriend(AclUser user)
//     {
//         return friends != null && friends.contains(user);
//     }
// 
//     @Override
//     public String toString()
//     {
//         return this.userName;
//     }
// }
// 
// Path: app/models/deadbolt/AccessResult.java
// public enum AccessResult
// {
//     ALLOWED,
//     DENIED,
//     NOT_SPECIFIED
// }


// Path: samples-and-tests/acl/app/security/AccessChainHandler.java
import controllers.AclController;
import controllers.deadbolt.RestrictedResourcesHandler;
import model.AccessControlPreference;
import model.AclUser;
import models.deadbolt.AccessResult;
import play.mvc.Http;
import java.security.AccessController;
import java.util.List;
import java.util.Map;

package security;



/**
 * @author Steve Chaloner (steve@objectify.be)
 */
public abstract class AccessChainHandler implements RestrictedResourcesHandler
{
    public AccessResult checkAccess(List<String> resourceNames,
                                    Map<String, String> resourceParameters)
    {
        String currentUserName = AclController.getCurrentUserName();
        Http.Request request = Http.Request.current();
        String targetUserName = request.params.get("targetUserName");

        AccessResult accessResult = AccessResult.DENIED;
        if (targetUserName == null || currentUserName.equals(targetUserName))
        {
            // current user is viewing own information
            accessResult = AccessResult.ALLOWED;
        }
        else
        {
            AclUser targetUser = AclUser.getByUserName(targetUserName);

            switch (getAccessChain(targetUser.accessControlPreference))
            {
                case FRIENDS:
                    AclUser currentUser = AclUser.getByUserName(currentUserName);
                    accessResult = targetUser.isFriend(currentUser) ? AccessResult.ALLOWED : AccessResult.DENIED;
                    break;
                case ANYONE:
                    accessResult = AccessResult.ALLOWED;
                    break;
            }
        }

        return accessResult;
    }

    public abstract AccessControlPreference.AccessChain getAccessChain(AccessControlPreference preference);