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

import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import com.avaya.collaboration.businessdata.api.ServiceData;
import com.avaya.collaboration.call.Call;
import com.avaya.collaboration.call.CallPolicies;
import com.avaya.collaboration.call.CallTerminationPolicy;
import com.avaya.collaboration.call.Participant;
import com.avaya.collaboration.call.ParticipantFactory;
import com.avaya.collaboration.call.media.DigitCollectorOperationCause;
import com.avaya.collaboration.dal.factory.CollaborationDataFactory;
import com.avaya.collaboration.util.logger.Logger;
import com.avaya.zephyr.platform.dal.api.ServiceDescriptor;
import com.avaya.zephyr.platform.dal.api.ServiceUtil;

@RunWith(PowerMockRunner.class)
@PrepareForTest(
{ CollaborationDataFactory.class, ServiceUtil.class, ParticipantFactory.class })
public class CallingPoliciesMediaListenerTest
{
    private static final DigitCollectorOperationCause CAUSE = DigitCollectorOperationCause.NUMBER_OF_DIGITS;
    private static final String DOMAIN = "avaya.com";
    private static final String CALLER = "3404@avaya.com";
    private static final String CALLED = "3403@avaya.com";
    private static final String CALLER_NO_DOMAIN = "3404";
    private static final String CALLED_NO_DOMAIN = "3403";
    private static final String CALLER_DISPLAY = "Trying Fork...3404";
    private static final String CALLED_DISPLAY = "Trying Fork...3403";
    private static final String RDR_NUM = "3405@avaya.com";
    private static final String LOG_RDR = "digitsCollected: attempting to redirect to=";
    private static final String LOG_WRN = "checkDigitRange: invalid digit exception=";
    private static final String LOG_WRN_DFLT = "digitsCollected: invalid digit=";
    @Mock
    private ServiceDescriptor svcDesc;
    @Mock
    private ServiceData svcData;
    @Mock
    private ServiceAttributeReader svcAttrRdr;
    @Mock
    private Call call;
    @Mock
    private Participant caller, called;
    @Mock
    private CallPolicies callPolicies;
    @Mock
    private Logger logger;
    private CallingPoliciesMediaListener clngPcsMediaLstnr;

    @Before
    public void setUp() throws Exception
    {
        PowerMockito.mockStatic(ServiceUtil.class);
        PowerMockito.mockStatic(CollaborationDataFactory.class);
        PowerMockito.mockStatic(ParticipantFactory.class);

        when(caller.getHandle()).thenReturn(CALLER_NO_DOMAIN);
        when(caller.getDomain()).thenReturn(DOMAIN);
        when(caller.getAddress()).thenReturn(CALLER);
        when(called.getHandle()).thenReturn(CALLED_NO_DOMAIN);
        when(called.getDomain()).thenReturn(DOMAIN);
        when(called.getAddress()).thenReturn(CALLED);
        when(call.getCallingParty()).thenReturn(caller);
        when(call.getCalledParty()).thenReturn(called);
        when(call.isCallingPhase()).thenReturn(true);
        when(call.getCallPolicies()).thenReturn(callPolicies);
        when(logger.isFinestEnabled()).thenReturn(true);
        when(ServiceUtil.getServiceDescriptor()).thenReturn(svcDesc);
        final String svcDescName = svcDesc.getName();
        final String svcDescVersion = svcDesc.getVersion();
        when(CollaborationDataFactory.getServiceData(svcDescName, svcDescVersion)).thenReturn(svcData);
        clngPcsMediaLstnr = new CallingPoliciesMediaListener(call, logger);
    }

    @Test
    public void digitsCollected_fork() throws Exception
    {
        final List<String> forkDest = new ArrayList<String>();
        when(svcData.getServiceAttribute(CALLER, "forkDestination1Attribute")).thenReturn(CALLER);
        when(svcData.getServiceAttribute(Matchers.anyString(), Matchers.anyString())).thenReturn(CALLER);
        when(svcData.getServiceAttribute(CALLED, "forkDestination2Attribute")).thenReturn(CALLED);
        forkDest.add(svcData.getServiceAttribute(CALLER, "forkDestination1Attribute"));
        forkDest.add(svcData.getServiceAttribute(CALLED, "forkDestination2Attribute"));
        when(svcAttrRdr.getForkedDestinations((Participant) Matchers.anyObject())).thenReturn(forkDest);
        when(ParticipantFactory.create(CALLER_NO_DOMAIN, DOMAIN, CALLER_DISPLAY)).thenReturn(caller);
        when(ParticipantFactory.create(CALLED_NO_DOMAIN, DOMAIN, CALLED_DISPLAY)).thenReturn(called);
        clngPcsMediaLstnr.digitsCollected(UUID.randomUUID(), "4", CAUSE);

        verify(logger).finer("digitsCollected ENTER " + 4);
        verify(call).allow();
        verify(call).addParticipant(caller);
        verify(call).addParticipant(called);
    }

    @Test
    public void digitsCollected_redirect() throws Exception
    {
        when(svcData.getServiceAttribute(Matchers.anyString(), Matchers.anyString())).thenReturn(RDR_NUM);
        clngPcsMediaLstnr.digitsCollected(UUID.randomUUID(), "3", CAUSE);

        verify(logger).finer("digitsCollected ENTER " + 3);
        verify(svcData).getServiceAttribute(CALLED, "redirectDestinationAttribute");
        verify(logger).finest(LOG_RDR + RDR_NUM);
        verify(call).divertTo(RDR_NUM);
    }

    @Test
    public void digitsCollected_redirect_logDisabled() throws Exception
    {
        when(logger.isFinestEnabled()).thenReturn(false);
        when(svcData.getServiceAttribute(Matchers.anyString(), Matchers.anyString())).thenReturn(RDR_NUM);
        clngPcsMediaLstnr.digitsCollected(UUID.randomUUID(), "3", CAUSE);

        verify(svcData).getServiceAttribute(CALLED, "redirectDestinationAttribute");
        verify(call).divertTo(RDR_NUM);
    }

    @Test
    public void digitsCollected_allow()
    {
        clngPcsMediaLstnr.digitsCollected(UUID.randomUUID(), "1", CAUSE);

        verify(logger).finer("digitsCollected ENTER " + 1);
        verify(call).allow();
    }

    @Test
    public void digitsCollected_drop()
    {
        clngPcsMediaLstnr.digitsCollected(UUID.randomUUID(), "2", CAUSE);

        verify(logger).finer("digitsCollected ENTER " + 2);
        verify(call).drop();
    }

    @Test
    public void digitsCollected_seqFork()
    {
        clngPcsMediaLstnr.digitsCollected(UUID.randomUUID(), "5", CAUSE);

        verify(logger).finer("digitsCollected ENTER " + 5);
        verify(callPolicies).setCallTerminationPolicy(CallTerminationPolicy.NO_PARTICIPANT_REMAINS);
        verify(call).allow();
    }

    @Test
    public void digitsCollected_makeAnotherCall()
    {
        clngPcsMediaLstnr.digitsCollected(UUID.randomUUID(), "6", CAUSE);

        verify(logger).finer("digitsCollected ENTER " + 6);
        verify(callPolicies).setCallTerminationPolicy(CallTerminationPolicy.NO_PARTICIPANT_REMAINS);
        verify(call).allow();
    }

    @Test
    public void digitsCollected_callback()
    {
        clngPcsMediaLstnr.digitsCollected(UUID.randomUUID(), "7", CAUSE);

        verify(logger).finer("digitsCollected ENTER " + 7);
        verify(callPolicies).setCallTerminationPolicy(CallTerminationPolicy.NO_PARTICIPANT_REMAINS);
        verify(call).allow();
    }

    @Test
    public void digitsCollected_exception()
    {
        final NullPointerException npe = new NullPointerException();
        doThrow(npe).when(call).getCallPolicies();
        clngPcsMediaLstnr.digitsCollected(UUID.randomUUID(), "7", CAUSE);

        verify(logger).finer("digitsCollected ENTER " + 7);
        verify(call).drop();
    }

    @Test
    public void digitsCollected_invalidDigit() throws Exception
    {
        clngPcsMediaLstnr.digitsCollected(UUID.randomUUID(), "*", CAUSE);

        verify(logger).warn("digitsCollected: invalid digit=" + "*");
        verify(logger).warn(LOG_WRN + Matchers.anyString());
        verify(logger).warn(LOG_WRN_DFLT + Matchers.anyString());
        verify(call).drop();
    }
}
