/*
 * Copyright 2012 Erlend Hamnaberg
 *
 * 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 net.hamnaberg.json;

import net.hamnaberg.json.extension.Extended;
import net.hamnaberg.json.util.ListOps;
import net.hamnaberg.json.util.MapOps;
import net.hamnaberg.json.util.Optional;
import net.hamnaberg.json.util.Predicate;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.JsonNodeFactory;
import org.codehaus.jackson.node.ObjectNode;

import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public final class Item extends Extended<Item> implements WithHref {

    Item(ObjectNode node) {
        super(node);
    }

    public static Item create(URI href, List<Property> properties, List<Link> links) {
        ObjectNode node = JsonNodeFactory.instance.objectNode();
        node.put("href", href.toString());
        if (!properties.isEmpty()) {
           ArrayNode data = JsonNodeFactory.instance.arrayNode();
            for (Property property : properties) {
                data.add(property.asJson());
            }
            node.put("data", data);
        }
        return new Item(node);
    }

    public URI getHref() {
        return URI.create(delegate.get("href").asText());
    }

    public List<Property> getData() {
        return delegate.has("data") ? Property.fromData(delegate.get("data")) : Collections.<Property>emptyList();
    }

    public Map<String, Property> getDataAsMap() {
        Map<String, Property> builder = MapOps.newHashMap();
        for (Property property : getData()) {
            builder.put(property.getName(), property);
        }
        return Collections.unmodifiableMap(builder);
    }

    public List<Link> getLinks() {
        return delegate.has("links") ? Link.fromArray(delegate.get("links")) : Collections.<Link>emptyList();
    }

    public Template toTemplate() {
        return Template.create(getData());
    }

    public Optional<Link> findLink(Predicate<Link> predicate) {
        return ListOps.find(getLinks(), predicate);
    }

    public List<Link> findLinks(Predicate<Link> predicate) {
        return ListOps.filter(getLinks(), predicate);
    }

    public Optional<Property> findProperty(Predicate<Property> predicate) {
        return ListOps.find(getData(), predicate);
    }

    @Override
    protected Item copy(ObjectNode value) {
        return new Item(value);
    }

    @Override
    public String toString() {
        return String.format("Item with href %s, properties %s and links %s", getHref(), getData(), getLinks());
    }

    static List<Item> fromArray(JsonNode queries) {
        List<Item> builder = ListOps.newArrayList();
        for (JsonNode jsonNode : queries) {
            builder.add(new Item((ObjectNode) jsonNode));
        }
        return Collections.unmodifiableList(builder);
    }

    public void validate() {

    }
}

@@ -1050,64 +1050,9 @@
 til.
-Collections;%0Aimport java.util.List;%0Aimport java.util.Map
+*
 ;%0A%0Ap
@@ -1429,20 +1429,19 @@
 rayNode 
-data
+arr
  = JsonN
@@ -1540,20 +1540,19 @@
         
-data
+arr
 .add(pro
@@ -1611,20 +1611,255 @@
 %22data%22, 
-data
+arr);%0A        %7D%0A        if (!links.isEmpty()) %7B%0A            ArrayNode arr = JsonNodeFactory.instance.arrayNode();%0A            for (Link link : links) %7B%0A                arr.add(link.asJson());%0A            %7D%0A            node.put(%22links%22, arr
 );%0A     
@@ -2664,32 +2664,882 @@
 Data());%0A    %7D%0A%0A
+    public Template toTemplate(Template input) %7B%0A        Map%3CString, Property%3E dataFromTemplate = input.getDataAsMap();%0A        Map%3CString, Property%3E ourData = getDataAsMap();%0A        Set%3CString%3E propsNotInOur = new HashSet%3CString%3E();%0A        List%3CProperty%3E templateProps = new ArrayList%3CProperty%3E();%0A        for (String key : dataFromTemplate.keySet()) %7B%0A            Property property = ourData.get(key);%0A            if (property != null) %7B%0A                templateProps.add(property);%0A            %7D%0A            else %7B%0A                propsNotInOur.add(key);%0A            %7D%0A        %7D%0A        if (propsNotInOur.isEmpty()) %7B%0A            return Template.create(templateProps);%0A        %7D%0A        else %7B%0A            throw new IllegalArgumentException(%22There are some properties that cannot be found in the template:%5Cn%22 + propsNotInOur);%0A        %7D%0A%0A    %7D%0A%0A
     public Optio

Handle lInks in Item Make it possible to use an embedded Template which will be validated.