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

import static org.easymock.EasyMock.anyInt;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.fail;
import static org.powermock.api.easymock.PowerMock.createMock;
import static org.powermock.api.easymock.PowerMock.expectLastCall;
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.Calendar;

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.businessdata.api.ServiceNotFoundException;
import com.avaya.collaboration.conference.scheduled.SchedConf;
import com.avaya.collaboration.conference.scheduled.SchedConfFactory;
import com.avaya.collaboration.util.logger.Logger;

@RunWith(PowerMockRunner.class)
@PrepareForTest(
{ DynamicTeamFormationConferenceScheduler.class, SchedConf.class, SchedConfFactory.class })
public class DynamicTeamFormationConferenceSchedulerTest
{

    private static final String CONF_PARAM_SMGR_DURATION = "conferenceMaxDurationHours";
    private static final String CONF_ERROR_DURATION_LOG =
            "Error: Error occured acquiring 'Conference Maximum Duration' from SMGR. Defaulting to 2 hours.";;
    private static final String CONF_INFO_NO_CONF_DURATION_LOG =
            "Info: No 'Conference Maximum Duration' specified in the DynamicTeamFormationService attribute page on SMGR. Defaulting to 2 hours.";;
    private static final String CONF_INFO_TOO_LARGE_CONF_DURATION_LOG =
            "Info: 'Conference Maximum Duration' specified in the DynamicTeamFormationService attribute page on SMGR is too large. Setting to maximum 720 hours.";
    private static final String CONF_PARAM_HTTP_SUBJECT = "conferenceSubject";
    private static final String CONF_INFO_NO_SUBJECT_LOG =
            "Info: No conference subject specified in HTTP request.";
    private static final String CONF_PARAM_HTTP_DESCRIPTION = "conferenceDescription";
    private static final String CONF_INFO_NO_DESCRIPTION_LOG =
            "Info: No conference description specified in HTTP request.";
    private DynamicTeamFormationConferenceScheduler dynamicTeamFormationConferenceSchedulerTest;
    private Logger mockLogger;
    private PrintWriter mockPrintWriter;
    private HttpServletRequest mockHttpServletRequest;
    private ServiceData mockServiceData;
    private SchedConf mockSchedConf;

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

        dynamicTeamFormationConferenceSchedulerTest =
                new DynamicTeamFormationConferenceScheduler(mockServiceData, mockHttpServletRequest,
                        mockPrintWriter, mockLogger);
    }

    public void setupMockConferenceDuration(String conferenceDuration) throws NoAttributeFoundException,
            ServiceNotFoundException
    {
        if (conferenceDuration == null)
        {
            expect(
                    mockServiceData
                            .getServiceAttribute(CONF_PARAM_SMGR_DURATION))
                    .andThrow(new NoAttributeFoundException(
                            CONF_PARAM_SMGR_DURATION));
            setupMockLogHttpResponseError(CONF_ERROR_DURATION_LOG);
        }
        else
        {
            expect(
                    mockServiceData
                            .getServiceAttribute(CONF_PARAM_SMGR_DURATION))
                    .andReturn(conferenceDuration);
            if (conferenceDuration.isEmpty())
            {
                setupMockLogHttpResponseInfo(CONF_INFO_NO_CONF_DURATION_LOG);
            }
            else if (Integer.parseInt(conferenceDuration) > 720)
            {
                setupMockLogHttpResponseInfo(CONF_INFO_TOO_LARGE_CONF_DURATION_LOG);
            }
        }
    }

    private void setupMockConferenceSubject(String[] conferenceSubject)
    {
        expect(mockHttpServletRequest
                .getParameterValues(CONF_PARAM_HTTP_SUBJECT))
                .andReturn(conferenceSubject);

        boolean conferenceSubjectEveryEntryEmpty = true;
        if (conferenceSubject != null)
        {
            for (String conferenceSubjectToEntry : conferenceSubject)
            {
                if (!conferenceSubjectToEntry.isEmpty())
                {
                    conferenceSubjectEveryEntryEmpty = false;
                    break;
                }
            }
        }

        if (conferenceSubject == null || conferenceSubjectEveryEntryEmpty)
        {
            setupMockLogHttpResponseInfo(CONF_INFO_NO_SUBJECT_LOG);
        }
    }

    private void setupMockConferenceDescription(String[] conferenceDescription)
    {
        expect(mockHttpServletRequest
                .getParameterValues(CONF_PARAM_HTTP_DESCRIPTION))
                .andReturn(conferenceDescription);

        boolean conferenceDescriptionEveryEntryEmpty = true;
        if (conferenceDescription != null)
        {
            for (String conferenceDescriptionToEntry : conferenceDescription)
            {
                if (!conferenceDescriptionToEntry.isEmpty())
                {
                    conferenceDescriptionEveryEntryEmpty = false;
                    break;
                }
            }
        }

        if (conferenceDescription == null || conferenceDescriptionEveryEntryEmpty)
        {
            setupMockLogHttpResponseInfo(CONF_INFO_NO_DESCRIPTION_LOG);
        }
    }

    private void setupMockConference() throws Exception
    {
        mockStatic(SchedConfFactory.class);
        expect(SchedConfFactory.createConf()).andReturn(mockSchedConf);
        expect(mockSchedConf.setSubject((String) anyObject())).andReturn(mockSchedConf);
        expect(mockSchedConf.setDescription((String) anyObject())).andReturn(mockSchedConf);
        expect(mockSchedConf.setStartTime((Calendar) anyObject())).andReturn(mockSchedConf);
        expect(mockSchedConf.setDuration(anyInt(), anyInt(), anyInt()))
                .andReturn(mockSchedConf);
        mockSchedConf.schedule();
        expectLastCall();
    }

    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 testScheduleConference() throws Exception
    {
        // Test Info

        // Test Data
        final String conferenceDuration = "4";
        final String[] conferenceSubject =
        { "conference subject" };
        final String[] conferenceDescription =
        { "conference description" };

        // Setup mocks
        setupMockConferenceDuration(conferenceDuration);
        setupMockConferenceSubject(conferenceSubject);
        setupMockConferenceDescription(conferenceDescription);
        setupMockConference();

        // Replay, Execute, and Verify
        replayAll();
        try
        {
            dynamicTeamFormationConferenceSchedulerTest.scheduleConference();
        }
        catch (Exception e)
        {
            fail("scheduleConference threw exception " + e);
        }
        verifyAll();
    }

    @Test
    public void testScheduleConferenceDurationEmpty() throws Exception
    {
        // Test Info

        // Test Data
        final String conferenceDuration = "";
        final String[] conferenceSubject =
        { "conference subject" };
        final String[] conferenceDescription =
        { "conference description" };

        // Setup mocks
        setupMockConferenceDuration(conferenceDuration);
        setupMockConferenceSubject(conferenceSubject);
        setupMockConferenceDescription(conferenceDescription);
        setupMockConference();

        // Replay, Execute, and Verify
        replayAll();
        try
        {
            dynamicTeamFormationConferenceSchedulerTest.scheduleConference();
        }
        catch (Exception e)
        {
            fail("scheduleConference threw exception " + e);
        }
        verifyAll();
    }

    @Test
    public void testScheduleConferenceDurationException() throws Exception
    {
        // Test Info

        // Test Data
        final String conferenceDuration = null;
        final String[] conferenceSubject =
        { "conference subject" };
        final String[] conferenceDescription =
        { "conference description" };

        // Setup mocks
        setupMockConferenceDuration(conferenceDuration);
        setupMockConferenceSubject(conferenceSubject);
        setupMockConferenceDescription(conferenceDescription);
        setupMockConference();

        // Replay, Execute, and Verify
        replayAll();
        try
        {
            dynamicTeamFormationConferenceSchedulerTest.scheduleConference();
        }
        catch (Exception e)
        {
            fail("scheduleConference threw exception " + e);
        }
        verifyAll();
    }

    @Test
    public void testScheduleConferenceSubjectEmpty() throws Exception
    {
        // Test Info

        // Test Data
        final String conferenceDuration = "4";
        final String[] conferenceSubject =
        { "" };
        final String[] conferenceDescription =
        { "conference description" };

        // Setup mocks
        setupMockConferenceDuration(conferenceDuration);
        setupMockConferenceSubject(conferenceSubject);
        setupMockConferenceDescription(conferenceDescription);
        setupMockConference();

        // Replay, Execute, and Verify
        replayAll();
        try
        {
            dynamicTeamFormationConferenceSchedulerTest.scheduleConference();
        }
        catch (Exception e)
        {
            fail("scheduleConference threw exception " + e);
        }
        verifyAll();
    }

    @Test
    public void testScheduleConferenceSubjectException() throws Exception
    {
        // Test Info

        // Test Data
        final String conferenceDuration = "4";
        final String[] conferenceSubject = null;
        final String[] conferenceDescription =
        { "conference description" };

        // Setup mocks
        setupMockConferenceDuration(conferenceDuration);
        setupMockConferenceSubject(conferenceSubject);
        setupMockConferenceDescription(conferenceDescription);
        setupMockConference();

        // Replay, Execute, and Verify
        replayAll();
        try
        {
            dynamicTeamFormationConferenceSchedulerTest.scheduleConference();
        }
        catch (Exception e)
        {
            fail("scheduleConference threw exception " + e);
        }
        verifyAll();
    }

    @Test
    public void testScheduleConferenceDescriptionEmpty() throws Exception
    {
        // Test Info

        // Test Data
        final String conferenceDuration = "4";
        final String[] conferenceSubject =
        { "conference subject" };
        final String[] conferenceDescription =
        { "" };

        // Setup mocks
        setupMockConferenceDuration(conferenceDuration);
        setupMockConferenceSubject(conferenceSubject);
        setupMockConferenceDescription(conferenceDescription);
        setupMockConference();

        // Replay, Execute, and Verify
        replayAll();
        try
        {
            dynamicTeamFormationConferenceSchedulerTest.scheduleConference();
        }
        catch (Exception e)
        {
            fail("scheduleConference threw exception " + e);
        }
        verifyAll();
    }

    @Test
    public void testScheduleConferenceDescriptionException() throws Exception
    {
        // Test Info

        // Test Data
        final String conferenceDuration = "4";
        final String[] conferenceSubject =
        { "conference subject" };
        final String[] conferenceDescription = null;

        // Setup mocks
        setupMockConferenceDuration(conferenceDuration);
        setupMockConferenceSubject(conferenceSubject);
        setupMockConferenceDescription(conferenceDescription);
        setupMockConference();

        // Replay, Execute, and Verify
        replayAll();
        try
        {
            dynamicTeamFormationConferenceSchedulerTest.scheduleConference();
        }
        catch (Exception e)
        {
            fail("scheduleConference threw exception " + e);
        }
        verifyAll();
    }
}
