/*
 * 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 com.addthis.hydra.data.tree.prop;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;

import com.addthis.bundle.core.Bundle;
import com.addthis.bundle.core.BundleField;
import com.addthis.bundle.value.ValueFactory;
import com.addthis.bundle.value.ValueObject;
import com.addthis.codec.annotations.FieldConfig;
import com.addthis.hydra.data.filter.value.ValueFilter;
import com.addthis.hydra.data.tree.DataTreeNode;
import com.addthis.hydra.data.tree.DataTreeNodeUpdater;
import com.addthis.hydra.data.tree.TreeDataParameters;
import com.addthis.hydra.data.tree.TreeNodeData;


public final class DataCopy extends TreeNodeData<DataCopy.Config> {

    /**
     * This data attachment <span class="hydra-summary">stores a hashmap of key values
     * captured from the current bundle</span>. You provide the list of fields to keep and
     * any value filter you want to apply and this attachment will keep a copy.
     * <p/>
     * <p>Job Configuration Example:</p>
     * <pre>
     * {field:"ID", data.info.copy.key:{foo:"FOO", bar:"BAR"}}
     * </pre>
     *
     * <p><b>Query Path Directives</b>
     *
     * <p>${attachment}={label[;default value[\;]]} returns the value stored under
     * the given label or the optionally provided default value if the label is empty
     * (eg. if none of the values passed the filter). Little unsure of
     * the syntax/escaping/point of \; here.
     *
     * <p>% operations are not supported</p>
     *
     * @user-reference
     */
    public static final class Config extends TreeDataParameters<DataCopy> {

        /**
         * A mapping from labels to field names. Values are taken from the field
         * names and stored under the label. This field
         * is required.
         */
        @FieldConfig(codable = true, required = true)
        private HashMap<String, String> key;

        /**
         * A mapping from labels to value filters. Before a value is stored under a label
         * if it has a value filter then the filter is applied.
         * The default is no filters.
         */
        @FieldConfig(codable = true)
        private HashMap<String, ValueFilter> op;

        @Override
        public DataCopy newInstance() {
            DataCopy dc = new DataCopy();
            dc.dat = new HashMap<>();
            return dc;
        }
    }

    @FieldConfig(codable = true, required = true)
    private HashMap<String, String> dat;

    private HashMap<String, BundleField> keyAccess;

    @Override
    public boolean updateChildData(DataTreeNodeUpdater state, DataTreeNode tn, DataCopy.Config conf) {
        Bundle p = state.getBundle();
        if (keyAccess == null) {
            keyAccess = new HashMap<>();
            for (Entry<String, String> s : conf.key.entrySet()) {
                keyAccess.put(s.getKey(), p.getFormat().getField(s.getValue()));
            }
        }
        // copy values from pipeline
        for (Entry<String, BundleField> s : keyAccess.entrySet()) {
            ValueObject v = p.getValue(s.getValue());
            if (v != null) {
                if (conf.op != null) {
                    ValueFilter fo = conf.op.get(s.getKey());
                    if (fo != null) {
                        v = fo.filter(v, p);
                        if (v == null) {
                            continue;
                        }
                    }
                }
                dat.put(s.getKey(), v.toString());
            }
        }
        return true;
    }

    @Override
    public Collection<String> getValueTypes() {
        return dat.keySet();
    }

    @Override
    public ValueObject getValue(String key) {
        String dv = null;
        if (dat != null) {
            int ci = key.indexOf(";");
            int eci = key.indexOf("\\;");
            if (ci > 0 && eci - ci != 1) {
                dv = key.substring(ci + 1);
                key = key.substring(0, ci);
            }
            String v = dat.get(key);
            if (v != null && v.length() > 0) {
                return ValueFactory.create(v);
            }
        }
        return dv != null ? ValueFactory.create(dv) : null;
    }
}

@@ -743,27 +743,25 @@
 .bundle.
-core.Bundle
+util.Auto
 Field;%0Ai
@@ -2421,22 +2421,25 @@
 String, 
-String
+AutoField
 %3E key;%0A%0A
@@ -3015,61 +3015,8 @@
 t;%0A%0A
-    private HashMap%3CString, BundleField%3E keyAccess;%0A%0A
     
@@ -3170,253 +3170,8 @@
 ();%0A
-        if (keyAccess == null) %7B%0A            keyAccess = new HashMap%3C%3E();%0A            for (Entry%3CString, String%3E s : conf.key.entrySet()) %7B%0A                keyAccess.put(s.getKey(), p.getFormat().getField(s.getValue()));%0A            %7D%0A        %7D%0A
     
@@ -3230,22 +3230,20 @@
 String, 
-Bundle
+Auto
 Field%3E s
@@ -3249,17 +3249,16 @@
 s : 
-keyAccess
+conf.key
 .ent
@@ -3300,19 +3300,8 @@
 v = 
-p.getValue(
 s.ge
@@ -3308,16 +3308,27 @@
 tValue()
+.getValue(p
 );%0A     
@@ -4031,11 +4031,11 @@
 xOf(
-%22;%22
+';'
 );%0A 
@@ -4094,27 +4094,31 @@
  if 
+(
 (ci %3E 0
+)
  && 
+((
 eci - ci
  != 
@@ -4117,14 +4117,16 @@
 - ci
+)
  != 1)
+)
  %7B%0A 
@@ -4270,32 +4270,33 @@
 %0A            if 
+(
 (v != null && v.
@@ -4293,26 +4293,25 @@
 null
+)
  && 
+!
 v.
-length() %3E 0
+isEmpty()
 ) %7B%0A
@@ -4389,23 +4389,20 @@
         
-return 
+if (
 dv != nu
@@ -4407,10 +4407,30 @@
 null
- ?
+) %7B%0A            return
  Val
@@ -4453,16 +4453,61 @@
 (dv)
- : null;
+;%0A        %7D else %7B%0A            return null;%0A        %7D
 %0A   

update DataCopy to use AutoFields / minor cleanup