/**
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you 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 the following location:
 *
 *   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 org.apereo.portal.portlets.backgroundpreference;

import java.util.Arrays;

import org.apache.commons.lang.StringUtils;
import org.apereo.portal.spring.spel.IPortalSpELService;
import org.apereo.portal.spring.spel.PortalSpELServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.portlet.ActionRequest;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;
import javax.servlet.ServletContext;

/**
 * Determines set of images to display by checking to see if user is in a mobile user group as determined by the
 * portal's security roles.
 *
 * @author James Wennmacher, jwennmacher@unicon.net
 */
@Component
public class RoleBasedBackgroundSetSelectionStrategy implements BackgroundSetSelectionStrategy {

    private enum PreferenceNames {

        DEFAULT("default"),

        MOBILE("mobile");

        /**
         * <b>Must match</a> the name of the corresponding PAGS group perfectly.
         */
        private static final String MOBILE_DEVICE_ROLE_NAME = "Mobile Device Access";

        public static PreferenceNames getInstance(PortletRequest req) {
            return req.isUserInRole(MOBILE_DEVICE_ROLE_NAME) ? MOBILE : DEFAULT;
        }
        private final String prefix;

        private PreferenceNames(String prefix) {
            this.prefix = prefix;
        }

        public String getImageSetPreferenceName() {
            return prefix + "BackgroundImages";
        }

        public String getImageThumbnailSetPreferenceName() {
            return prefix + "BackgroundThumbnailImages";
        }

        public String getSelectedBackgroundImagePreferenceName() {
            return prefix + "SelectedBackgroundImage";
        }

        public String getBackgroundContainerSelectorPreferenceName() {
            return prefix + "BackgroundContainerSelector";
        }

        public String getImageCaptionsName() {
            return "backgroundImageCaptions";
        }
    }

    private static final String[] EMPTY_STRING_ARRAY = new String[0];

    @Autowired
    private ServletContext servletContext;

    @Autowired
    private IPortalSpELService portalSpELService;

    final StandardEvaluationContext evaluationContext = new StandardEvaluationContext();

    @PostConstruct
    public void init() {
        final String contextPath = servletContext.getContextPath();
        evaluationContext.setRootObject(new RootObjectImpl(contextPath));
    }

    @Override
    public String[] getImageSet(PortletRequest req) {
        final PreferenceNames names = PreferenceNames.getInstance(req);
        final PortletPreferences prefs = req.getPreferences();
        final String[] images = prefs.getValues(names.getImageSetPreferenceName(), EMPTY_STRING_ARRAY);
        for (int i=0; i<images.length; i++) {
            images[i] = evaluateImagePath(images[i]);
        }
        return images;
    }

    @Override
    public String[] getImageThumbnailSet(PortletRequest req) {
        PreferenceNames names = PreferenceNames.getInstance(req);
        PortletPreferences prefs = req.getPreferences();
        final String[] images = prefs.getValues(names.getImageThumbnailSetPreferenceName(), null);
        for (int i=0; i<images.length; i++) {
            images[i] = evaluateImagePath(images[i]);
        }
        return images;
    }

    @Override
    public String[] getImageCaptions(PortletRequest req) {
        PreferenceNames names = PreferenceNames.getInstance(req);
        PortletPreferences prefs = req.getPreferences();
        return prefs.getValues(names.getImageCaptionsName(), null);
    }

    @Override
    public String getSelectedImage(PortletRequest req) {
        // No evaluation required (already processed)
        PreferenceNames names = PreferenceNames.getInstance(req);
        PortletPreferences prefs = req.getPreferences();
        return prefs.getValue(names.getSelectedBackgroundImagePreferenceName(), null);
    }

    @Override
    public String getBackgroundContainerSelector(PortletRequest req) {
        PreferenceNames names = PreferenceNames.getInstance(req);
        PortletPreferences prefs = req.getPreferences();
        return prefs.getValue(names.getBackgroundContainerSelectorPreferenceName(), null);
    }

    @Override
    public void setSelectedImage(ActionRequest req, String backgroundImage) {

        PreferenceNames names = PreferenceNames.getInstance(req);
        PortletPreferences prefs = req.getPreferences();

        if (StringUtils.isNotBlank(backgroundImage)) {

            // We are trying to choose a background;  first verify the requested image is actually in the set...
            String[] images = prefs.getValues(names.getImageSetPreferenceName(), EMPTY_STRING_ARRAY);
            for (int i=0; i<images.length; i++) {
                images[i] = evaluateImagePath(images[i]);
            }
            if (Arrays.asList(images).contains(backgroundImage)) {
                try {
                    prefs.setValue(names.getSelectedBackgroundImagePreferenceName(), backgroundImage);
                    prefs.store();
                } catch (Exception e) {
                    throw new RuntimeException("Failed to store the user's choice of background image", e);
                }
            }

        } else {

            // We are trying to clear a previous selection
            try {
                prefs.reset(names.getSelectedBackgroundImagePreferenceName());
                prefs.store();
            } catch (Exception e) {
                throw new RuntimeException("Failed to reset the user's choice of background image", e);
            }

        }

    }

    /*
     * Implementation
     */

    private String evaluateImagePath(String pathBeforeProcessing) {
        final Expression x = portalSpELService.parseExpression(pathBeforeProcessing, PortalSpELServiceImpl.TemplateParserContext.INSTANCE);
        final String rslt = x.getValue(evaluationContext, String.class);
        return rslt;
    }

    /*
     * Nested Types
     */

    /**
     * Allows us to evaluate '${portalContext}' to '/uPortal' (or whatever it
     * is) within image paths.
     */
    private static final class RootObjectImpl {
        private final String portalContext;
        public RootObjectImpl(String portalContext) {
            this.portalContext = portalContext;
        }
        @SuppressWarnings("unused")
        public String getPortalContext() {
            return portalContext;
        }
    }

}

@@ -2222,32 +2222,33 @@
 AULT;%0A        %7D%0A
+%0A
         private 
@@ -2889,65 +2889,205 @@
     
-public String getI
+/**%0A         * The portlet-preference containing the i
 mage
-C
+ c
 aptions
-Name() %7B%0A            return
+.%0A         * This preference name will not change.%0A         */%0A        public static final String IMAGE_CAPTIONS_PREFERENCE_NAME =
  %22ba
@@ -3110,26 +3110,16 @@
 tions%22;%0A
-        %7D%0A
     %7D%0A%0A 
@@ -4719,30 +4719,38 @@
 mes.
-getImageCaptionsName()
+IMAGE_CAPTIONS_PREFERENCE_NAME
 , nu

Convert preference name to public field