package jalf;

import static jalf.util.ValidationUtils.validate;
import static jalf.util.ValidationUtils.validateCast;
import static jalf.util.ValidationUtils.validateNotNull;

import java.util.HashMap;
import java.util.Map;
import java.util.function.UnaryOperator;

/**
 * @author amirm
 */
public class Tuple {
    private Map<AttrName, Object> attrs;

    public Tuple(Map<AttrName, Object> attrs){
        this.attrs = attrs;
    }

    public Tuple(Object... keyValuePairs) {
        validateNotNull("Parameter 'keyValuePairs' must be non-null.", keyValuePairs);
        validate("Length of key-value pairs must be even.", keyValuePairs.length % 2, 0);
        attrs = new HashMap<>();
        if (keyValuePairs.length == 0) {
            return;
        }

        for (int i = 0; i < keyValuePairs.length; i++) {
            Object key = keyValuePairs[i++];
            String keyStr = validateCast("Attribute name must be a string.", key, String.class);
            Object value = keyValuePairs[i];
            attrs.put(AttrName.attr(keyStr), value);
        }
    }

    public Tuple project(AttrList on) {
        Map<AttrName, Object> p = new HashMap<>();
        for (AttrName attrName: on){
            p.put(attrName, attrs.get(attrName));
        }
        return new Tuple(p);
    }

    public Tuple rename(UnaryOperator<AttrName> r) {
        Map<AttrName, Object> renamed = new HashMap<>();
        for (AttrName attrName: attrs.keySet()) {
            AttrName as = r.apply(attrName);
            if (as == null)
                as = attrName;
            renamed.put(as, attrs.get(attrName));
        }
        return new Tuple(renamed);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Tuple tuple = (Tuple) o;
        return attrs.equals(tuple.attrs);
    }

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

@@ -19,104 +19,90 @@
 ort 
-static jalf.util.ValidationUtils.validate;%0Aimport static jalf.util.ValidationUtils.validateCast;
+java.util.HashMap;%0Aimport java.util.Map;%0Aimport java.util.function.UnaryOperator;%0A
 %0Aimp
@@ -142,33 +142,18 @@
 ils.
-validateNotNull;%0A
+*;
 %0Aimport 
 java
@@ -140,32 +140,39 @@
 Utils.*;%0Aimport 
+static 
 java.util.HashMa
@@ -169,101 +169,154 @@
 til.
-HashMap;%0Aimport java.util.Map;%0Aimport java.util.function.UnaryOperator;%0A%0A/**%0A * @author amirm
+Collections.unmodifiableMap;%0A%0A/**%0A * A tuple is an immutable set of attributes (i.e. name value pairs), with%0A * no two pairs having the same name.
 %0A */
@@ -424,16 +424,17 @@
 %3E attrs)
+ 
 %7B%0A      
@@ -448,21 +448,38 @@
 attrs = 
+unmodifiableMap(
 attrs
+)
 ;%0A    %7D%0A
@@ -1222,48 +1222,30 @@
     
-for (AttrName attrName: on)%7B%0A           
+on.forEach(attrName -%3E
  p.p
@@ -1273,35 +1273,26 @@
 t(attrName))
+)
 ;
-%0A        %7D
 %0A        ret
@@ -1434,21 +1434,68 @@
         
-for (
+attrs.entrySet().forEach(attribute -%3E %7B%0A            
 AttrName
@@ -1507,27 +1507,30 @@
 Name
-:
+ =
  attr
-s.keySet()) %7B
+ibute.getKey();
 %0A   
@@ -1662,30 +1662,31 @@
 as, attr
-s.get(attrName
+ibute.getValue(
 ));%0A    
@@ -1686,24 +1686,26 @@
 );%0A        %7D
+);
 %0A        ret

Refactor and document Tuple.