package eu.dnetlib.enabling.resultset;

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnit44Runner;
import org.mockito.stubbing.Answer;

import com.google.common.collect.Lists;

import eu.dnetlib.enabling.resultset.client.ResultSetPageProvider;
import eu.dnetlib.enabling.resultset.rmi.ResultSetService;

@RunWith(MockitoJUnit44Runner.class)
public class ResultSetPageProviderTest {

	private static final String RSID = "RS_123";
	private static final int PAGE_SIZE = 10;
	private static final String RSSTATUS = "closed";
	
	// Class Under test
	private ResultSetPageProvider pageProvider;

	@Mock
	private ResultSetService mockResultSet;
	
	private class ResultAnswer implements Answer<List<String>> {
		private int size;
		
		public ResultAnswer(int size) {
			this.size = size;
		}

		@Override
		public List<String> answer(InvocationOnMock invocation) throws Throwable {
			Object[] args = invocation.getArguments();
			int from = Integer.parseInt(args[1].toString());
			int to = Integer.parseInt(args[2].toString());

			
			if (to > size) to = size;
			if (from > to) throw new Exception("FROM IS GREATER THAN TO");
			
			List<String> list = Lists.newArrayList();
			for (int i = from; i<=to; i++) {
				list.add("RECORD " + i);
			}
			return list;
		}
	}
	
	@Before
	public void setUp() throws Exception {
		pageProvider = new ResultSetPageProvider(mockResultSet, RSID);
		pageProvider.setMaxWaitTime(60000);
		pageProvider.setPageSize(PAGE_SIZE);
	}

	@Test
	public void testNextPage5() throws Exception {
		performTest(5);
	}

	@Test
	public void testNextPage10() throws Exception {
		performTest(10);
	}

	@Test
	public void testNextPage15() throws Exception {
		performTest(15);
	}

	@Test
	public void testNextPage20() throws Exception {
		performTest(20);
	}

	@Test
	public void testNextPage250() throws Exception {
		performTest(250);
	}

	@Test
	public void testNextPage254() throws Exception {
		performTest(254);
	}

	public void performTest(int size) throws Exception {
		when(mockResultSet.getRSStatus(RSID)).thenReturn(RSSTATUS);
		when(mockResultSet.getNumberOfElements(RSID)).thenReturn(size);
		when(mockResultSet.getResult(anyString(), anyInt(), anyInt(), anyString())).thenAnswer(new ResultAnswer(size));
		
		List<String> list = Lists.newArrayList();
		
		while (true) {
			List<String> res = pageProvider.nextPage();
			if (res == null || res.isEmpty()) break;
			list.addAll(res);
		}
		
		assertEquals(list.size(), size);
		verify(mockResultSet, times(((size - 1) / PAGE_SIZE) + 1)).getResult(anyString(), anyInt(), anyInt(), anyString());
	}

}
