package org.slc.sli.api.security.oauth;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import org.slc.sli.api.security.SLIPrincipal;
import org.slc.sli.api.security.context.ContextResolverStore;
import org.slc.sli.api.security.context.resolver.AllowAllEntityContextResolver;
import org.slc.sli.common.constants.EntityNames;
import org.slc.sli.domain.Entity;
import org.slc.sli.domain.NeutralCriteria;
import org.slc.sli.domain.NeutralQuery;
import org.slc.sli.domain.Repository;

/**
 * Determines which applications a given user is authorized to use based on
 * that user's ed-org.
 *
 * @author pwolf
 *
 */
@Component
public class ApplicationAuthorizationValidator {

    private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationAuthorizationValidator.class);

    @Autowired
    private Repository<Entity> repo;

    @Autowired
    private ContextResolverStore contextResolverStore;

    /**
     * Get the list of authorized apps for the user based on the user's LEA.
     *
     * No additional filtering is done on the results. E.g. if a user is a non-admin,
     * the admin apps will still show up in the list, or if an app is disabled it will
     * still show up.
     *
     * @param principal
     *
     * @return list of app IDs, or null if it couldn't be determined
     */
    @SuppressWarnings("unchecked")
    public List<String> getAuthorizedApps(SLIPrincipal principal) {
        List<Entity> districts = findUsersDistricts(principal);

        //essentially allow by default for users with no entity data, ie. administrators
        if (districts == null) {
            return null;
        }
        List<String> apps = null;
        for (Entity district : districts) {

            NeutralQuery query = new NeutralQuery();
            query.addCriteria(new NeutralCriteria("authId", "=", district.getEntityId()));
            query.addCriteria(new NeutralCriteria("authType", "=", "EDUCATION_ORGANIZATION"));
            Entity authorizedApps = repo.findOne("applicationAuthorization", query);

            if (authorizedApps != null) {
                if (apps == null) {
                    apps = new ArrayList<String>();
                }
                apps.addAll((List<String>) authorizedApps.getBody().get("appIds"));
            }

        }

        return apps;
    }

    /**
     * Looks up the user's LEA entity.
     *
     * Currently it returns a list of all LEAs the user might be associated with.
     * In the case there's a hierarchy of LEAs, all are returned in no particular order.
     *
     * @param principal
     * @return a list of accessible LEAs, or null if no entity data was found
     */
    private List<Entity> findUsersDistricts(SLIPrincipal principal) {
        List<Entity> toReturn = new ArrayList<Entity>();
        if (principal.getEntity() != null) {
            List<String> edOrgs = null;
            try {
                edOrgs = contextResolverStore.findResolver(EntityNames.TEACHER, EntityNames.EDUCATION_ORGANIZATION).findAccessible(principal.getEntity());
            } catch (IllegalArgumentException ex) {
                // this is what the resolver throws if it doesn't find any edorg data
                LOGGER.warn("Could not find an associated ed-org for {}.", principal.getExternalId());
            }
            if (edOrgs == null || edOrgs.size() == 0) {   //maybe user is a staff?
                edOrgs = contextResolverStore.findResolver(EntityNames.STAFF, EntityNames.EDUCATION_ORGANIZATION).findAccessible(principal.getEntity());
            }

            //Need to clean this up when we remove the demo user 'hack'
            if (edOrgs == AllowAllEntityContextResolver.SUPER_LIST) {
                return null;
            }
            for (String id : edOrgs) {
                Entity entity = repo.findById(EntityNames.EDUCATION_ORGANIZATION, id);
                if (entity == null) {
                    warn("Could not find ed-org with ID {}", id);
                } else {
                    List<String> category = (List<String>) entity.getBody().get("organizationCategories");
                    if (category.contains("Local Education Agency")) {
                        toReturn.add(entity);
                    }
                }
            }

        } else {
            LOGGER.warn("Skipping LEA lookup for {} because no entity data was found.", principal.getExternalId());
            return null;
        }
        if (toReturn.size() == 0) {
            LOGGER.warn("Could not find an associated LEA for {}.", principal.getExternalId());
        }
        return toReturn;
    }

}

@@ -4269,16 +4269,64 @@
 ries%22);%0A
+                    if (category != null) %7B%0A    
         
@@ -4412,16 +4412,20 @@
         
+  
+  
 toReturn
@@ -4450,33 +4450,80 @@
                 
-%7D
+    %7D%0A                    %7D%0A                    
 %0A               

Fix sandbox/idp issue