/*
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the License).  You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the license at
 * https://glassfish.dev.java.net/public/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.
 * If applicable, add the following below the CDDL Header,
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Copyright (c) Ericsson AB, 2004-2007. All rights reserved.
 */
package com.ericsson.ssa.sip.wrapper;

import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.sip.B2buaHelper;
import javax.servlet.sip.SipServletMessage;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipSession;
import javax.servlet.sip.TooManyHopsException;
import javax.servlet.sip.UAMode;

import com.ericsson.ssa.utils.objectwrapping.AbstractWrapperObject;
import com.ericsson.ssa.utils.objectwrapping.ObjectWrapper;
import com.ericsson.ssa.utils.objectwrapping.WrapperContext;
import com.ericsson.ssa.utils.objectwrapping.WrapperUtil;

/**
 * B2BuaHelper wrapper.
 *   
 * The B2BuaHelper can be retrieved out-of-band by following twisted way:
 * <code>
 * 	 SipApplicationSession sasOOB = SipSessionsUtil.getApplicationSession("AnySASId");
 * 
 *   SipSession $1stLegSessionOOB = sasOOB.getSession("AnySipSessionId");
 *   B2BuaHelper b2buaHelperOOB = $1stLegSessionOOB.createRequest("INVITE").getB2buaHelper()
 *   		
 *   SipSession $2ndLegSessionOOB = b2buaHelperOOB.getLinkedSession(1stLegSessionOOB);
 *   
 * </code>   
 *  
 * 
 * @author epkadsz
 * @since 2007 nov 21
 *
 */
public class WrappedB2BUAHelper extends AbstractWrapperObject<B2buaHelper> implements
		B2buaHelper {

	private volatile static ObjectWrapper<SipServletMessage> _servletMessageWrapper;
	
	private static ObjectWrapper<SipServletMessage> getServletMessageWrapper() {
		if (_servletMessageWrapper == null)
			synchronized (WrappedB2BUAHelper.class) {
				if (_servletMessageWrapper == null)
					_servletMessageWrapper = new SelectiveServletMessageWrapper();
			}
		return _servletMessageWrapper;
	}
	
	public WrappedB2BUAHelper(B2buaHelper uaHelper, WrapperContext context) {
		super(uaHelper, context);
	}
	
	/**
	 * This method does not wrap the newly request since there are no know scenarios where origRequest can be retrieved as out of band.
	 * {@inheritDoc} 
	 */
	public SipServletRequest createRequest(SipServletRequest origRequest,
			boolean linked, Map<String, Set<String>> headerMap)
			throws IllegalArgumentException, TooManyHopsException {
		
		return getDelegate().createRequest(origRequest, linked, headerMap);
	}

	/**
	 * Wraps the newly created requested only if the session is wrapped already.
	 * {@inheritDoc} 
	 */
	public SipServletRequest createRequest(SipSession session,
			SipServletRequest origRequest, Map<String, Set<String>> headerMap)
			throws IllegalArgumentException {
		SipSession unwrappedSession = WrapperUtil.unwrap(session);
		SipServletRequest unwrappedOrigRequest = WrapperUtil.unwrap(origRequest);
		SipServletRequest newRequest = getDelegate().createRequest(unwrappedSession, unwrappedOrigRequest, headerMap);
		
		if (unwrappedSession != session)
			newRequest = WrapperFactorySet.wrap(newRequest, getContext());
		
		return newRequest;
	}

	/**
	 * {@inheritDoc}  
	 */
	public SipServletResponse createResponseToOriginalRequest(
			SipSession session, int status, String reasonPhrase) {
		SipSession unwrappedSession = WrapperUtil.unwrap(session);
		SipServletResponse response = getDelegate().createResponseToOriginalRequest(unwrappedSession, status, reasonPhrase);
		if (unwrappedSession != session)
			response = WrapperFactorySet.wrap(response, getContext());
		
		return response;
	}

	/**
	 * {@inheritDoc}  
	 */
	public SipSession getLinkedSession(SipSession session) {
		//unwrap if needed
		SipSession unwrappedSession = WrapperUtil.unwrap(session);
		SipSession linkedSession = getDelegate().getLinkedSession(unwrappedSession);
		
		if (linkedSession != null) {
			//if we were wrapped, then we return wrapped linked session, otherwise return the unwrapped version
			if (unwrappedSession != session) 
				linkedSession = WrapperFactorySet.getSipSessionFactory().wrap(linkedSession, getContext());
		}
		
		return linkedSession;
	}

	/**
	 * {@inheritDoc}  
	 */
	public SipServletRequest getLinkedSipServletRequest(SipServletRequest req) {
		
		return WrapperFactorySet.wrap(getDelegate().getLinkedSipServletRequest(WrapperUtil.unwrap(req)), getContext());
	}

	/**
	 * {@inheritDoc}  
	 */
	public List<SipServletMessage> getPendingMessages(SipSession session,
			UAMode mode) {
		SipSession unwrappedSession = WrapperUtil.unwrap(session);
		List<SipServletMessage> list = getDelegate().getPendingMessages(unwrappedSession, mode);
		
		if (list != null && list.size() != 0)
			if (unwrappedSession != session)
				list = WrapperUtil.wrap(list, getServletMessageWrapper(), getContext());
		
		return list;
	}

	/**
	 * {@inheritDoc}  
	 */
	public void linkSipSessions(SipSession session1, SipSession session2) {
		session1 = WrapperUtil.unwrap(session1);
		session2 = WrapperUtil.unwrap(session2);
		getDelegate().linkSipSessions(session1, session2);
	}

	/**
	 * {@inheritDoc}  
	 */
	public void unlinkSipSessions(SipSession session) {
		getDelegate().unlinkSipSessions(WrapperUtil.unwrap(session));
	}
}

/**
 * Selective wrapper used when returning pending request list.
 * @author EPKADSZ
 */
class SelectiveServletMessageWrapper implements ObjectWrapper<SipServletMessage> {
	public SipServletMessage wrap(SipServletMessage object, WrapperContext context) {
		if (object instanceof SipServletRequest)
			return WrapperFactorySet.wrap((SipServletRequest)object, context);
		else
			if (object instanceof SipServletResponse)
				return WrapperFactorySet.wrap((SipServletResponse)object, context);
				
		return object;
	}
}


