package es.predictia.smartmap.ws;

import java.util.Map;
import java.util.Optional;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.fasterxml.jackson.databind.ObjectMapper;

import es.predictia.smartmap.model.DataType;
import es.predictia.smartmap.service.DataService;

import lombok.extern.slf4j.Slf4j;

/**
 * Echo messages by implementing a Spring {@link WebSocketHandler} abstraction.
 */
@Slf4j
public class DataWsHandler extends TextWebSocketHandler {

	private final DataService dataService;
	private final ObjectMapper converter = new ObjectMapper();
	private final Map<String, Timer> timers = new ConcurrentHashMap<>();

	@Autowired
	public DataWsHandler(DataService dataService) {
		this.dataService = dataService;
	}

	@Override
	public void afterConnectionEstablished(WebSocketSession session) {
		log.debug("Opened new session {}", session.getId());
	}

	@Override
	public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		Optional.ofNullable(timers.get(session.getId()))
			.ifPresent(Timer::cancel);
		var type = DataType.valueOf(message.getPayload());
		var iTimer = new Timer(); 
		iTimer.scheduleAtFixedRate(task(() -> {
			var data = dataService.getLastData(type);
			if(session.isOpen()){
				try {
					session.sendMessage(new TextMessage(converter.writeValueAsString(data)));
				} catch (Throwable e) {
					log.debug("problem sending data", e);
				}
			}else{
				log.debug("session {} is closed", session.getId());
				Optional.ofNullable(timers.remove(session.getId()))
					.ifPresent(Timer::cancel);
			}
		}), 0, 1000);
		timers.put(session.getId(), iTimer);
	}

	private static TimerTask task(Runnable r) {
		return new TimerTask() {
			@Override 
			public void run() {
				r.run();
			}
		};
	}
	
	@Override
	public void handleTransportError(WebSocketSession session, Throwable e) throws Exception {
		log.debug("session {} had transport error: {}", session.getId(), e.getMessage());
		Optional.ofNullable(timers.remove(session.getId()))
			.ifPresent(Timer::cancel);
		session.close(CloseStatus.SERVER_ERROR);
	}

}

@@ -1517,14 +1517,168 @@
 ;%0A%09%09
-var iT
+timers.put(session.getId(), createSendMessageTimer(session, type));%0A%09%7D%0A%0A%09private Timer createSendMessageTimer(WebSocketSession session, DataType type) %7B%0A%09%09var t
 imer
@@ -1696,18 +1696,17 @@
 r(); %0A%09%09
-iT
+t
 imer.sch
@@ -1726,21 +1726,64 @@
 ate(
-t
+new TimerT
 ask(
-(
 ) 
--%3E
+%7B%0A%09%09%09@Override %0A%09%09%09public void run()
  %7B%0A
+%09
 %09%09%09v
@@ -1823,16 +1823,17 @@
 (type);%0A
+%09
 %09%09%09if(se
@@ -1857,14 +1857,16 @@
 %09%09%09%09
+%09
 try %7B%0A
+%09
 %09%09%09%09
@@ -1936,24 +1936,25 @@
 ng(data)));%0A
+%09
 %09%09%09%09%7D catch 
@@ -1970,24 +1970,25 @@
 e e) %7B%0A%09%09%09%09%09
+%09
 log.debug(%22p
@@ -2017,18 +2017,20 @@
 e);%0A%09%09%09%09
+%09
 %7D%0A
+%09
 %09%09%09%7Delse
@@ -2031,24 +2031,25 @@
 %09%7Delse%7B%0A%09%09%09%09
+%09
 log.debug(%22s
@@ -2084,24 +2084,25 @@
 n.getId());%0A
+%09
 %09%09%09%09Optional
@@ -2145,16 +2145,17 @@
 tId()))%0A
+%09
 %09%09%09%09%09.if
@@ -2185,14 +2185,19 @@
 %0A%09%09%09
+%09
 %7D%0A
+%09
 %09%09%7D
-)
+%0A%09%09%7D
 , 0,
@@ -2210,179 +2210,20 @@
 ;%0A%09%09
-timers.put(session.getId(), iTimer);%0A%09%7D%0A%0A%09private static TimerTask task(Runnable r) %7B%0A%09%09return new TimerTask() %7B%0A%09%09%09@Override %0A%09%09%09public void run() %7B%0A%09%09%09%09r.run();%0A%09%09%09%7D%0A%09%09%7D
+return timer
 ;%0A%09%7D

refactor timer creation