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

import com.ericsson.ssa.config.ConfigFactory;
import com.ericsson.ssa.config.annotations.Configuration;
import com.ericsson.ssa.config.annotations.UpdatePolicy;
import com.ericsson.ssa.config.annotations.UsagePolicy;
import com.ericsson.ssa.sip.Layer;
import com.ericsson.ssa.sip.SipServletRequestImpl;
import com.ericsson.ssa.sip.SipServletResponseImpl;
import java.util.concurrent.atomic.AtomicLong;
import com.ericsson.ssa.container.callflow.Reporter;
import com.ericsson.ssa.container.callflow.CallflowResolver;
import org.jvnet.glassfish.comms.util.LogUtil;


public abstract class NetworkManager implements Layer {
    private static NetworkManager instance = null;

    private static final String GRIZZLY_ENABLE_PROPERTY = "sip.network.grizzly";
    
    private AtomicLong _EasInvalidSipMessages = new AtomicLong();
    private AtomicLong _EasReceivedSipRequests = new AtomicLong();
    private AtomicLong _EasReceivedSipResponses = new AtomicLong();
    private AtomicLong _EasSentSipRequests = new AtomicLong();
    private AtomicLong _EasSentSipResponses = new AtomicLong();
    
    private Reporter _reporter;
    
    public void setReporters(String reporters){
        _reporter = CallflowResolver.getInstance().getReporter(reporters);
    }
    
    public Reporter getReporter(){
        return _reporter;
    }
    
    private LogUtil log = LogUtil.SIP_LOGGER;
    private int _SipLinkTimeout = 10; // ms
    private int _SipLinkTimeoutRetries = 25; // iterations
    private int _SipLinkMaxQueueLen = 50;
    private int _SipLinkWaitLockTimeout = 5000;
    private long _SipLinkAliveTimeout = 120;
    private boolean _errorResponseEnabled = false;   

    public abstract void next(SipServletRequestImpl req);

    public abstract void next(SipServletResponseImpl resp);

    public abstract void registerNext(Layer layer);

    public abstract void dispatch(SipServletRequestImpl req);

    public abstract void dispatch(SipServletResponseImpl resp);

    public synchronized static NetworkManager getInstance() {
        if (instance == null) {
            //TODO remove in final version so only one Network manager is present
            String grizzlyEnabledPropertyValue = System.getProperty(GRIZZLY_ENABLE_PROPERTY);
            if (grizzlyEnabledPropertyValue != null &&
                    Boolean.parseBoolean(grizzlyEnabledPropertyValue)) {
                instance = new GrizzlyNetworkManager();                
            } else {
                instance = new OLDNetworkManager();
            }
            
            ConfigFactory.instance().activateConfiguration(instance);
        }

        return instance;
    }

    public boolean isRunning() {
        return true;
    }
    
        // package access
    void incrEasInvalidSipMessages() {
        _EasInvalidSipMessages.incrementAndGet();
    }

    void incrEasReceivedSipRequests() {
        _EasReceivedSipRequests.incrementAndGet();
    }

    void incrEasReceivedSipResponses() {
        _EasReceivedSipResponses.incrementAndGet();
    }

    void incrEasSentSipRequests() {
        _EasSentSipRequests.incrementAndGet();
    }

    void incrEasSentSipResponses() {
        _EasSentSipResponses.incrementAndGet();
    }

    public long getEasInvalidSipMessages() {
        return _EasInvalidSipMessages.longValue();
    }

    public long getEasReceivedSipRequests() {
        return _EasReceivedSipRequests.longValue();
    }

    public long getEasReceivedSipResponses() {
        return _EasReceivedSipResponses.longValue();
    }

    public long getEasSentSipRequests() {
        return _EasSentSipRequests.longValue();
    }

    public long getEasSentSipResponses() {
        return _EasSentSipResponses.longValue();
    }
    
    
    /**
     * Defines timeout value in milliseconds for a single write operation of a
     * sip link.
     * </p>
     * Range: 1-50ms
     *
     * @param timeout
     */
    @Configuration (key="WriteTimeoutInMillis", node="/SipService/SipProtocol/SipLink")
    public void setSipLinkTimeout(int timeout) {
        if ((timeout > 0) && (timeout <= 50)) {
            _SipLinkTimeout = timeout;
        } else {
            if (log.logWarning()) {
                log.warning("sip.stack.network.bad_sip_link_timeout", timeout);
            }   Integer i;             
        }
    }

    /**
     * Defines timeout value in milliseconds for a single write operation of a
     * sip link.
     *
     * @return timeout for write operation of a sip link
     */
    public int getSipLinkTimeout() {
        return _SipLinkTimeout;
    }

    /**
     * Defines timeout value in seconds for keeping an inactive link. If no
     * traffic has been generated on that link for that time period the link is
     * closed.
     *
     * @return timeout value in seconds for keeping an inactive link
     */
    public long getSipLinkAliveTimeout() {
        return _SipLinkAliveTimeout;
    }

    /**
     * Defines timeout value in seconds for keeping an inactive link. If no
     * traffic has been generated on that link for that time period the link is
     * closed.
     *
     * @param timeout
     *           value in seconds for keeping an inactive link
     */
    @Configuration (key="ConnectionAliveTimeoutInSeconds", node="/SipService/SipProtocol/SipLink")
    public void setSipLinkAliveTimeout(long timeout) {
        _SipLinkAliveTimeout = timeout;
    }

    /**
     * Defines the number of retries to perform of a single write operation of a
     * sip link.
     * </p>
     * Range: 1-25
     * </p>
     * The maximum time a link will try for success of a write operation is
     * defined by SipLinkTimeout * SipLinkTimeoutRetries milliseconds.
     *
     * @param retries
     */
    @Configuration (key="WriteTimeoutRetries", node="/SipService/SipProtocol/SipLink")
    public void setSipLinkTimeoutRetries(int retries) {
        if ((retries > 0) && (retries <= 25)) {
            _SipLinkTimeoutRetries = retries;
        } else {
            if (log.logWarning()) {
                log.warning("sip.stack.network.bad_sip_link_timeout_retries", retries);
            }
        }

        _SipLinkTimeoutRetries = retries;
    }

    /**
     * Defines the number of retries to perform of a single write operation of a
     * sip link.
     * </p>
     * The maximum time a link will try for success of a write operation is
     * defined by SipLinkTimeout * SipLinkTimeoutRetries milliseconds.
     *
     * @return the number of retries to perform of a single write operation of a
     *         sip link.
     */
    public int getSipLinkTimeoutRetries() {
        return _SipLinkTimeoutRetries;
    }

    /**
     * Returns the maximum number of connect/write tasks that can be queued in a
     * link.
     *
     * @return the maximum number of connect/write tasks that can be queued in a
     *         link
     */
    public int getSipLinkMaxQueueLength() {
        return _SipLinkMaxQueueLen;
    }

    /**
     * Returns the maximum number of connect/write tasks that can be queued in a
     * link.
     *
     * @param length
     *           the maximum number of connect/write tasks that can be queued in
     *           a link
     */
    @Configuration (key="MaxQueueLength", node="/SipService/SipProtocol/SipLink")
    public void setSipLinkMaxQueueLength(int length) {
        _SipLinkMaxQueueLen = length;
    }

    /**
     * Returns the maximum time a thread will wait to get an exclusive lock for a
     * sip link.
     *
     * @return the maximum time a thread will wait to get an exclusive lock for a
     *         sip link.
     */
    public int getSipLinkWaitLockTimeout() {
        return _SipLinkWaitLockTimeout;
    }

    /**
     * Sets the maximum time a thread will wait to get an exclusive lock for a
     * sip link.
     *
     * @param timeout
     */
    @Configuration (key="SipLinkWaitLockTimeout", node="/SipService/SipProtocol/SipLink", 
        usage=UsagePolicy.IGNORE, update=UpdatePolicy.STARTUP) //This was never before configurable!
    public void setSipLinkWaitLockTimeout(int timeout) {
        _SipLinkWaitLockTimeout = timeout;
    }
    
    /**
     * Returns whether a malformed request should be handled by sending a proper
     * informational error response.
     *
     * @return
     */
    public Boolean isErrorResponseEnabled() {
        return _errorResponseEnabled;
    }

    /**
     * Setter of the <code>ErrorResponseEnabled</code> property.
     *
     * @param responseEnabled
     */
    @Configuration (key="ErrorResponseEnabled", node="/SipService/SipProtocol")
    public void setErrorResponseEnabled(Boolean responseEnabled) {
        _errorResponseEnabled = responseEnabled;
    }    
}
