package eu.dnetlib.enabling.aas.utils;

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

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;


import com.sun.xacml.ctx.RequestCtx;
import com.sun.xacml.ctx.ResponseCtx;
import com.sun.xacml.ctx.Result;
import com.sun.xacml.ctx.Status;
import com.sun.xacml.ctx.Subject;

import eu.dnetlib.enabling.aas.rmi.Attribute;
import eu.dnetlib.enabling.aas.rmi.AuthenticateRequest;
import eu.dnetlib.enabling.aas.rmi.AuthorizeRequest;
import eu.dnetlib.enabling.aas.rmi.AuthorizeResp;
import eu.dnetlib.enabling.aas.rmi.Obligation;
import eu.dnetlib.enabling.aas.rmi.TypedString;
import eu.dnetlib.enabling.aas.utils.DriverConverter;

/**
 * @author mhorst
 *
 */
public class DriverConverterTest {

	AuthorizeRequest authorizeRequest;
	ResponseCtx responseCtx;
	
	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
		authorizeRequest=null;
		responseCtx=null;
		
	}
	
	private static AuthorizeRequest prepareAuthorizeRequest() {
		Attribute[] attrs = new Attribute[3];
		String ATTRIBUTE_STRING_TYPE = "http://www.w3.org/2001/XMLSchema#string";
		
		Attribute attr0 = new Attribute();
		attr0.setKey("request:ip_addr");
		attr0.setType(ATTRIBUTE_STRING_TYPE);
		attr0.setValue("192.168.0.1");
		
		Attribute attr1 = new Attribute();
		attr1.setKey("request:defined-time");
		attr1.setType("http://www.w3.org/2001/XMLSchema#time");
		attr1.setValue("18:00:00");
		
		Attribute attr2 = new Attribute();
		attr2.setKey("urn:oasis:names:tc:xacml:1.0:subject:subject-id");
		attr2.setType("urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name");
		attr2.setValue("az@gmail.com");
		
		attrs[0] = attr0;
		attrs[1] = attr1;
		attrs[2] = attr2;
		
		AuthorizeRequest request = new AuthorizeRequest("main-door", "open", attrs);
		return request;
	}
	
	private static ResponseCtx prepareAuthorizeResponse(int decision) {
		Status status = Status.getOkInstance();
		String resource = "main-door";
		Set<com.sun.xacml.Obligation> obligations = prepareObligations();
		Result result = new Result(decision, status, resource, obligations);
		ResponseCtx resp = new ResponseCtx(result);
		return resp;
	}
	
	private static AuthenticateRequest prepareAuthenticateRequest() {
		TypedString[] principals = new TypedString[1];
		TypedString[] credentials = new TypedString[1];
		
		TypedString login = new TypedString("somebody","login");
		principals[0] = login;
		TypedString password = new TypedString("pass", "password");
		credentials[0] = password;
		
		Attribute[] attrs = new Attribute[3];
		String ATTRIBUTE_STRING_TYPE = "http://www.w3.org/2001/XMLSchema#string";
		
		Attribute attr0 = new Attribute();
		attr0.setKey("authenticate_request:ip_addr");
		attr0.setType(ATTRIBUTE_STRING_TYPE);
		attr0.setValue("192.168.0.1");
		
		Attribute attr1 = new Attribute();
		attr1.setKey("authenticate_request:defined-time");
		attr1.setType("http://www.w3.org/2001/XMLSchema#time");
		attr1.setValue("18:00:00");
		
		Attribute attr2 = new Attribute();
		attr2.setKey("urn:oasis:names:tc:xacml:1.0:subject:subject-id");
		attr2.setType("urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name");
		attr2.setValue("az@gmail.com");
		
		attrs[0] = attr0;
		attrs[1] = attr1;
		attrs[2] = attr2;
		
		AuthenticateRequest request = new AuthenticateRequest(principals, credentials, attrs);
		return request;
	}
	
	private static Set<com.sun.xacml.Obligation> prepareObligations() {
		Set<com.sun.xacml.Obligation> obligations = new HashSet<com.sun.xacml.Obligation>();
		URI obligation1 = null;
		try {
			obligation1 = new URI("LogAccess");
			
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
		List emptyAssignments = new ArrayList();
		obligations.add(new com.sun.xacml.Obligation(obligation1, 0, emptyAssignments));
		return obligations;
	}

	@Test
	public void testConvertRequest() {
		authorizeRequest=prepareAuthorizeRequest();
		RequestCtx requestCtx = DriverConverter.convertRequest(authorizeRequest);
		assertNotNull(requestCtx);
		Iterator itSub = requestCtx.getSubjects().iterator();
		assertTrue(itSub.hasNext());
		if (itSub.hasNext()) {
			Subject sub = (Subject) itSub.next();
			assertNotNull(sub);
			assertTrue(sub.getAttributes().isEmpty());
		}
		Iterator itRes = requestCtx.getResource().iterator();
		assertTrue(itRes.hasNext());
		if (itRes.hasNext()) {
			com.sun.xacml.ctx.Attribute res = (com.sun.xacml.ctx.Attribute) itRes.next();
			assertNotNull(res);
			assertEquals("main-door",res.getValue().encode());
		}
		Iterator itAct = requestCtx.getAction().iterator();
		assertTrue(itAct.hasNext());
		if (itAct.hasNext()) {
			com.sun.xacml.ctx.Attribute act = (com.sun.xacml.ctx.Attribute) itAct.next();
			assertNotNull(act);
			assertEquals("open",act.getValue().encode());
		}

	}

	@Test
	public void testConvertResponse() {
		responseCtx = prepareAuthorizeResponse(Result.DECISION_PERMIT);
		AuthorizeResp authResponse = DriverConverter.convertAuthorizeResponse(responseCtx);
		assertNotNull(authResponse);
		assertTrue(authResponse.isAuthorized());
		assertFalse(authResponse.hasErrors());
		assertTrue(authResponse.hasObligations());
		
		responseCtx = prepareAuthorizeResponse(Result.DECISION_DENY);
		authResponse = DriverConverter.convertAuthorizeResponse(responseCtx);
		assertNotNull(authResponse);
		assertFalse(authResponse.isAuthorized());
		assertFalse(authResponse.hasErrors());
		assertTrue(authResponse.hasObligations());
		
		responseCtx = prepareAuthorizeResponse(Result.DECISION_INDETERMINATE);
		authResponse = DriverConverter.convertAuthorizeResponse(responseCtx);
		assertNotNull(authResponse);
		assertFalse(authResponse.isAuthorized());
		assertTrue(authResponse.hasErrors());
		assertTrue(authResponse.hasObligations());
	}

	@Test
	public void testConvertObligations() {
		String resource = "main-door";
		Set<com.sun.xacml.Obligation> sourceObligations = prepareObligations();
		Obligation[] obligations = DriverConverter.convertObligations(sourceObligations, resource);
		assertNotNull(obligations);
		assertEquals(1, obligations.length);
		Obligation obl = obligations[0];
		assertEquals("LogAccess", obl.getObligation());
		assertEquals(resource, obl.getResource());
		assertEquals(0, obl.getAttributes().length);
	}

	@Test
	public void testConvertAuthenticationRequest() {
		AuthenticateRequest authReq = prepareAuthenticateRequest();
		RequestCtx reqCtx = DriverConverter.convertRequest(authReq);
		assertNotNull(reqCtx);
		Iterator itRes = reqCtx.getResource().iterator();
		assertTrue(itRes.hasNext());
		if (itRes.hasNext()) {
			com.sun.xacml.ctx.Attribute res = (com.sun.xacml.ctx.Attribute) itRes.next();
			assertNotNull(res);
			assertEquals("authentication",res.getValue().encode());
		}
		Iterator itSubj = reqCtx.getSubjects().iterator();
		assertTrue(itSubj.hasNext());
		if (itSubj.hasNext()) {
			Subject subject = (Subject) itSubj.next();
			Set attributes = subject.getAttributes();
			Iterator itAttr = attributes.iterator();
			assertNotNull(itAttr.hasNext());
			if (itAttr.hasNext()) {
				com.sun.xacml.ctx.Attribute attr = (com.sun.xacml.ctx.Attribute) itAttr.next();
				assertEquals("login", attr.getValue().encode());
			}
		}
		
	}

	
//	@Test
	public void testConvertAuthenticationResponse() {
//		tested in A2ServiceImplTest		
	}
}
