package no.ssb.vtl.script.support;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
import no.ssb.vtl.model.DataPoint;
import no.ssb.vtl.model.DataStructure;
import no.ssb.vtl.model.VTLObject;

import java.util.LinkedList;
import java.util.List;
import java.util.function.UnaryOperator;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Support class that reorder the values in a DataPoint.
 */
public class DatapointNormalizer implements UnaryOperator<DataPoint> {

    private final int[] swaps;

    public DatapointNormalizer(DataStructure from, DataStructure to) {
        checkNotNull(from);
        checkNotNull(to);

        checkArgument(from.keySet().containsAll(to.keySet()));
        checkArgument(!from.isEmpty());

        ImmutableList<String> fromList = ImmutableSet.copyOf(from.keySet()).asList();
        ImmutableList<String> toList = ImmutableSet.copyOf(to.keySet()).asList();

        // build indices swaps
        LinkedList<Integer> swaps = Lists.newLinkedList();
        String current;
        for (String fromName : fromList) {
            current = fromName;
            int fromIdx = fromList.indexOf(current);
            int toIdx = toList.indexOf(current);
            while (fromIdx != toIdx) {
                if (swaps.isEmpty() || swaps.getLast() != fromIdx)
                    swaps.add(fromIdx);
                toIdx = toList.indexOf(current);
                swaps.add(toIdx);
                current = fromList.get(toIdx);
                fromIdx = fromList.indexOf(current);
            }
        }
        this.swaps = Ints.toArray(swaps);
    }

    @Override
    public DataPoint apply(DataPoint datapoint) {
        if (swaps.length == 0)
            return datapoint;

        VTLObject last = datapoint.get(swaps[0]);
        for (int i = 1; i < swaps.length; i++) {
            VTLObject tmp = datapoint.get(swaps[i]);
            datapoint.set(swaps[i], last);
            last = tmp;
        }

        return datapoint;
    }
}

@@ -312,24 +312,77 @@
 VTLObject;%0A%0A
+import java.util.ArrayList;%0Aimport java.util.Arrays;%0A
 import java.
@@ -756,20 +756,61 @@
 l int%5B%5D 
-swap
+fromIndices;%0A    private final int%5B%5D toIndice
 s;%0A%0A    
@@ -1228,22 +1228,16 @@
  indices
- swaps
 %0A       
@@ -1237,22 +1237,21 @@
         
-Linked
+Array
 List%3CInt
@@ -1256,20 +1256,26 @@
 nteger%3E 
-swap
+fromIndice
 s = List
@@ -1279,22 +1279,21 @@
 ists.new
-Linked
+Array
 List();%0A
@@ -1304,22 +1304,59 @@
     
-String current
+ArrayList%3CInteger%3E toIndices = Lists.newArrayList()
 ;%0A  
@@ -1400,40 +1400,8 @@
 ) %7B%0A
-            current = fromName;%0A
     
@@ -1413,25 +1413,27 @@
    int fromI
-d
+nde
 x = fromList
@@ -1433,39 +1433,40 @@
 romList.indexOf(
-current
+fromName
 );%0A            i
@@ -1467,25 +1467,27 @@
      int toI
-d
+nde
 x = toList.i
@@ -1485,39 +1485,40 @@
  toList.indexOf(
-current
+fromName
 );%0A            w
@@ -1520,34 +1520,33 @@
     
-while
+if
  (fromI
-dx !
+ndex =
 = toI
-dx) %7B
+ndex)
 %0A   
@@ -1562,58 +1562,17 @@
     
-if (swaps.isEmpty() %7C%7C swaps.getLast() != fromIdx)
+continue;
 %0A   
@@ -1576,36 +1576,34 @@
             
-        swap
+fromIndice
 s.add(fromId
@@ -1601,17 +1601,19 @@
 dd(fromI
-d
+nde
 x);%0A    
@@ -1624,65 +1624,16 @@
     
-    
 toI
-dx = toList.indexOf(current);%0A                swap
+ndice
 s.ad
@@ -1633,25 +1633,27 @@
 ices.add(toI
-d
+nde
 x);%0A        
@@ -1652,24 +1652,26 @@
         
+%7D%0A
         
 current 
@@ -1666,115 +1666,53 @@
     
-current = fromList.get(toIdx);%0A                fromIdx = fromList.indexOf(current);%0A            %7D%0A        %7D
+this.fromIndices = Ints.toArray(fromIndices);
 %0A   
@@ -1721,20 +1721,24 @@
    this.
-swap
+toIndice
 s = Ints
@@ -1746,20 +1746,24 @@
 toArray(
-swap
+toIndice
 s);%0A    
@@ -1841,20 +1841,26 @@
     if (
-swap
+fromIndice
 s.length
@@ -1909,47 +1909,53 @@
     
-VTLObject last = datapoint.get(swaps%5B0%5D
+DataPoint copy = (DataPoint) datapoint.clone(
 );%0A 
@@ -1978,19 +1978,25 @@
 i = 
-1
+0
 ; i %3C 
-swap
+fromIndice
 s.le
@@ -2005,18 +2005,16 @@
 th; i++)
- %7B
 %0A       
@@ -2021,24 +2021,8 @@
     
- VTLObject tmp =
  dat
@@ -2032,99 +2032,52 @@
 int.
-get(swaps%5Bi%5D);%0A            datapoint.set(swaps%5Bi%5D, last);%0A            last = tmp;%0A        %7D
+set(toIndices%5Bi%5D, copy.get(fromIndices%5Bi%5D));
 %0A%0A  

Rewrite the datapoint normalizer