/*
 * Copyright (C) 2005 - 2011 Jaspersoft Corporation. All rights reserved.
 * http://www.jaspersoft.com.
 *
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License  as
 * published by the Free Software Foundation, either version 3 of  the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero  General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public  License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.jaspersoft.jasperserver.api.metadata.view.service.impl;

import java.util.Date;
import java.util.List;

import junit.textui.TestRunner;

import org.springframework.security.GrantedAuthority;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;

import com.jaspersoft.jasperserver.api.metadata.user.domain.Role;
import com.jaspersoft.jasperserver.api.metadata.user.domain.User;
import com.jaspersoft.jasperserver.util.test.BaseJasperServerTest;

/**
 * @author swood
 * @version $Id: UserAuthorityServiceTest.java 19930 2010-12-11 15:17:19Z tmatyashovsky $
 */
public class UserAuthorityServiceTest extends BaseJasperServerTest {

    protected void onSetUp() throws Exception {
        super.onSetUp();
    }

	public UserAuthorityServiceTest(String name) {
		super(name);
		setAutowireMode(AUTOWIRE_BY_NAME);
	}

	public static void main(String[] args) {
		TestRunner.run(UserAuthorityServiceTest.class);
	}


	public void onTearDown() {
		/*
		 *  Leave entries in the database
		 *
		 */

		// get rid of objects we don't want in samples

		getUserAuthorityService().deleteUser(null, "newUser");

		getUserAuthorityService().deleteRole(null, "newRole");
		getUserAuthorityService().deleteRole(null, "anotherRole");

		// temp
		getUserAuthorityService().deleteUser(null, "TestUser");
		getUserAuthorityService().deleteRole(null, "TestRole0");
		getUserAuthorityService().deleteRole(null, "TestRole1");
		getUserAuthorityService().deleteRole(null, "TestRole2");
		getUserAuthorityService().deleteRole(null, "TestRole3");
		getUserAuthorityService().deleteRole(null, "TestRole4");
	}

	public Role addRole(User user, String roleName) {
		Role role = getUserAuthorityService().getRole(null, roleName);

		if (role == null) {
			role = getUserAuthorityService().newRole(null);
			role.setRoleName(roleName);
			role.setExternallyDefined(false);

			getUserAuthorityService().putRole(null, role);
		}

		getUserAuthorityService().addRole(null, user, role);
		return role;
	}

	private User findOrCreateUser(String username, String password, String fullName) {
		User workingUser = getUserAuthorityService().getUser(null, username);
		if (workingUser == null) {
			workingUser = getUserAuthorityService().newUser(null);
			workingUser.setUsername(username);
			workingUser.setPassword((password == null ? username : password));
			workingUser.setFullName(fullName);
			workingUser.setEnabled(true);
			workingUser.setExternallyDefined(false);
            workingUser.setPreviousPasswordChangeTime(new Date());

			getUserAuthorityService().putUser(null, workingUser);
		}

		return workingUser;
	}

	public void testNewUser() {
		User newUser = findOrCreateUser("newUser", "newPassword", "newUser");
		// No roles added yet
		assertTrue(newUser.getRoles() == null || newUser.getRoles().isEmpty());

		addRole(newUser, "newRole");
		assertTrue(newUser.getRoles() != null || newUser.getRoles().size() == 1);

	}

	public void testOrdinaryUser() {
		User newUser = findOrCreateUser("joeuser", "joeuser", "Joe User");
		// No roles added yet
		assertTrue(newUser.getRoles() == null || newUser.getRoles().isEmpty());

		addRole(newUser, "ROLE_USER");
		assertTrue(newUser.getRoles() != null || newUser.getRoles().size() == 1);
	}

	public void testOrdinaryETLUser() {
		User newUser = findOrCreateUser("etluser", "etluser", "etluser");
		// No roles added yet
		assertTrue(newUser.getRoles() == null || newUser.getRoles().isEmpty());

		addRole(newUser, "ROLE_USER");
		assertTrue(newUser.getRoles() != null || newUser.getRoles().size() == 1);

		addRole(newUser, "ROLE_ETL_ADMIN");
		assertTrue(newUser.getRoles() != null || newUser.getRoles().size() == 2);
	}

	public void testAdminETLUser() {
		User newUser = findOrCreateUser("etladmin", "etladmin", "etladmin");
		// No roles added yet
		assertTrue(newUser.getRoles() == null || newUser.getRoles().isEmpty());

		addRole(newUser, "ROLE_USER");
		assertTrue(newUser.getRoles() != null || newUser.getRoles().size() == 1);

		addRole(newUser, "ROLE_ADMINISTRATOR");
		assertTrue(newUser.getRoles() != null || newUser.getRoles().size() == 2);

		addRole(newUser, "ROLE_ETL_ADMIN");
		assertTrue(newUser.getRoles() != null || newUser.getRoles().size() == 3);

	}

	public void testAdminUser() {
		User newUser = findOrCreateUser("admin", null, "admin");
		// No roles added yet
		assertTrue(newUser.getRoles() == null || newUser.getRoles().isEmpty());

		addRole(newUser, "ROLE_USER");
		assertTrue(newUser.getRoles() != null || newUser.getRoles().size() == 1);

		addRole(newUser, "ROLE_ADMINISTRATOR");
		assertTrue(newUser.getRoles() != null || newUser.getRoles().size() == 2);

	}

	public void testJasperadminUser() {
		User newUser = findOrCreateUser("jasperadmin", "jasperadmin", "jasperadmin");
		// No roles added yet
		assertTrue(newUser.getRoles() == null || newUser.getRoles().isEmpty());

		addRole(newUser, "ROLE_USER");
		assertTrue(newUser.getRoles() != null || newUser.getRoles().size() == 1);

		addRole(newUser, "ROLE_ADMINISTRATOR");
		assertTrue(newUser.getRoles() != null || newUser.getRoles().size() == 2);
	}

	public void testAnonymousUser() {
		User newUser = findOrCreateUser("anonymousUser", "", "anonymousUser");
		// No roles added yet
		assertTrue(newUser.getRoles() == null || newUser.getRoles().isEmpty());

		addRole(newUser, "ROLE_ANONYMOUS");
		assertTrue("newUser.getRoles() wrong size", newUser.getRoles() != null || newUser.getRoles().size() == 1);
		//assertTrue("newRole.getUsers() wrong size", newRole.getUsers() != null || newRole.getUsers().size() == 1);

		UserDetailsService userDetailsService = (UserDetailsService) getUserAuthorityService();

		UserDetails details = userDetailsService.loadUserByUsername(newUser.getUsername());

		assertTrue("load by Acegi interface", details != null);

		GrantedAuthority[] authorities = details.getAuthorities();
		assertTrue("authorities wrong size", authorities != null || authorities.length == 1);
		assertTrue("right authority", authorities[0].getAuthority().equalsIgnoreCase("ROLE_ANONYMOUS"));

	}

	public void testUpdateUser() {
		User newUser = findOrCreateUser("newUser", "", "newUser");
		assertNotNull(newUser);
		assertTrue(newUser.isEnabled());
		getUserAuthorityService().disableUser(null, newUser.getUsername());
		newUser = findOrCreateUser("newUser", "", "newUser");
		assertTrue("error: user still disabled", !newUser.isEnabled());

		addRole(newUser, "anotherRole");

		Role r = getUserAuthorityService().getRole(null, "anotherRole");

		assertTrue("error: 'anotherRole' does not exist", r != null);
		assertTrue("error: newUser does not have anotherRole", newUser.getRoles().contains(r));

		getUserAuthorityService().putUser(null, newUser);

		newUser.removeRole(r);
		assertTrue("error: newUser still contains anotherRole", !newUser.getRoles().contains(r));

		getUserAuthorityService().putUser(null, newUser);

		newUser = getUserAuthorityService().getUser(null, "newUser");
		assertTrue("error: after retrieval - newUser REALLY still contains anotherRole", !newUser.getRoles().contains(r));

	}

	public void testGetUsersAndRoles() {
		// Depending on the order of test classes that are run, we could have more users and roles
		// than we created here.

		List results = getUserAuthorityService().getUsers(null, null);
		assertTrue("getUsers right size: expected at least 3, got " + results.size(), results.size() >= 3);
		results = getUserAuthorityService().getRoles(null, null);
		assertTrue("getRoles right size: expected at least 4, got " + results.size(), results.size() >= 4);
	}

/*	public void testObjectPermissionMaintenance() {

	}
*/
}
