/*
 * Copyright (C) 2005 - 2011 Jaspersoft Corporation. All rights reserved.
 * http://www.jaspersoft.com.
 *
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License  as
 * published by the Free Software Foundation, either version 3 of  the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero  General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public  License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.jaspersoft.jasperserver.war.cascade;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.directwebremoting.WebContextFactory;
import org.springframework.security.Authentication;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.beans.factory.InitializingBean;

import com.jaspersoft.jasperserver.api.metadata.user.domain.impl.client.MetadataUserDetails;
import com.jaspersoft.jasperserver.war.cascade.cache.DelegatorCacheManager;
import com.jaspersoft.jasperserver.war.cascade.cache.SessionCache;

/**
 * CascadeLogicDelegator
 * @author jwhang
 * @version $Id: ControlLogicDelegator.java 19932 2010-12-11 15:24:29Z tmatyashovsky $
 * Responsible for delegating to a ControlLogicFacade implementation, and checking/updating the short term cache.
 */

public class ControlLogicDelegator implements Delegator, InitializingBean {

    private HashMap<String,ControlLogic> controlLogicPool = new HashMap<String,ControlLogic>();
    private HashMap<String,String> controlLogicMap = new HashMap<String,String>();
    private String defaultControlLogic = "TokenControlLogic";

    private DelegatorCacheManager delegatorCacheManager;
    private Map<String, SessionCache> sessionCachePool;

    /*
     * Get a set of injected classes implementing the ControlLogicFacade interface.
     */
    public HashMap<String, ControlLogic> getControlLogicPool() {
        return controlLogicPool;
    }

    public void setControlLogicPool(
            HashMap<String, ControlLogic> controlLogicPool) {
        this.controlLogicPool = controlLogicPool;
    }

    public DelegatorCacheManager getDelegatorCacheManager() {
        return delegatorCacheManager;
    }

    public void setDelegatorCacheManager(DelegatorCacheManager delegatorCacheManager) {
        this.delegatorCacheManager = delegatorCacheManager;
    }

    public HashMap<String, String> getControlLogicMap() {
        return controlLogicMap;
    }

    public void setControlLogicMap(HashMap<String, String> controlLogicMap) {
        this.controlLogicMap = controlLogicMap;
    }

    public String getDefaultControlLogic() {
        return defaultControlLogic;
    }

    public void setDefaultControlLogic(String defaultControlLogic) {
        this.defaultControlLogic = defaultControlLogic;
    }

    public void afterPropertiesSet() throws Exception {
        //initialize the timer class.
        sessionCachePool = Collections.synchronizedMap(new HashMap<String,SessionCache>());
        delegatorCacheManager.initialize(sessionCachePool);
    }

    /*
     * Pass through calls to the control logic implementation to use.
     */

    public List<EventEnvelope> initialize(String reportUri,
            List<EventEnvelope> envelopes) throws SecurityException {
        ControlLogic relControlLogic = resolveControlLogic(reportUri);
        return relControlLogic.initialize(reportUri, envelopes, getSessionCache());
    }

    public List<EventEnvelope> handleEvents(String reportUri,
            List<EventEnvelope> envelopes) throws SecurityException {
        ControlLogic relControlLogic = resolveControlLogic(reportUri);
        return relControlLogic.handleEvents(reportUri, envelopes, getSessionCache());
    }

    public List<EventEnvelope> autoPopulate(String reportUri, List<EventEnvelope> envelopes, String lookupKey) throws SecurityException {
        ControlLogic relControlLogic = resolveControlLogic(reportUri);
        return relControlLogic.autoPopulate(reportUri, envelopes, lookupKey, getSessionCache());
    }

    public boolean isOptionAvailable(String reportName, String inputControlName, String option) {
        //TODO: future expansion to validate parameter entries.
        return true;
    }

    private ControlLogic resolveControlLogic(String reportUri){
        // check mappings based on report URI.
        Object specControlLogic = controlLogicMap.get(reportUri);
        if (specControlLogic != null){
            return controlLogicPool.get((String) specControlLogic);
        }
        // if nothing, return default.
        return controlLogicPool.get(defaultControlLogic);
    }

    private SessionCache getSessionCache() throws SecurityException {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth == null || auth.getPrincipal().equals("anonymousUser")) {
            throw new SecurityException("Session expired.");
        }
        MetadataUserDetails userDetails = (MetadataUserDetails) auth.getPrincipal();

        String sessionId = WebContextFactory.get().getSession().getId();
        StringBuffer cacheKey = new StringBuffer();
        cacheKey.append(userDetails.getUsername().replace('|', '.'));
        if (userDetails.getTenantId() != null) {
            cacheKey.append("|").append(userDetails.getTenantId().replace('|', '.'));
        }
        cacheKey.append(sessionId);

        SessionCache cache = sessionCachePool.get(cacheKey.toString());
        if (cache == null) { //create a new cache.
            //cache = new SessionCacheImpl(cacheKey);
            cache = delegatorCacheManager.createSessionCache(cacheKey.toString());
            sessionCachePool.put(cacheKey.toString(), cache);
        }
        return cache;
    }
}





