package gov.va.med.edp.web.controller;

import gov.va.med.edp.web.servlet.listener.TimeOutIntegrationSessionAttributeListener;

import java.util.Random;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.ModelAndView;

/**
 * TODO: document PackageClientVersionSynchronizationController
 */
public class ClientVersionSynchronizationController extends SiteCodeController implements InitializingBean {

    public static final String DEFAULT_INCOMPATIBILITY_VIEW = "incompatibilityView";

    private String clientArtifactId;
    private String viewName;
    private String incompatibilityViewName = DEFAULT_INCOMPATIBILITY_VIEW;
    private Random random = new Random();

    public ClientVersionSynchronizationController() {
        setRequireSession(true);
    }

    public void afterPropertiesSet() throws Exception {
        Assert.notNull(clientArtifactId, "clientArtifactId must not be null");
        Assert.notNull(viewName, "viewName must not be null");
    }

    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String serverPackageVersion = (String) request.getSession().getAttribute(SessionConstants.SERVER_PACKAGE_VERSION_KEY);
        if (serverPackageVersion == null) {
            DataAccessException error = (DataAccessException) request.getSession().getAttribute(SessionConstants.SERVER_ERROR_KEY);
            if (error != null) {
                throw error;
            } else {
                throw new IllegalStateException("Didn't find server package version number or an error explaining its absence in session. Is the " +
                        TimeOutIntegrationSessionAttributeListener.class.getName() + " session listener configured correctly?");
            }
        }

        String swfID = generateAndRememberSwfId(request);

        return createModelAndView(serverPackageVersion, swfID);
    }

    // generate a swf id and add to list for this session        
    private String generateAndRememberSwfId(HttpServletRequest request) {
        String swfID = generateUid();
        String ids = (String) request.getSession().getAttribute(SessionConstants.RECOGNIZED_SWF_IDS_KEY);

        Set idSet = StringUtils.commaDelimitedListToSet(ids);
        while (idSet.contains(swfID)) {
            swfID = generateUid();
        }
        idSet.add(swfID);
        ids = StringUtils.collectionToCommaDelimitedString(idSet);

        request.getSession().setAttribute(SessionConstants.RECOGNIZED_SWF_IDS_KEY, ids);
        return swfID;
    }

    protected ModelAndView createModelAndView(String serverPackageVersion, String swfID) {
        ModelAndView mav = new ModelAndView(isCompatible(serverPackageVersion) ? getViewName() : getIncompatibilityViewName());
        mav.addObject("swfID", swfID);
        mav.addObject("serverPackageVersion", serverPackageVersion);
        mav.addObject("clientVersion", serverPackageVersion); // TODO: remove this from flashVars after Flex 3 migration (use resource bundle inside SWF)
        mav.addObject("clientArtifactId", getClientArtifactId());
        mav.addObject("clientFinalName", getClientFinalName(serverPackageVersion));
        return mav;
    }

    private String generateUid() {
        return Integer.toString(Math.abs(random.nextInt()));
    }

    private boolean isCompatible(String serverPackageVersion) {
        Resource r = getWebApplicationContext().getResource(getClientFileName(serverPackageVersion));
        return r.exists();
    }

    private String getClientFinalName(String serverPackageVersion) {
        return getClientArtifactId() + "-" + serverPackageVersion;
    }

    private String getClientFileName(String serverPackageVersion) {
        return getClientFinalName(serverPackageVersion) + ".swf";
    }

    public String getClientArtifactId() {
        return clientArtifactId;
    }

    public void setClientArtifactId(String clientArtifactId) {
        this.clientArtifactId = clientArtifactId;
    }

    public String getViewName() {
        return viewName;
    }

    public void setViewName(String viewName) {
        this.viewName = viewName;
    }

    public String getIncompatibilityViewName() {
        return incompatibilityViewName;
    }

    public void setIncompatibilityViewName(String incompatibilityViewName) {
        this.incompatibilityViewName = incompatibilityViewName;
    }
}
