package oracle.fodemo.storefront.listeners;

import java.util.HashMap;

import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

import javax.servlet.http.HttpSession;

import oracle.adf.controller.ControllerContext;
import oracle.adf.controller.ViewPortContext;
import oracle.adf.model.binding.DCBindingContainer;
import oracle.adf.model.binding.DCIteratorBinding;


import oracle.adfinternal.view.faces.model.binding.FacesCtrlSearchBinding;

import oracle.fodemo.storefront.jsf.util.JSFUtils;

import oracle.jbo.Row;
import oracle.jbo.domain.DBSequence;
import oracle.jbo.domain.Number;

/**
 * Used in FOD demo to set the page welcome message referenced from the template. 
 * The welcome message for the unauthenticated and authenticated user is stored in
 * a session attribute and referenced by the JSF pages. The messaged are read from
 * the message bundle to ensure internationalization working.
 * 
 * Authentication is performed using container-managed security, which means that 
 * we don't have a handle to determine whether or not authentication has been 
 * successful. This PhaseListener helps to show the right message to the user and 
 * to populate the UserInfoBean with user information like Firstname, Lastname, PersonId
 * etc.
 */

public class FODPhaseListener implements PhaseListener{
    public FODPhaseListener() {
    }

    public void afterPhase(PhaseEvent phaseEvent) {

        final String WELCOME_MESSAGE = "WelcomeMessage";
        FacesContext fctx = phaseEvent.getFacesContext();
        String remoteUser = fctx.getExternalContext().getRemoteUser();
        HttpSession thisSession = ((HttpSession)fctx.getExternalContext().getSession(false));
        
        // set unauthenticated message if user is not authenticated and the message doesn't
        // exist in the session
        
        if (remoteUser == null && thisSession.getAttribute(WELCOME_MESSAGE)== null){            
              thisSession.setAttribute(WELCOME_MESSAGE,JSFUtils.getStringFromBundle("home.unauthenticated.message"));
        }
        // if the user is authenticated and the UserInfo HashMap does not contain the user PersonId, update
        // the UserInfo and set the authenticated message to the session
        else if (remoteUser != null && JSFUtils.resolveExpression("#{UserInfo['PersonId']}")==null) {
            /*
             * The following lines of code access the binding container of the current JSF page, which is the 
             * page the request is navigated to after authentication. This pageDef file contains a reference to
             * the template binding file (pageDef created on the template) From here the iterator PersonsIter in 
             * the template binding can be accessed.
             */

            // WE CAN NEVER BE SURE WE ARE REDIRECTING TO A PAGE, SO ITS BEST  
            // GRAB REFERENCE THE PAGEDEF GLOBAL BINDINGS CONTAINER.
            DCBindingContainer templateBinding =  (DCBindingContainer) JSFUtils.resolveExpression("#{data.templates_StoreFrontTemplatePageDef}");
            DCIteratorBinding personsIter = (DCIteratorBinding) templateBinding.get("PersonsIterator");

            // set value of search criteria. "AuthenticatedUserByPrincipalCriteriaQuery" is created as a search region 
            // in the template pageDef file, associated to personsIterator
            FacesCtrlSearchBinding srchBinding = (FacesCtrlSearchBinding) templateBinding.get("AuthenticatedUserByPrincipalCriteriaQuery");
            // use the remote use name to lookup the user in the view criteria
            srchBinding.setParameterExpression("userPrincipal",remoteUser);
            srchBinding.execute();
                            
            Row authenticatedPerson = personsIter.getCurrentRow();
            
            thisSession.setAttribute(WELCOME_MESSAGE,authenticatedPerson.getAttribute("FirstName")+" "+authenticatedPerson.getAttribute("LastName"));   
            
            //populating user info
            HashMap userInfo = (HashMap) JSFUtils.resolveExpression("#{UserInfo}");
            //ADD ALL INFORMATION AS STRING SO WE HAVE A RELIABLE DATA TYPE
            String firstName = (String) authenticatedPerson.getAttribute("FirstName");
            String lastName = (String) authenticatedPerson.getAttribute("LastName");
            String personId = ((DBSequence) authenticatedPerson.getAttribute("PersonId")).toString();
            userInfo.put("FirstName", firstName);
            userInfo.put("LastName", lastName);
            userInfo.put("PersonId", personId);
        }
        
    }

    public void beforePhase(PhaseEvent phaseEvent) {
    }

    public PhaseId getPhaseId() {
        return PhaseId.RESTORE_VIEW;
    }
}
