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 = "create", 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(
         @JsonProperty(value = "id", required = true) long id,
         @JsonProperty(value = "job", required = true) Object job,
         @JsonProperty(value = "result", required = true) Object result) {
      Assert.notNull(job, "Precondition violated: job != null.");
      Assert.notNull(job, "Precondition violated: result != 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);
   }
}

@@ -1076,17 +1076,19 @@
 = %22creat
-e
+ion
 %22, requi
@@ -1842,16 +1842,170 @@
 ecution(
+long id, Object job, Object result) %7B%0A      this(id, job, result, Instant.now(), null, null);%0A   %7D%0A%0A   /**%0A    * Jackson constructor.%0A    */%0A   Execution(
 %0A       
@@ -2190,32 +2190,254 @@
 e) Object result
+,%0A         @JsonProperty(value = %22creation%22, required = true) Instant creation,%0A         @JsonProperty(value = %22start%22, required = false) Instant start,%0A         @JsonProperty(value = %22stop%22, required = false) Instant stop
 ) %7B%0A      Assert
@@ -2503,35 +2503,38 @@
  Assert.notNull(
-job
+result
 , %22Precondition 
@@ -2561,16 +2561,95 @@
 null.%22);
+%0A      // Assert.notNull(creation, %22Precondition violated: creation != null.%22);
 %0A%0A      

Add creation, start and stop timestamps to execution