/*
 * Copyright (c) 2016 IBM Corporation and others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.brunel.data.modify;

import org.brunel.data.Data;
import org.brunel.data.Dataset;
import org.brunel.data.Field;
import org.brunel.data.Fields;
import org.brunel.data.util.ItemsList;

import java.util.ArrayList;
import java.util.List;

/**
 * This transform takes data and multiplies rows
 */
public class Each extends DataOperation {


    /*
     * Command is a list of fields to use to split rows
     */
    public static Dataset transform(Dataset base, String command) {
        // Apply successively to each usable field
        for (String s : strings(command, ';')) {
            Field f = base.field(s);
            if (f.isProperty("list"))
                base = splitFieldValues(base, f);
        }
        return base;
    }

    private static Dataset splitFieldValues(Dataset base, Field target) {

       ItemsList nulls = new ItemsList(new Object[1]);

        List<Integer> index = new ArrayList<>();         // For the non-target fields
        List<Object> splitValues = new ArrayList<>();     // For the target field
        for (int i = 0; i < target.rowCount(); i++) {
            ItemsList list = (ItemsList) target.value(i);
            if (list == null) list = nulls;                     // Treat a null as a list with a single null item
            for (int j=0; j<list.size(); j++) {
                splitValues.add(list.get(i));                   // Add the actual value
                index.add(i);                                   // Repeat the index for each list case
            }
        }

        // Convert List<Integer> to int[]
        int[] idx = Data.toPrimitive(index.toArray(new Integer[index.size()]));

        Field[] results = new Field[base.fields.length];
        for (int i = 0; i < results.length; i++) {
            Field f = base.fields[i];
            if (f == target) {
                Object[] data = splitValues.toArray(new Object[splitValues.size()]);
                results[i] = Fields.makeColumnField(f.name, f.label, data);
            } else {
                results[i] = Fields.permute(f, idx, false);
            }
        }

        return base.replaceFields(results);

    }

}

@@ -897,23 +897,96 @@
 and 
-multiplies rows
+converts a single row with multiple items into multiple rows each%0A * with a single item.
 %0A */
@@ -1029,17 +1029,16 @@
 tion %7B%0A%0A
-%0A
     /*%0A 
@@ -1371,27 +1371,28 @@
  = split
-FieldValues
+ListsInField
 (base, f
@@ -1468,19 +1468,20 @@
 plit
-FieldValues
+ListsInField
 (Dat
@@ -1512,64 +1512,8 @@
  %7B%0A%0A
-       ItemsList nulls = new ItemsList(new Object%5B1%5D);%0A%0A
     
@@ -1530,21 +1530,20 @@
 nteger%3E 
-index
+rows
  = new A
@@ -1551,24 +1551,28 @@
 rayList%3C%3E();
+    
          // 
@@ -1575,33 +1575,40 @@
  // 
-For the non-target fields
+A list of the rows from the base
 %0A   
@@ -1625,21 +1625,21 @@
 Object%3E 
-split
+field
 Values =
@@ -1666,25 +1666,49 @@
     
+  
 // 
-For the target
+A parallel list of the values of the
  fie
@@ -1856,21 +1856,49 @@
 ll) 
-list = 
+%7B%0A                fieldValues.add(
 null
-s;
+); 
     
@@ -1921,54 +1921,139 @@
  // 
-Treat a null as a list with a single null item
+Add a single null value for this row%0A                rows.add(i);                                // Add a single index for this row
 %0A   
@@ -2053,32 +2053,39 @@
 row%0A            
+%7D else 
 for (int j=0; j%3C
@@ -2120,21 +2120,21 @@
         
-split
+field
 Values.a
@@ -2145,17 +2145,17 @@
 ist.get(
-i
+j
 ));     
@@ -2168,29 +2168,49 @@
     
-    // Add the actual
+// For the j-th item,in the list, add the
  val
@@ -2228,21 +2228,20 @@
         
-index
+rows
 .add(i);
@@ -2276,23 +2276,22 @@
     
-   // Repeat th
+// Add the sam
 e in
@@ -2417,21 +2417,20 @@
 imitive(
-index
+rows
 .toArray
@@ -2442,21 +2442,20 @@
 Integer%5B
-index
+rows
 .size()%5D
@@ -2668,21 +2668,21 @@
  data = 
-split
+field
 Values.t
@@ -2699,21 +2699,21 @@
  Object%5B
-split
+field
 Values.s

Fix defect in "Each"