/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.springframework.integration.http.outbound;

import static org.assertj.core.api.Assertions.assertThat;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * @author Gary Russell
 * @author Gunnar Hillert
 * @author Artem Bilan
 *
 * @since 2.1
 *
 */
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class CookieTests {

	@Autowired
	private MessageChannel ch1;

	@Autowired
	private QueueChannel ch6;

	private static ByteArrayOutputStream bos = new ByteArrayOutputStream();

	private static List<HttpHeaders> allHeaders = new ArrayList<>();

	@Test
	public void testCookie() throws Exception {
		ch1.send(new GenericMessage<>("Hello, world!"));
		assertThat(ch6.receive()).isNotNull();


		bos.close();
		BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bos.toByteArray())));
		String line = br.readLine();
		assertThat(line).isEqualTo("Hello, world!Hello, again!Hello, once more!");
		assertThat(br.readLine()).isNull();
		br.close();
		assertThat(allHeaders.size()).isEqualTo(3);
		assertThat(allHeaders.get(0).containsKey("Cookie")).isFalse();
		assertThat(allHeaders.get(1).containsKey("Cookie")).isTrue();
		assertThat(allHeaders.get(1).get("Cookie").get(0)).isEqualTo("JSESSIONID=X123");
		assertThat(allHeaders.get(2).containsKey("Cookie")).isTrue();
		assertThat(allHeaders.get(2).get("Cookie").get(0)).isEqualTo("JSESSIONID=X124");
	}

	public static class RequestFactory implements ClientHttpRequestFactory {

		private int count = 123;

		public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod)
				throws IOException {

			return new ClientHttpRequest() {

				private HttpHeaders headers = new HttpHeaders();

				public HttpHeaders getHeaders() {
					return headers;
				}

				public OutputStream getBody() throws IOException {
					return bos;
				}

				public URI getURI() {
					return null;
				}

				public HttpMethod getMethod() {
					return null;
				}

				@Override
				public String getMethodValue() {
					return null;
				}

				public ClientHttpResponse execute() throws IOException {
					allHeaders.add(headers);
					return new ClientHttpResponse() {

						public HttpHeaders getHeaders() {
							HttpHeaders headers = new HttpHeaders();
							headers.set("Set-cookie", "JSESSIONID=X" + count++); // test case insensitivity
							headers.set("Content-Length", "2");
							headers.set("Content-Type", "text/plain");
							return headers;
						}

						public InputStream getBody() throws IOException {
							return new ByteArrayInputStream("OK".getBytes());
						}

						public String getStatusText() throws IOException {
							return "OK";
						}

						public HttpStatus getStatusCode() throws IOException {
							return HttpStatus.OK;
						}

						public void close() {
						}

						public int getRawStatusCode() throws IOException {
							return 200;
						}

					};
				}

			};

		}

	}

}
