package com.gomoku.service;

import static com.gomoku.domain.player.PlayerUriBuilder.buildUri;
import static java.util.Arrays.asList;
import static java.util.Optional.empty;
import static java.util.Optional.of;
import static org.slf4j.LoggerFactory.getLogger;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.MediaType.APPLICATION_JSON;

import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gomoku.domain.board.Board;
import com.gomoku.domain.board.BoardFieldType;
import com.gomoku.domain.game.task.GameState;
import com.gomoku.repository.entity.Player;

/**
 * Gomoku game service, it is responsible for execute one match on the board by the actual state of the game and actual player.
 *
 * @author zeldan
 *
 */
@Service
public class GameExecutorService {

    private static final Logger LOG = getLogger(GameExecutorService.class);

    private final ObjectMapper objectMapper;

    private final RestTemplate restTemplate;

    @Autowired
    public GameExecutorService(final ObjectMapper objectMapper, final RestTemplate restTemplate) {
        this.objectMapper = objectMapper;
        this.restTemplate = restTemplate;
    }

    public Optional<GameState> playOneRound(final GameState gameState, final BoardFieldType actualPlayer) {
        final Player player = gameState.getPlayers().get(actualPlayer);
        final Board board = gameState.getBoard();
        final URI playerURI = buildUri(player.getNetworkAddress(), board, actualPlayer);
        final HttpEntity<String> userResponse = executeURI(playerURI);
        final Map<String, Integer> readValue = getValueFromUserResponse(userResponse.getBody());
        if (!readValue.isEmpty()) {
            final Board changedBoard = board.mark(readValue.get("x"), readValue.get("y"), actualPlayer);
            return of(new GameState(gameState.getPlayers(), changedBoard));
        }
        return empty();
    }

    private ResponseEntity<String> executeURI(final URI playerURI) {
        return restTemplate.exchange(
                playerURI,
                GET,
                getHttpEntity(),
                String.class);
    }

    private Map<String, Integer> getValueFromUserResponse(final String response) {
        try {
            return objectMapper.readValue(response, new TypeReference<HashMap<String, Integer>>() {
            });
        } catch (final IOException e) {
            LOG.error("An error occured while try to parse user response.", e);
        }
        return Collections.<String, Integer> emptyMap();
    }

    private HttpEntity<Object> getHttpEntity() {
        final HttpHeaders headers = new HttpHeaders();
        headers.setAccept(asList(APPLICATION_JSON));
        return new HttpEntity<>(headers);
    }

}

@@ -92,47 +92,8 @@
 ri;%0A
-import static java.util.Arrays.asList;%0A
 impo
@@ -261,17 +261,21 @@
 Http
-Method.GE
+Headers.ACCEP
 T;%0Ai
@@ -338,16 +338,22 @@
 ION_JSON
+_VALUE
 ;%0A%0Aimpor
@@ -666,27 +666,29 @@
 rk.http.
-HttpHeaders
+RequestEntity
 ;%0Aimport
@@ -2516,37 +2516,63 @@
     
-return restTemplate.exchange(
+final RequestEntity%3CVoid%3E requestEntity = RequestEntity
 %0A   
@@ -2584,16 +2584,21 @@
         
+.get(
 playerUR
@@ -2598,17 +2598,17 @@
 layerURI
-,
+)
 %0A       
@@ -2620,12 +2620,47 @@
     
-GET,
+.header(ACCEPT, APPLICATION_JSON_VALUE)
 %0A   
@@ -2676,24 +2676,17 @@
     
-getHttpEntity(),
+.build();
 %0A   
@@ -2690,23 +2690,59 @@
         
-       
+return restTemplate.exchange(requestEntity,
  String.
@@ -3167,212 +3167,6 @@
  %7D%0A%0A
-    private HttpEntity%3CObject%3E getHttpEntity() %7B%0A        final HttpHeaders headers = new HttpHeaders();%0A        headers.setAccept(asList(APPLICATION_JSON));%0A        return new HttpEntity%3C%3E(headers);%0A    %7D%0A%0A
 %7D%0A

use requestentity to exchange URI