/*****************************************************************************
 * © 2015 Avaya Inc. All rights reserved.
 ****************************************************************************/
package com.avaya.services.Callingpolicies;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;

import com.avaya.collaboration.call.Call;
import com.avaya.collaboration.call.CallFactory;
import com.avaya.collaboration.util.logger.Logger;

@Startup
@Singleton
public class SequentialForkingTimer
{
    @Resource
    private TimerService timerService;

    private final Logger logger;

    public SequentialForkingTimer()
    {
        this(Logger.getLogger(SequentialForkingTimer.class));
    }

    SequentialForkingTimer(final Logger logger)
    {
        this.logger = logger;
    }

    @PostConstruct
    public void init()
    {
        if (timerService.getTimers() != null)
        {
            for (Timer timer : timerService.getTimers())
            {
                try
                {
                    timer.cancel();
                }
                catch (final Exception e)
                {
                    logger.finest("init: timer was not cancelled properly", e);
                }
            }
        }
        logger.finest("PostConstruct DONE");
    }

    /**
     * Create single action timer for a given callId.
     * 
     * @param millis  The number of milliseconds that must elapse before the timer expires.
     * @param callId The callId to associate with the timer
     */
    public void createTimer(final long millis, final String callId)
    {
        logger.finer("createTimer ENTER" + callId);
        final TimerConfig timerConfig = new TimerConfig();
        timerConfig.setInfo(callId);
        logger.finer("createTimer EXIT");
        timerService.createSingleActionTimer(millis, timerConfig);
    }

    /**
     * This method cancels the appropriate timer based on the callId.
     * 
     * @param callId The Call ID to cancel the timer
     */
    public void cancelTimer(final String callId)
    {
        logger.finer("cancelTimer ENTER" + callId);
        for (Timer timer : timerService.getTimers())
        {
            try
            {
                if (timer.getInfo().equals(callId))
                {
                    logger.finest("cancelTimer cancelling appropriate timer ...");
                    timer.cancel();
                }
            }
            catch (final Exception e)
            {
                logger.finest("init: timer was not cancelled properly", e);
            }
        }

        logger.finer("cancelTimer EXIT");
    }

    /**
     * This method is invoked when the timer expires. It will drop the called party.
     *  
     * @param timer Reference to timer
     */
    @Timeout
    public void onTimer(final Timer timer)
    {
        logger.finer("onTimer ENTER" + timer.getInfo());
        final String callId = (String) timer.getInfo();
        final Call call = CallFactory.getCall(callId);
        call.dropParticipant(call.getCalledParty());
        logger.finer("onTimer EXIT");
    }

    // for JUnit only: the postConstruct is not being called by unit tests. So, we need to set these another way.
    SequentialForkingTimer(final TimerService timerService, final Logger logger)
    {
        this.timerService = timerService;
        this.logger = logger;
    }
}
