package com.avaya.zephyr.services.dynamicteamformation.email;

import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.powermock.api.easymock.PowerMock.createMock;
import static org.powermock.api.easymock.PowerMock.expectLastCall;
import static org.powermock.api.easymock.PowerMock.expectNew;
import static org.powermock.api.easymock.PowerMock.mockStatic;
import static org.powermock.api.easymock.PowerMock.replayAll;
import static org.powermock.api.easymock.PowerMock.verifyAll;

import java.io.PrintWriter;
import java.util.ArrayList;

import javax.servlet.http.HttpServletRequest;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import com.avaya.collaboration.businessdata.api.NoAttributeFoundException;
import com.avaya.collaboration.businessdata.api.ServiceData;
import com.avaya.collaboration.conference.scheduled.SchedConf;
import com.avaya.collaboration.email.EmailFactory;
import com.avaya.collaboration.email.EmailRequest;
import com.avaya.collaboration.util.logger.Logger;

@RunWith(PowerMockRunner.class)
@PrepareForTest(
{ DynamicTeamFormationEmailSender.class, EmailRequest.class, EmailFactory.class,
        DynamicTeamFormationEmailListener.class })
public class DynamicTeamFormationEmailSenderTest
{

    private static final String EMAIL_PARAM_HTTP_TO = "emailTo";
    private static final String EMAIL_INFO_NO_TO_LOG =
            "Info: No email recipients specified in the HTTP request.";
    private static final String EMAIL_INFO_NOT_SENT_LOG = "Info: Email will not be sent.";
    private static final String EMAIL_PARAM_HTTP_SUBJECT = "emailSubject";
    private static final String EMAIL_INFO_NO_SUBJECT_LOG =
            "Info: No email subject specified in HTTP request.";
    private static final String EMAIL_PARAM_HTTP_BODY = "emailBody";
    private static final String EMAIL_INFO_NO_BODY_LOG = "Info: No email body specified in HTTP request.";
    private static final String EMAIL_PARAM_SMGR_FROM = "emailFrom";
    private static final String EMAIL_ERROR_FROM_LOG =
            "Error: Error occured acquiring 'from' email address from SMGR.";
    private static final String EMAIL_INFO_USE_EC_FROM_LOG =
            "Will attempt to use the email connector's 'default sender' attribute for the 'from' address.";
    private static final String EMAIL_INFO_NO_FROM_LOG =
            "Info: No 'from' email address specified in the DynamicTeamFormationService attribute page on SMGR.";
    private static final String EMAIL_PARAM_SMGR_REPLYTO = "emailReplyTo";
    private static final String EMAIL_ERROR_REPLYTO_LOG =
            "Error: Error occured acquiring 'replyTo' email address from SMGR.";
    private DynamicTeamFormationEmailSender dynamicTeamFormationEmailSenderTest;
    private Logger mockLogger;
    private PrintWriter mockPrintWriter;
    private HttpServletRequest mockHttpServletRequest;
    private ServiceData mockServiceData;
    private EmailRequest mockEmailRequest;
    private SchedConf mockSchedConf;
    private DynamicTeamFormationEmailListener mockDynamicTeamFormationEmailListener;

    @Before
    public void setUpMockCommon() throws Exception
    {
        mockLogger = createMock(Logger.class);
        mockPrintWriter = createMock(PrintWriter.class);
        mockServiceData = createMock(ServiceData.class);
        mockHttpServletRequest = createMock(HttpServletRequest.class);
        mockEmailRequest = createMock(EmailRequest.class);
        mockSchedConf = createMock(SchedConf.class);

        mockDynamicTeamFormationEmailListener =
                createMock(DynamicTeamFormationEmailListener.class, mockEmailRequest);

        dynamicTeamFormationEmailSenderTest =
                new DynamicTeamFormationEmailSender(mockServiceData, mockHttpServletRequest,
                        mockPrintWriter, mockLogger);
    }

    private void setupMockEmailTo(String[] emailTo)
    {
        expect(mockHttpServletRequest
                .getParameterValues(EMAIL_PARAM_HTTP_TO))
                .andReturn(emailTo);

        boolean emailToEveryEntryEmpty = true;
        if (emailTo != null)
        {
            for (String emailToEntry : emailTo)
            {
                if (!emailToEntry.isEmpty())
                {
                    emailToEveryEntryEmpty = false;
                    break;
                }
            }
        }

        if (emailTo == null || emailToEveryEntryEmpty)
        {
            setupMockLogHttpResponseInfo(EMAIL_INFO_NO_TO_LOG);
            setupMockLogHttpResponseInfo(EMAIL_INFO_NOT_SENT_LOG);
        }
    }

    private void setupMockEmailSubject(String[] emailSubject)
    {
        expect(mockHttpServletRequest
                .getParameterValues(EMAIL_PARAM_HTTP_SUBJECT))
                .andReturn(emailSubject);

        boolean emailSubjectEveryEntryEmpty = true;
        if (emailSubject != null)
        {
            for (String emailToEntry : emailSubject)
            {
                if (!emailToEntry.isEmpty())
                {
                    emailSubjectEveryEntryEmpty = false;
                    break;
                }
            }
        }

        if (emailSubject == null || emailSubjectEveryEntryEmpty)
        {
            setupMockLogHttpResponseInfo(EMAIL_INFO_NO_SUBJECT_LOG);
            setupMockLogHttpResponseInfo(EMAIL_INFO_NOT_SENT_LOG);
        }
    }

    private void setupMockEmailBody(String[] emailBody)
    {
        expect(mockHttpServletRequest
                .getParameterValues(EMAIL_PARAM_HTTP_BODY))
                .andReturn(emailBody);

        boolean emailBodyEveryEntryEmpty = true;
        if (emailBody != null)
        {
            for (String emailToEntry : emailBody)
            {
                if (!emailToEntry.isEmpty())
                {
                    emailBodyEveryEntryEmpty = false;
                    break;
                }
            }
        }

        if (emailBody == null || emailBodyEveryEntryEmpty)
        {
            setupMockLogHttpResponseInfo(EMAIL_INFO_NO_BODY_LOG);
            setupMockLogHttpResponseInfo(EMAIL_INFO_NOT_SENT_LOG);
        }
        else
        {
            expect(mockSchedConf.getUrl()).andReturn("mockUrl");
        }
    }

    private void setupMockEmailFrom(String emailFrom) throws Exception
    {
        if (emailFrom == null)
        {
            expect(mockServiceData
                    .getServiceAttribute(EMAIL_PARAM_SMGR_FROM))
                    .andThrow(new NoAttributeFoundException(
                            EMAIL_PARAM_SMGR_FROM));
            setupMockLogHttpResponseError(EMAIL_ERROR_FROM_LOG);
            setupMockLogHttpResponseInfo(EMAIL_INFO_USE_EC_FROM_LOG);
        }
        else
        {
            expect(mockServiceData
                    .getServiceAttribute(EMAIL_PARAM_SMGR_FROM))
                    .andReturn(emailFrom);
            if (emailFrom.isEmpty())
            {
                setupMockLogHttpResponseInfo(EMAIL_INFO_NO_FROM_LOG);
                setupMockLogHttpResponseInfo(EMAIL_INFO_USE_EC_FROM_LOG);
            }
        }
    }

    private void setupMockEmailReplyTo(String emailReplyTo) throws Exception
    {
        if (emailReplyTo == null)
        {
            expect(mockServiceData
                    .getServiceAttribute(EMAIL_PARAM_SMGR_REPLYTO))
                    .andThrow(new NoAttributeFoundException(
                            EMAIL_PARAM_SMGR_REPLYTO));
            setupMockLogHttpResponseError(EMAIL_ERROR_REPLYTO_LOG);
        }
        else
        {
            expect(mockServiceData
                    .getServiceAttribute(EMAIL_PARAM_SMGR_REPLYTO))
                    .andReturn(emailReplyTo);
        }
    }

    private void setupMockEmailRequest() throws Exception
    {
        mockStatic(EmailFactory.class);
        expect(EmailFactory.createEmailRequest()).andReturn(mockEmailRequest);
        expect(mockEmailRequest.setFrom((String) anyObject())).andReturn(mockEmailRequest);
        expect(mockEmailRequest.setReplyTo((String) anyObject())).andReturn(mockEmailRequest);
        expect(mockEmailRequest.getTo()).andReturn(new ArrayList<String>()).anyTimes();
        expect(mockEmailRequest.setSubject((String) anyObject())).andReturn(mockEmailRequest);
        expect(mockEmailRequest.setTextBody((String) anyObject())).andReturn(mockEmailRequest);
        expectNew(DynamicTeamFormationEmailListener.class, mockEmailRequest).andReturn(
                mockDynamicTeamFormationEmailListener);
        expect(mockEmailRequest.setListener(mockDynamicTeamFormationEmailListener)).andReturn(
                mockEmailRequest);
        mockEmailRequest.send();
        expectLastCall();
        setupMockLogHttpResponseInfo(null);
    }

    private void setupMockLogHttpResponseInfo(String logInfo)
    {
        if (logInfo == null)
        {
            mockLogger.info((String) anyObject());
            expectLastCall();
            mockPrintWriter.println((String) anyObject());
            expectLastCall();
        }
        else
        {
            mockLogger.info(logInfo);
            expectLastCall();
            mockPrintWriter.println(logInfo);
            expectLastCall();
        }
    }

    private void setupMockLogHttpResponseError(String logError)
    {
        if (logError == null)
        {
            mockLogger.error((String) anyObject());
            expectLastCall();
            mockPrintWriter.println((String) anyObject());
            expectLastCall();
        }
        else
        {
            mockLogger.error((String) anyObject(), (Exception) anyObject());
            expectLastCall();
            mockPrintWriter.println(logError);
            expectLastCall();
        }
    }

    @Test
    public void testSendEmail() throws Exception
    {
        // Test Info
        // sendEmail needs the HTTP request to have the 'to',
        // 'subject', and 'body' email fields

        // Test Data
        final String[] emailToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] emailSubject =
        { "test subject" };
        final String[] emailBody =
        { "test body" };
        final String emailFrom = "from@domain.com";
        final String emailReplyTo = "replyTo@domain.com";

        // Setup mocks
        setupMockEmailTo(emailToMultipleCommaMixed);
        setupMockEmailSubject(emailSubject);
        setupMockEmailBody(emailBody);
        setupMockEmailFrom(emailFrom);
        setupMockEmailReplyTo(emailReplyTo);
        setupMockEmailRequest();

        // Replay, Execute, and Verify
        replayAll();
        assertTrue(dynamicTeamFormationEmailSenderTest.sendEmail(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendEmailNullTo() throws Exception
    {
        // Test Info
        // sendEmail needs the HTTP request to have the 'to',
        // 'subject', and 'body' email fields.

        // Test Data
        final String[] emailToNull = null;
        final String[] emailSubject =
        { "test subject" };
        final String[] emailBody =
        { "test body" };

        // Setup mocks
        setupMockEmailTo(emailToNull);
        setupMockEmailSubject(emailSubject);
        setupMockEmailBody(emailBody);

        // Replay, Execute, and Verify
        replayAll();
        assertFalse(dynamicTeamFormationEmailSenderTest.sendEmail(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendEmailEmptyTo() throws Exception
    {
        // Test Info
        // sendEmail needs the HTTP request to have the 'to',
        // 'subject', and 'body' email fields.

        // Test Data
        final String[] emailToEmpty =
        { "" };
        final String[] emailSubject =
        { "test subject" };
        final String[] emailBody =
        { "test body" };

        // Setup mocks
        setupMockEmailTo(emailToEmpty);
        setupMockEmailSubject(emailSubject);
        setupMockEmailBody(emailBody);

        // Replay, Execute, and Verify
        replayAll();
        assertFalse(dynamicTeamFormationEmailSenderTest.sendEmail(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendEmailNullSubject() throws Exception
    {
        // Test Info
        // sendEmail needs the HTTP request to have the 'to',
        // 'subject', and 'body' email fields.

        // Test Data
        final String[] emailToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] emailSubjectNull = null;
        final String[] emailBody =
        { "test body" };

        // Setup mocks
        setupMockEmailTo(emailToMultipleCommaMixed);
        setupMockEmailSubject(emailSubjectNull);
        setupMockEmailBody(emailBody);

        // Replay, Execute, and Verify
        replayAll();
        assertFalse(dynamicTeamFormationEmailSenderTest.sendEmail(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendEmailEmptySubject() throws Exception
    {
        // Test Info
        // sendEmail needs the HTTP request to have the 'to',
        // 'subject', and 'body' email fields.

        // Test Data
        final String[] emailToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] emailSubjectEmpty =
        { "" };
        final String[] emailBody =
        { "test body" };

        // Setup mocks
        setupMockEmailTo(emailToMultipleCommaMixed);
        setupMockEmailSubject(emailSubjectEmpty);
        setupMockEmailBody(emailBody);

        // Replay, Execute, and Verify
        replayAll();
        assertFalse(dynamicTeamFormationEmailSenderTest.sendEmail(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendEmailNullBody() throws Exception
    {
        // Test Info
        // sendEmail needs the HTTP request to have the 'to',
        // 'subject', and 'body' email fields.

        // Test Data
        final String[] emailToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] emailSubject =
        { "test subject" };
        final String[] emailBodyNull = null;

        // Setup mocks
        setupMockEmailTo(emailToMultipleCommaMixed);
        setupMockEmailSubject(emailSubject);
        setupMockEmailBody(emailBodyNull);

        // Replay, Execute, and Verify
        replayAll();
        assertFalse(dynamicTeamFormationEmailSenderTest.sendEmail(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendEmailEmptyBody() throws Exception
    {
        // Test Info
        // sendEmail needs the HTTP request to have the 'to',
        // 'subject', and 'body' email fields.

        // Test Data
        final String[] emailToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] emailSubject =
        { "test subject" };
        final String[] emailBodyEmpty =
        { "" };

        // Setup mocks
        setupMockEmailTo(emailToMultipleCommaMixed);
        setupMockEmailSubject(emailSubject);
        setupMockEmailBody(emailBodyEmpty);

        // Replay, Execute, and Verify
        replayAll();
        assertFalse(dynamicTeamFormationEmailSenderTest.sendEmail(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendEmailEmptyFrom() throws Exception
    {
        // Test Info
        // sendEmail needs the HTTP request to have the 'to',
        // 'subject', and 'body' email fields

        // Test Data
        final String[] emailToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] emailSubject =
        { "test subject" };
        final String[] emailBody =
        { "test body" };
        final String emailFromEmpty = "";
        final String emailReplyTo = "replyTo@domain.com";

        // Setup mocks
        setupMockEmailTo(emailToMultipleCommaMixed);
        setupMockEmailSubject(emailSubject);
        setupMockEmailBody(emailBody);
        setupMockEmailFrom(emailFromEmpty);
        setupMockEmailReplyTo(emailReplyTo);
        setupMockEmailRequest();

        // Replay, Execute, and Verify
        replayAll();
        assertTrue(dynamicTeamFormationEmailSenderTest.sendEmail(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendEmailExceptionFrom() throws Exception
    {
        // Test Info
        // sendEmail needs the HTTP request to have the 'to',
        // 'subject', and 'body' email fields

        // Test Data
        final String[] emailToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] emailSubject =
        { "test subject" };
        final String[] emailBody =
        { "test body" };
        final String emailFrom = null;
        final String emailReplyTo = "replyTo@domain.com";

        // Setup mocks
        setupMockEmailTo(emailToMultipleCommaMixed);
        setupMockEmailSubject(emailSubject);
        setupMockEmailBody(emailBody);
        setupMockEmailFrom(emailFrom);
        setupMockEmailReplyTo(emailReplyTo);
        setupMockEmailRequest();

        // Replay, Execute, and Verify
        replayAll();
        assertTrue(dynamicTeamFormationEmailSenderTest.sendEmail(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendEmailReplyToEmpty() throws Exception
    {
        // Test Info
        // sendEmail needs the HTTP request to have the 'to',
        // 'subject', and 'body' email fields, and the SMGR attribute 'email
        // from' field to be present

        // Test Data
        final String[] emailToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] emailSubject =
        { "test subject" };
        final String[] emailBody =
        { "test body" };
        final String emailFrom = "from@domain.com";
        final String emailReplyToEmpty = "";

        // Setup mocks
        setupMockEmailTo(emailToMultipleCommaMixed);
        setupMockEmailSubject(emailSubject);
        setupMockEmailBody(emailBody);
        setupMockEmailFrom(emailFrom);
        setupMockEmailReplyTo(emailReplyToEmpty);
        setupMockEmailRequest();

        // Replay, Execute, and Verify
        replayAll();
        assertTrue(dynamicTeamFormationEmailSenderTest.sendEmail(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendEmailExceptionReplyTo() throws Exception
    {
        // Test Info
        // sendEmail needs the HTTP request to have the 'to',
        // 'subject', and 'body' email fields

        // Test Data
        final String[] emailToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] emailSubject =
        { "test subject" };
        final String[] emailBody =
        { "test body" };
        final String emailFrom = "from@domain.com";
        final String emailReplyToNull = null;

        // Setup mocks
        setupMockEmailTo(emailToMultipleCommaMixed);
        setupMockEmailSubject(emailSubject);
        setupMockEmailBody(emailBody);
        setupMockEmailFrom(emailFrom);
        setupMockEmailReplyTo(emailReplyToNull);
        setupMockEmailRequest();

        // Replay, Execute, and Verify
        replayAll();
        assertTrue(dynamicTeamFormationEmailSenderTest.sendEmail(mockSchedConf));
        verifyAll();
    }

}
