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

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import com.avaya.collaboration.call.Call;
import com.avaya.collaboration.call.CallTerminationPolicy;
import com.avaya.collaboration.call.media.DigitCollectorOperationCause;
import com.avaya.collaboration.call.media.MediaListenerAbstract;
import com.avaya.collaboration.util.logger.Logger;

public final class CallingPoliciesMediaListener extends MediaListenerAbstract
{
    private final Call call;
    private final ForkingOperation forkOperation;
    private final ServiceAttributeReader serviceAttributeReader;

    public static final String NO_SELECTION = "";
    public static final String ALLOW_DIGIT1 = "1"; // Allow Call option
    public static final String DROP_DIGIT2 = "2"; // Drop Call option
    public static final String REDIRECT_DIGIT3 = "3"; // Redirect Call option
    public static final String PARALLELFORK_DIGIT4 = "4"; // Parallel Forking option
    public static final String SEQUENTIALFORK_DIGIT5 = "5"; // Sequential Forking option
    public static final String MAKEANOTHERCALL_DIGIT6 = "6"; // Serial Calling - Make Another Call option
    public static final String CALLBACK_DIGIT7 = "7"; // Serial Calling - Call Back option
    public static final String NOANSWERTIMER_ENABLED = "NOANSWERTIMER_ENABLED";
    public static final String YES = "Y";
    public static final String NO = "N";
    public static final Map<String, String> callDigitSelectMap = Collections.synchronizedMap(new HashMap<String, String>());

    private final Logger logger;

    public CallingPoliciesMediaListener(final Call call)
    {
        this(call, Logger.getLogger(CallingPoliciesMediaListener.class));
    }

    public CallingPoliciesMediaListener(final Call call, final Logger logger)
    {
        this(call, new ForkingOperationImpl(), new ServiceAttributeReaderImpl(), logger);
    }

    CallingPoliciesMediaListener(final Call call, final ForkingOperation forkOperation,
            final ServiceAttributeReader serviceAttributeReader, final Logger logger)
    {
        this.call = call;
        this.forkOperation = forkOperation;
        this.serviceAttributeReader = serviceAttributeReader;
        this.logger = logger;
    }

    @Override
    public void digitsCollected(final UUID requestId, final String digits,
            final DigitCollectorOperationCause cause)
    {
        logger.finer("digitsCollected ENTER " + digits);
        CallingPoliciesMediaListener.callDigitSelectMap.put(call.getId(), digits);
        call.setAttribute(NOANSWERTIMER_ENABLED, YES);

        try
        {
            switch (digits)
            {
                case ALLOW_DIGIT1:
                    call.allow();
                    break;
                case DROP_DIGIT2:
                    call.drop();
                    break;
                case REDIRECT_DIGIT3:
                    final String redirectNumber = serviceAttributeReader.getRedirectNumber(call.getCalledParty());
                    if (logger.isFinestEnabled())
                    {
                        logger.finest("digitsCollected: attempting to redirect to=" + redirectNumber);
                    }
                    call.divertTo(redirectNumber);
                    break;
                case PARALLELFORK_DIGIT4:
                    call.allow();
                    forkOperation.forkTo(call);
                    break;
                case SEQUENTIALFORK_DIGIT5:
                case MAKEANOTHERCALL_DIGIT6:
                case CALLBACK_DIGIT7:
                    // Set the Call Termination Policy to NO_PARTICIPANT_REMAINS.
                    // It means to clear the call when no Participant remains in
                    // the call (i.e., the last remaining Participant dropped).
                    call.getCallPolicies().setCallTerminationPolicy(CallTerminationPolicy.NO_PARTICIPANT_REMAINS);
                    call.allow();
                    break;
                default:
                    logger.warn("digitsCollected: invalid digit=" + digits);
                    call.drop();
                    break;
            }
        }
        catch (final Exception e)
        {
            logger.error("digitsCollected: failed operation exception=", e);
            call.drop();
        }
        logger.finer("digitsCollected EXIT ");
    }
}
