package com.s24.redjob.worker;

import java.time.Instant;

import org.springframework.util.Assert;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;

/**
 * Job execution. Stored as JSON in Redis.
 */
public class Execution {
   /**
    * Id of job.
    */
   @JsonProperty(value = "id", required = true)
   private final long id;

   /**
    * Job.
    */
   @JsonProperty(value = "job", required = true)
   @JsonTypeInfo(use = Id.NAME, include = As.EXTERNAL_PROPERTY, property = "jobType")
   private final Object job;

   /**
    * Job result.
    */
   @JsonProperty(value = "result", required = true)
   @JsonTypeInfo(use = Id.NAME, include = As.EXTERNAL_PROPERTY, property = "resultType")
   private Object result;

   /**
    * Creation of execution.
    */
   @JsonProperty(value = "creation", required = true)
   private Instant creation;

   /**
    * Start of execution.
    */
   @JsonInclude(value = Include.NON_NULL)
   @JsonProperty(value = "start", required = false)
   private Instant start;

   /**
    * Stop of execution.
    */
   @JsonInclude(value = Include.NON_NULL)
   @JsonProperty(value = "stop", required = false)
   private Instant stop;

   /**
    * Constructor.
    *
    * @param id
    *           Id of job.
    * @param job
    *           Job.
    */
   public Execution(long id, Object job) {
      this(id, job, new NoResult());
   }

   /**
    * Constructor.
    *
    * @param id
    *           Id of job.
    * @param job
    *           Job.
    * @param result
    *           Job result.
    */
   public Execution(long id, Object job, Object result) {
      this(id, job, result, Instant.now(), null, null);
   }

   /**
    * Jackson constructor.
    */
   Execution(
         @JsonProperty(value = "id", required = true) long id,
         @JsonProperty(value = "job", required = true) Object job,
         @JsonProperty(value = "result", required = true) Object result,
         @JsonProperty(value = "creation", required = true) Instant creation,
         @JsonProperty(value = "start", required = false) Instant start,
         @JsonProperty(value = "stop", required = false) Instant stop) {
      Assert.notNull(job, "Precondition violated: job != null.");
      Assert.notNull(result, "Precondition violated: result != null.");
      // Assert.notNull(creation, "Precondition violated: creation != null.");

      this.id = id;
      this.job = job;
      this.result = result;
      this.creation = Instant.now();
   }

   /**
    * Id of the job.
    */
   public long getId() {
      return id;
   }

   /**
    * Job.
    */
   @SuppressWarnings("unchecked")
   public <J> J getJob() {
      return (J) job;
   }

   /**
    * Job result.
    */
   @SuppressWarnings("unchecked")
   public <R> R getResult() {
      return (R) result;
   }

   /**
    * Job result.
    */
   public void setResult(Object result) {
      this.result = result;
   }

   /**
    * Creation of execution.
    */
   public Instant getCreation() {
      return creation;
   }

   /**
    * Start execution.
    */
   public void start() {
      start = Instant.now();
   }

   /**
    * Start of execution.
    */
   public Instant getStart() {
      return start;
   }

   /**
    * Stop execution.
    */
   public void stop() {
      stop = Instant.now();
   }

   /**
    * Stop of execution.
    */
   public Instant getStop() {
      return stop;
   }

   @Override
   public boolean equals(Object o) {
      return o instanceof Execution &&
            id == ((Execution) o).id &&
            job.equals(((Execution) o).job);
   }

   @Override
   public int hashCode() {
      return Long.hashCode(id);
   }
}

@@ -1068,35 +1068,34 @@
 y(value = %22creat
-ion
+ed
 %22, required = tr
@@ -1122,19 +1122,18 @@
 nt creat
-ion
+ed
 ;%0A%0A   /*
@@ -1293,36 +1293,35 @@
 ;%0A%0A   /**%0A    * 
-Stop
+End
  of execution.%0A 
@@ -1386,36 +1386,35 @@
 operty(value = %22
-stop
+end
 %22, required = fa
@@ -1437,20 +1437,19 @@
 Instant 
-stop
+end
 ;%0A%0A   /*
@@ -2232,19 +2232,18 @@
 = %22creat
-ion
+ed
 %22, requi
@@ -2267,19 +2267,18 @@
 nt creat
-ion
+ed
 ,%0A      
@@ -2376,20 +2376,19 @@
 alue = %22
-stop
+end
 %22, requi
@@ -2408,20 +2408,19 @@
 Instant 
-stop
+end
 ) %7B%0A    
@@ -2582,19 +2582,18 @@
 ll(creat
-ion
+ed
 , %22Preco
@@ -2615,19 +2615,18 @@
 d: creat
-ion
+ed
  != null
@@ -2717,19 +2717,18 @@
 is.creat
-ion
+ed
  = Insta
@@ -3244,19 +3244,18 @@
 getCreat
-ion
+ed
 () %7B%0A   
@@ -3269,19 +3269,18 @@
 rn creat
-ion
+ed
 ;%0A   %7D%0A%0A
@@ -3486,20 +3486,19 @@
 *%0A    * 
-Stop
+End
  executi
@@ -3538,20 +3538,19 @@
 %7B%0A      
-stop
+end
  = Insta
@@ -3578,20 +3578,19 @@
 *%0A    * 
-Stop
+End
  of exec
@@ -3628,12 +3628,11 @@
  get
-Stop
+End
 () %7B
@@ -3645,20 +3645,19 @@
  return 
-stop
+end
 ;%0A   %7D%0A%0A

Add creation, start and stop timestamps to execution