/*
 * 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.persistence;

import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.sip.SipApplicationSession;

import com.ericsson.ssa.sip.SipApplicationSessionImpl;
import com.ericsson.ssa.sip.wrapper.WrappedSipApplicationSession;
import com.ericsson.ssa.utils.objectwrapping.WrapperContext;

/**
 * Class for handle out-of-band / out-of-tree access.
 * Most of the modyfing data methods will trigger replication of the delegated sip entity.
 * All overriden method triggers replication.
 * @author epkadsz
 *
 */
public class OnModificationReplicatedApplicationSession extends WrappedSipApplicationSession {

	/** Indicating if the local replication should override the context replication flag. */
	private boolean localReplication = false;
	
	/**
	 * Constructor used when the SAS is wrapped first time.
	 * @param sas
	 */
	public OnModificationReplicatedApplicationSession(SipApplicationSession sas) {
		super(sas, new ReplicationContext());
	}
	
	/**
	 * Wrapping using the already created context.
	 * 
	 * @param sas
	 * @param context
	 */
	public OnModificationReplicatedApplicationSession(SipApplicationSession sas, WrapperContext context) {
		super(sas, context);
	}
	
	public ReplicationContext getContext() {
		return (ReplicationContext)super.getContext();
	}
	
	@Override
	public void invalidate() {
		super.invalidate();
		//Todo, check replication point
	}

	@Override
	public void removeAttribute(String name) {
		super.removeAttribute(name);
		saveDelegate();
	}

	/**
	 * Interceptor with possibility to toggle off the auto replication.
	 * @param name
	 * @param value
	 */
	@Override
	public void setAttribute(String name, Object value) {
		//just to optimize the analysis
		if (getContext().isAutoReplicationOn()) {
			if (name.equals(ReplicationContext.OOB_GLOBAL_REPLICATION_FLAG)) {
				getContext().setAutoReplicationOn(false);
				return; // we dont store the flag
			}
		}
		if (localReplication == false) {
			if (name.equals(ReplicationContext.OOB_SHALLOW_REPLICATION_FLAG)) {
				localReplication = true;
				return; // we dont store the flag
			}
		}
		
		super.setAttribute(name, value);
		
		saveDelegate();
	}

	@Override
	public int setExpires(int expires) {
		int result = super.setExpires(expires);
		saveDelegate();
		
		return result;
	}
	
	@ReplicationTrigger(name = "Out of band / Out of tree for SAS", info = "This SAS is retrieved via SipSessionsUtil. Each modification should be replicated.", condition = "")
	private void saveDelegate() {
		if (getContext().isAutoReplicationOn() || localReplication) {
			getContext().incReplications();
			
			PersistenceUtil.getInstance().saveSipApplicationSessionDeeply((SipApplicationSessionImpl)getDelegate());
		}
	}
}

/**
 * Context that is passed between the different wrappers.
 * Its one context for every time a sas is wrapped.
 * @author EPKADSZ
 *
 */
class ReplicationContext implements WrapperContext {

	/** Setting this flag makes sure that the on-modify-methods replicates even if the global replication flag is off. 
	 * This allows scenarios where the application does not want to replicate when setting attrbutes on SS, but on SAS. */
	public static final String OOB_SHALLOW_REPLICATION_FLAG = "ENABLE_LOCAL_REPLICATION";
	
	/** Setting this flag will not replicate anything on-modify-replicate declarad methods unless the local replication is turned on.
	 * This allows scenearios where the application modifies SS but don't want to replicate on-modify-methods in that SS. 
	 * But instead relying on the in band replication triggers. */
	public static final String OOB_GLOBAL_REPLICATION_FLAG = "DISABLE_REPLICATION";

	private volatile boolean _globalRep = true;
	
	private AtomicInteger _replicationsTriggered = new AtomicInteger();
	
	public boolean isAutoReplicationOn() {
		return _globalRep;
	}
	public void setAutoReplicationOn(boolean flag) {
		_globalRep = flag;
	}
	
	public void incReplications() {
		_replicationsTriggered.incrementAndGet();
	}
}
