package gov.va.med.authentication.kernel.ccow;

import gov.va.med.authentication.kernel.KaajeeSSLHelper;
import java.io.IOException;
import java.io.PrintWriter;

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

import org.apache.log4j.Logger;
import org.apache.log4j.Level;

import com.sentillion.sdkweb.webcontextor.ContextItemCollection;
import com.sentillion.sdkweb.webcontextor.WebContextor;

/**
 * @author VHIT Security and Other Common Services (S&OCS)
 * @version 1.1.0.007
 */
public class ContextInitializer {
	
	private static Logger logger = Logger.getLogger(ContextInitializer.class);
	
	private final String CONTEXT_PARTICIPANT = ContextInitializerFilter.CONTEXT_PARTICIPANT;
	private final String APPLET_CODEBASE = ContextInitializerFilter.APPLET_CODEBASE;
	private final String CCOW_KAAJEE_APPL_NAME = ContextInitializerFilter.CCOW_KAAJEE_APPL_NAME;
	private final String SESSION_ID = ContextInitializerFilter.SESSION_ID;
	private final String BODY_TEXT =ContextInitializerFilter.LOCATOR_APPLET_BODY;
	
	private CcowEnv ccowEnv;
	private HttpServletRequest req;
	private HttpServletResponse res;

	public ContextInitializer(CcowEnv ccowEnv, HttpServletRequest req, HttpServletResponse res) {
		this.ccowEnv  = ccowEnv;
		this.req = req;
		this.res = res;
	}

	public boolean locatorSent() {
		return ccowEnv.locatorSent();
	}

	public void setEnvironment() {
		// define and save contextParticipantURL, applCodebaseURL, applicationName
		
    	// url = http(s)://host:port + context-path + /.../.../...?query-string
    	// uri = context-path + /.../.../...?query-string
    	String url = req.getRequestURL().toString(); 
    	String contextPath = req.getContextPath();
    	String base = url.split(contextPath)[0];   // http(s)://host:port    
    	String applCodebaseURL = base + contextPath + "/" + APPLET_CODEBASE;
    	String clientIPAddr = req.getRemoteAddr();
    	//String applicationName = (APP_NAME == null ? "kaajeeSampleApp" : APP_NAME);
    	//String contextParticipantURL = "http:server:port" + contextPath + "/" + CONTEXT_PARTICIPANT;
    	// must be http as context manager can't communicate in https
    	String serverName = req.getServerName();
    	KaajeeSSLHelper helper = new KaajeeSSLHelper();    	
    	int nonSSLPort = 80;  // will be overridden with actual
    	try {
			nonSSLPort = helper.getListenPort();
		} catch (Exception e) {
			
			logger.warn("Error obtaining port number from this server: " + e.getMessage());
		}
    	String contextParticipantURL = "http://" + serverName + ":" + nonSSLPort + contextPath + "/" + CONTEXT_PARTICIPANT;
    	String encodedContextParticipantURL = contextParticipantURL + ";" + SESSION_ID + "=" + req.getSession().getId();
    	
    	ccowEnv.setApplicationName(CCOW_KAAJEE_APPL_NAME); // formally assigned to KAAJEE and FATKAAT
    	ccowEnv.setContextParticipantURL(encodedContextParticipantURL);
    	ccowEnv.setAppletCodebaseURL(applCodebaseURL);
    	ccowEnv.setClientIPAddr(clientIPAddr);
	}

	public void sendLocatorApplet() {

		String contextParticipantURL = ccowEnv.getContextParticipantURL();
    	String appletCodebaseURL = ccowEnv.getAppletCodebaseURL();
    	String refreshURL = req.getRequestURL().toString();

    	AppletTag applet = new AppletTag(contextParticipantURL,
    										appletCodebaseURL,
    										refreshURL);  			
    	try {
			sendApplet(res, applet);
		} catch (IOException e) {
			if (logger.isEnabledFor(Level.ERROR)) {
				logger.debug("Error sending the Locator Applet: " + e.getMessage());
			}
		} finally {
			ccowEnv.setLocatorSent();
		}        
	}

	private void sendApplet(HttpServletResponse res, AppletTag applet) 
    	throws IOException {    	    

    	
    	res.setContentType("text/html");
    	PrintWriter out = res.getWriter();
    	// Notify Browser not to cache generated page
    	res.setHeader("Cache-Control","no-cache"); // Supports http 1.1
    	res.setHeader("Pragma","no-cache");  // Support http 1.0
    	res.setHeader("Expires","0");  // Expires immediately
    	
    	String TITLE = "LOCATOR APPLET PAGE";
    	
    	// output title
    	out.print("<HEAD><TITLE> " + TITLE + " </TITLE></HEAD><BODY>");
    	
    	// output body
    	out.print("<h1> " + BODY_TEXT + " </h1>");
    	// insert the applet
    	String LocatorApplet = applet.getLocatorAppletTag();
    	out.print(LocatorApplet);
    	out.print("</BODY>");
    	out.flush();

		if (logger.isEnabledFor(Level.DEBUG)) {
			logger.debug("Locator Applet sent back to browser: ");
		}
	}

	public boolean detectedCtxMgrParam() {
        // check to see if locator applet sent ctx manager url info
		boolean detected = false;
		String existing = ccowEnv.getContextManagerURL();
		if (logger.isEnabledFor(Level.DEBUG)) {
			logger.debug("before: " + existing);
		}
        String contextManagerUrl = req.getParameter("contextManagerUrl");
        detected = (contextManagerUrl != null && contextManagerUrl.length() > 0);
        if (detected){
    		if (logger.isEnabledFor(Level.DEBUG)) {
    			logger.debug("detected: " + contextManagerUrl);
    		}
        	boolean different = !(contextManagerUrl.equals(existing));
        	if (different) {
            	ccowEnv.setContextManagerURL(contextManagerUrl);
            	// force to read new common context data
            	ccowEnv.setActiveContextSession(null);
            	ccowEnv.setCurrentCommonContext(null);
        	}    
        }        
        return detected;
	}

	public void joincontext() {
		// join common context (readonly)
		CommonContextSession ctxSession = null;
		ctxSession = ccowEnv.getActiveContextSession();
		if (ctxSession == null) {
			ctxSession = ContextManager.joinReadContext(ccowEnv);
			
			if (ctxSession != null) {
				
				ccowEnv.setActiveContextSession(ctxSession);
				
			} else {
				// do nothing
				if (logger.isEnabledFor(Level.DEBUG)) {
					logger.debug("Failed to join a ReadContext session . . . ");
				}
			}
		} else {
			// already in session, resume if suspended
			if (logger.isEnabledFor(Level.DEBUG)) {
				logger.debug("already in ReadContext session, will resume . . . ");
			}
			ctxSession.resume();
			if (ctxSession.getState() != WebContextor.CsParticipating) {
				// could not resume context session
				ccowEnv.setActiveContextSession(null);
				if (logger.isEnabledFor(Level.DEBUG)) {
					logger.debug("failed to resume context session: " + ctxSession);
				}
			}
		}
	}

	public void retrieveUserContext() {
		// now get the current context collection and convert to Map
    	// save the current context into the session
		CommonContextMap context = null;
		context = ccowEnv.getCurrentCommonContext();
		if (context == null) {
			CommonContextSession ctxSession = ccowEnv.getActiveContextSession();
			if (ctxSession != null) {
				ContextItemCollection collection = ctxSession.getCurrentContext();
				if (collection != null && collection.count() > 0){
					context = new CommonContextMap(collection);
					ccowEnv.setCurrentCommonContext(context);
				} else {
					if (logger.isEnabledFor(Level.DEBUG)) {
						logger.debug("there is no current VA context");
					}
				}
			} else {
				// do nothing
				if (logger.isEnabledFor(Level.DEBUG)) {
					logger.debug("there is no active context");
				}
			}
		} else {
			// do nothing
			if (logger.isEnabledFor(Level.DEBUG)) {
				logger.debug("there is already a current VA context");
			}
		}
	}

	public boolean isUserLoggedIn() {
		LoginResult result = new LoginResult(this.ccowEnv,this.req);
		return result.isSuccessful();
	}
}
