/*
 * Licensed to The OpenNMS Group, Inc (TOG) under one or more
 * contributor license agreements.  See the LICENSE.md file
 * distributed with this work for additional information
 * regarding copyright ownership.
 *
 * TOG licenses this file to You under the GNU Affero General
 * Public License Version 3 (the "License") or (at your option)
 * any later version.  You may not use this file except in
 * compliance with the License.  You may obtain a copy of the
 * License at:
 *
 *      https://www.gnu.org/licenses/agpl-3.0.txt
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied.  See the License for the specific
 * language governing permissions and limitations under the
 * License.
 */
package org.opennms.netmgt.config.mock;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;

import org.junit.Before;
import org.junit.Test;
import org.opennms.core.test.ConfigurationTestUtils;
import org.opennms.core.test.IntervalTestCase;
import org.opennms.core.test.MockLogAppender;
import org.opennms.core.utils.OwnedInterval;
import org.opennms.core.utils.OwnedIntervalSequence;
import org.opennms.core.utils.Owner;
import org.opennms.netmgt.config.GroupFactory;
import org.opennms.netmgt.config.GroupManager;
import org.opennms.netmgt.config.MonthlyCalendar;
import org.opennms.netmgt.config.UserFactory;
import org.opennms.netmgt.config.UserManager;
import org.opennms.netmgt.config.WebGroup;
import org.opennms.netmgt.config.WebGroupManager;
import org.opennms.netmgt.config.WebRole;
import org.opennms.netmgt.config.WebRoleContext;
import org.opennms.netmgt.config.WebRoleManager;
import org.opennms.netmgt.config.WebUser;
import org.opennms.netmgt.config.WebUserManager;
import org.opennms.netmgt.config.groups.Group;
import org.opennms.netmgt.config.groups.Role;
import org.opennms.netmgt.config.users.User;

public class RolesTest extends IntervalTestCase {
    private GroupManager m_groupManager;
    private UserManager m_userManager;
    private WebRoleManager m_roleMgr;
    private WebGroupManager m_groupMgr;
    private WebUserManager m_userMgr;

    @Before
    @Override
    public void setUp() throws Exception {
        super.setUp();
        
        MockLogAppender.setupLogging();
        m_groupManager = new MockGroupManager(ConfigurationTestUtils.getConfigForResourceWithReplacements(this, "/org/opennms/netmgt/config/mock/groups.xml", new String[][] {}));
        m_userManager = new MockUserManager(m_groupManager, ConfigurationTestUtils.getConfigForResourceWithReplacements(this, "/org/opennms/netmgt/config/mock/users.xml", new String[][] {}));
        
        GroupFactory.setInstance(m_groupManager);
        UserFactory.setInstance(m_userManager);
        
        m_roleMgr = WebRoleContext.getWebRoleManager();
        m_groupMgr = WebRoleContext.getWebGroupManager();
        m_userMgr = WebRoleContext.getWebUserManager();

    }

    @Test
    public void testRoles() throws Exception {
        assertNotNull(m_roleMgr);
        assertNotNull(m_roleMgr.getRoles());
        
        String[] roleNames = m_groupManager.getRoleNames();
        assertEquals(roleNames.length, m_roleMgr.getRoles().size());
        for (int i = 0; i < roleNames.length; i++) {
            String roleName = roleNames[i];
            Role role = m_groupManager.getRole(roleName);
            WebRole webRole = m_roleMgr.getRole(roleName);
            assertNotNull(webRole);
            assertRole(role, webRole);
        }
        
        for (String groupName : m_groupManager.getGroupNames()) {
            Group group = m_groupManager.getGroup(groupName);
            WebGroup webGroup = m_groupMgr.getGroup(groupName);
            assertGroup(group, webGroup);
        }
        
        for (String userName : m_userManager.getUserNames()) {
            User user = m_userManager.getUser(userName);
            WebUser webUser = m_userMgr.getUser(userName);
            assertUser(user, webUser);
        }
        
        WebRole oncall = m_roleMgr.getRole("oncall");
        assertEquals("oncall", oncall.getName());
        assertEquals(m_groupMgr.getGroup("InitialGroup"), oncall.getMembershipGroup());
        
    }
    
    @Test
    public void testWeekCount() throws Exception {
        int firstDayOfWeek = Calendar.getInstance().getFirstDayOfWeek();
        if(firstDayOfWeek != Calendar.SUNDAY && firstDayOfWeek != Calendar.MONDAY) {
            fail("Start of week is not Monday or Sunday");
        }
        
        Date aug3 = getDate("2005-08-03");
        MonthlyCalendar calendar = new MonthlyCalendar(aug3, null, null);
        assertEquals(5, calendar.getWeeks().length);
        
        Date july17 = getDate("2005-07-17");
        calendar = new MonthlyCalendar(july17, null, null);
        assertEquals(firstDayOfWeek == Calendar.SUNDAY ? 6 : 5, calendar.getWeeks().length);
        
        Date may27 = getDate("2005-05-27");
        calendar = new MonthlyCalendar(may27, null, null);
        assertEquals(firstDayOfWeek == Calendar.SUNDAY ? 5 : 6, calendar.getWeeks().length);
        
        Date feb14_04 = getDate("2004-02-14");
        calendar = new MonthlyCalendar(feb14_04, null, null);
        assertEquals(5, calendar.getWeeks().length);
        
        Date feb7_09 = getDate("2009-02-09");
        calendar = new MonthlyCalendar(feb7_09, null, null);
        assertEquals(firstDayOfWeek == Calendar.SUNDAY ? 4 : 5, calendar.getWeeks().length);
        
    }
    
    @Test
    public void testTimeIntervals() throws Exception {
        OwnedIntervalSequence intervals = m_groupManager.getRoleScheduleEntries("oncall", getDate("2005-08-18"), getDate("2005-08-19"));
        
        assertNotNull(intervals);
        
        Owner brozow = new Owner("oncall", "brozow", 1, 1);
        Owner admin = new Owner("oncall", "admin", 1, 1);
        Owner david = new Owner("oncall", "david", 1, 1);
        OwnedIntervalSequence before = new OwnedIntervalSequence();
        before.addInterval(owned(david, aug(18, 0, 9)));
        before.addInterval(owned(admin, aug(18, 9, 17)));
        before.addInterval(owned(david, aug(18, 17, 23)));
        before.addInterval(owned(brozow, aug(18, 23, 24)));

        OwnedInterval[] expected = {
                owned(david, aug(18, 0, 9)),
                owned(admin, aug(18, 9, 17)),
                owned(david, aug(18, 17, 23)),
                owned(brozow, aug(18, 23, 24)), // brozow is the supervisor and this period is unscheduled
        };
        
        assertTimeIntervalSequence(expected, intervals);

        
    }
    
    private void assertUser(User user, WebUser webUser) {
        assertEquals(user.getUserId(), webUser.getName());
    }

    private void assertGroup(Group group, WebGroup webGroup) throws Exception {
        assertEquals(group.getName(), webGroup.getName());
        Collection<String> userNames = group.getUsers();
        assertEquals(userNames.size(), webGroup.getUsers().size());
        for (Iterator<WebUser> it = webGroup.getUsers().iterator(); it.hasNext();) {
            WebUser user = it.next();
            assertTrue(userNames.contains(user.getName()));
            assertUser(m_userManager.getUser(user.getName()), user);
            
        }
    }

    private void assertRole(Role role, WebRole webRole) throws Exception {
        assertEquals(role.getName(), webRole.getName());
        assertEquals(role.getDescription().orElse(null), webRole.getDescription());
        assertNotNull(webRole.getMembershipGroup());
        assertEquals(role.getMembershipGroup(), webRole.getMembershipGroup().getName());
        assertNotNull(webRole.getDefaultUser());
        assertEquals(role.getSupervisor(), webRole.getDefaultUser().getName());
        Collection<WebUser> scheduledUsers = webRole.getCurrentUsers();
        for (Iterator<WebUser> it = scheduledUsers.iterator(); it.hasNext();) {
            WebUser currentUser = it.next();
            assertTrue(m_groupManager.isUserScheduledForRole(currentUser.getName(), webRole.getName(), new Date()));
        }
    }

    private Date getDate(String date) throws ParseException {
        return new SimpleDateFormat("yyyy-MM-dd").parse(date);
    }
    
    

}
