package com.nitorcreations.willow.servers;

import java.util.List;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;

import javax.inject.Inject;
import javax.inject.Named;

import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.elasticsearch.client.Client;
import org.elasticsearch.node.Node;

import com.google.gson.Gson;
import com.nitorcreations.willow.metrics.Metric;
import com.nitorcreations.willow.metrics.MetricConfig;

@WebSocket
@Named
public class ServerSidePollingSocket extends BasicWillowSocket {
  @Inject
  private Node node;
  @Inject
  ScheduledExecutorService scheduler;
  private final Map<String, Metric> metrics;
  private List<ScheduledFuture<?>> pollers = new ArrayList<>();
  public final int minStep = 1000;
  private final Gson gson = new Gson();
  private class PollTask implements Runnable {
	  private final Metric metric;
	  private final MetricConfig conf;
	  private final long currTimeDelay;
	  private final Session session;
	  private final Gson gson = new Gson();
	  public PollTask(Session session, MetricConfig conf) {
		  this.conf = conf;
		  this.metric = metrics.get(conf.metricKey);
		  if (metric == null) throw new IllegalArgumentException("No metric found for " + conf.metricKey);
	      long now = System.currentTimeMillis();
	      this.currTimeDelay = now - conf.getStop();
	      this.session = session;
	  }

	@Override
	public void run() {
		try (Client client = node.client()){
			long stop = System.currentTimeMillis() - currTimeDelay;
			long start = stop - conf.getStep();
			Metric nextMetric = metric.getClass().newInstance();
			Object ret = nextMetric.calculateMetric(client, conf);
			conf.setStop(stop);
			conf.setStart(start);
			session.getRemote().sendString(gson.toJson(ret));
		} catch (InstantiationException | IllegalAccessException | IOException e) {
			log.log(Level.INFO, "Failed to send polled statistics", e);
		}
	}
  }
  @Inject
  public ServerSidePollingSocket(Map<String, Metric> metrics) {
    this.metrics = new HashMap<>(metrics);
  }

  @OnWebSocketMessage
  public void messageReceived(Session session, String message) {
    try {
      MetricConfig conf = gson.fromJson(message, MetricConfig.class);
      PollTask task = new PollTask(session, conf);
      ScheduledFuture<?> handle = scheduler.scheduleAtFixedRate(task, 0, conf.getStep(), TimeUnit.MILLISECONDS);
      pollers.add(handle);
    } catch (Throwable e) {
		log.log(Level.INFO, "Failed to schedule task", e);
    }
  }
  @OnWebSocketConnect
  public void onConnect(Session session) {
    super.onConnect(session);
  }
  @OnWebSocketClose
  public void onClose(int statusCode, String reason) {
	for (ScheduledFuture<?> next : pollers) {
		next.cancel(true);
	}
    super.onClose(statusCode, reason);
  }

}

@@ -1315,17 +1315,18 @@
 nable %7B%0A
-%09
+  
   privat
@@ -1348,17 +1348,18 @@
 metric;%0A
-%09
+  
   privat
@@ -1385,17 +1385,18 @@
 g conf;%0A
-%09
+  
   privat
@@ -1423,19 +1423,20 @@
 eDelay;%0A
-%09
+ 
   
+ 
 private 
@@ -1458,17 +1458,18 @@
 ession;%0A
-%09
+  
   privat
@@ -1500,17 +1500,18 @@
 Gson();%0A
-%09
+  
   public
@@ -1558,18 +1558,20 @@
 conf) %7B%0A
-%09%09
+    
   this.c
@@ -1582,18 +1582,20 @@
 = conf;%0A
-%09%09
+    
   this.m
@@ -1631,18 +1631,20 @@
 icKey);%0A
-%09%09
+    
   if (me
@@ -1734,17 +1734,16 @@
 icKey);%0A
-%09
       lo
@@ -1775,25 +1775,24 @@
 meMillis();%0A
-%09
       this.c
@@ -1828,17 +1828,16 @@
 Stop();%0A
-%09
       th
@@ -1862,15 +1862,19 @@
 on;%0A
-%09
+  
   %7D%0A%0A
-%09
+    
 @Ove
@@ -1879,17 +1879,20 @@
 verride%0A
-%09
+    
 public v
@@ -1903,18 +1903,22 @@
 run() %7B%0A
-%09%09
+      
 try (Cli
@@ -1946,19 +1946,24 @@
 ent())%7B%0A
-%09%09%09
+        
 long sto
@@ -2010,19 +2010,24 @@
 eDelay;%0A
-%09%09%09
+        
 long sta
@@ -2054,19 +2054,24 @@
 Step();%0A
-%09%09%09
+        
 Metric n
@@ -2115,19 +2115,24 @@
 ance();%0A
-%09%09%09
+        
 Object r
@@ -2178,19 +2178,24 @@
  conf);%0A
-%09%09%09
+        
 conf.set
@@ -2206,19 +2206,24 @@
 (stop);%0A
-%09%09%09
+        
 conf.set
@@ -2236,19 +2236,24 @@
 start);%0A
-%09%09%09
+        
 session.
@@ -2294,18 +2294,22 @@
 (ret));%0A
-%09%09
+      
 %7D catch 
@@ -2380,11 +2380,16 @@
 ) %7B%0A
-%09%09%09
+        
 log.
@@ -2448,13 +2448,20 @@
 e);%0A
-%09%09%7D%0A%09
+      %7D%0A    
 %7D%0A  
@@ -2970,18 +2970,22 @@
 le e) %7B%0A
-%09%09
+      
 log.log(
@@ -3211,17 +3211,20 @@
 ason) %7B%0A
-%09
+    
 for (Sch
@@ -3261,10 +3261,14 @@
 ) %7B%0A
-%09%09
+      
 next
@@ -3286,9 +3286,12 @@
 e);%0A
-%09
+    
 %7D%0A  

Fix whitespace