package io.burt.jmespath.node;

import java.util.List;
import java.util.LinkedList;
import java.util.Collections;

import io.burt.jmespath.Adapter;

public class SliceNode<T> extends Node<T> {
  private final Integer start;
  private final Integer stop;
  private final Integer step;

  public SliceNode(Adapter<T> runtime, Integer start, Integer stop, Integer step, Node<T> source) {
    super(runtime, source);
    this.start = start;
    this.stop = stop;
    this.step = step;
  }

  @Override
  public T searchOne(T projectionElement) {
    List<T> elements = runtime.toList(projectionElement);
    List<T> output = new LinkedList<>();
    int i;
    int n;
    if (start == null) {
      i = step > 0 ? 0 : elements.size();
    } else if (start < 0) {
      i = elements.size() + start;
    } else {
      i = start;
    }
    if (stop == null) {
      n = step > 0 ? elements.size() : -1;
    } else if (stop < 0) {
      n = elements.size() + stop;
    } else {
      n = Math.min(elements.size(), stop);
    }
    if (step > 0) {
      for ( ; i < n; i += step) {
        output.add(elements.get(i));
      }
    } else {
      i = Math.min(i, elements.size() - 1);
      n = Math.max(n, -1);
      for ( ; i > n; i += step) {
        output.add(elements.get(i));
      }
    }
    return runtime.createArray(output);
  }

  protected Integer start() {
    return start;
  }

  protected Integer stop() {
    return stop;
  }

  protected Integer step() {
    return step;
  }

  @Override
  protected String internalToString() {
    return String.format("%d, %d, %d", start, stop, step);
  }

  @Override
  protected boolean internalEquals(Object o) {
    SliceNode other = (SliceNode) o;
    return start() == other.start() && stop() == other.stop() && step() == other.step();
  }

  @Override
  protected int internalHashCode() {
    int h = 1;
    h = h * 31 + start;
    h = h * 31 + stop;
    h = h * 31 + step;
    return h;
  }
}

@@ -42,16 +42,21 @@
 va.util.
+Array
 List;%0Aim
@@ -76,46 +76,10 @@
 l.Li
-nkedList;%0Aimport java.util.Collection
 s
+t
 ;%0A%0Ai
@@ -171,23 +171,19 @@
 e final 
-I
+i
 nt
-eger
  start;%0A
@@ -198,23 +198,19 @@
 e final 
-I
+i
 nt
-eger
  stop;%0A 
@@ -228,21 +228,44 @@
 nal 
-I
+i
 nt
-eger
  step;
+%0A  private final int limit;
 %0A%0A  
@@ -401,21 +401,138 @@
  this.st
-art =
+ep = (step == null) ? 1 : step;%0A    this.limit = (this.step %3C 0) ? -1 : 0;%0A    this.start = (start == null) ? this.limit :
  start;%0A
@@ -551,33 +551,88 @@
 p = 
+(
 stop
-;%0A    this.step = ste
+ == null) ? ((this.step %3C 0) ? Integer.MIN_VALUE : Integer.MAX_VALUE) : sto
 p;%0A 
@@ -757,117 +757,43 @@
     
-List%3CT%3E output = new LinkedList%3C%3E();%0A    int i;%0A    int n;%0A    if (start == null) %7B%0A      i = step %3E
+int begin = (start %3C
  0
+)
  ? 
-0 : 
+Math.max(
 elem
@@ -807,153 +807,38 @@
 ze()
-;%0A    %7D else if (
+ + 
 start
- %3C
+,
  0) 
-%7B%0A      i = elements.size() + start;%0A    %7D else %7B%0A      i = start;%0A    %7D%0A    if (stop == null) %7B%0A      n = step %3E 0 ?
+: Math.min(start,
  ele
@@ -853,28 +853,24 @@
 ze()
- : -1
+)
 ;%0A    
-%7D else if
+int end =
  (st
@@ -877,28 +877,27 @@
 op %3C 0) 
-%7B%0A      n = 
+? Math.max(
 elements
@@ -914,32 +914,18 @@
 stop
-;%0A    %7D else %7B%0A      n =
+, limit) :
  Mat
@@ -930,16 +930,22 @@
 ath.min(
+stop, 
 elements
@@ -955,208 +955,84 @@
 ze()
-, stop
 );%0A    
-%7D%0A    if (step %3E 0) %7B%0A      for ( ; i %3C n; i += step) %7B%0A        output.add(elements.get(i));%0A      %7D%0A    %7D else %7B%0A      i = Math.min(i, elements.size() - 1);%0A      n = Math.max(n, -1
+List%3CT%3E output = new ArrayList%3C%3E(Math.max(0, (end - begin) / step)
 );%0A
-  
     
@@ -1040,16 +1040,31 @@
 or (
- ; i %3E n
+int i = begin; i != end
 ; i 
@@ -1074,18 +1074,16 @@
 step) %7B%0A
-  
       ou
@@ -1113,22 +1113,14 @@
 ));%0A
-  
     %7D%0A
-    %7D%0A
     
@@ -1164,163 +1164,8 @@
  %7D%0A%0A
-  protected Integer start() %7B%0A    return start;%0A  %7D%0A%0A  protected Integer stop() %7B%0A    return stop;%0A  %7D%0A%0A  protected Integer step() %7B%0A    return step;%0A  %7D%0A%0A
   @O
@@ -1388,18 +1388,16 @@
 rn start
-()
  == othe
@@ -1407,18 +1407,16 @@
 tart
-()
  && stop
 () =
@@ -1411,18 +1411,16 @@
  && stop
-()
  == othe
@@ -1429,18 +1429,16 @@
 stop
-()
  && step
 () =
@@ -1433,18 +1433,16 @@
  && step
-()
  == othe
@@ -1447,18 +1447,16 @@
 her.step
-()
 ;%0A  %7D%0A%0A 

Reimplement SliceNode