/*
 * RESTHeart - the Web API for MongoDB
 * Copyright (C) SoftInstigate Srl
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.restheart.hal;

import java.util.Objects;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonString;
import org.bson.BsonValue;
import org.restheart.handlers.RequestContext;

/**
 *
 * @author Andrea Di Cesare {@literal <andrea@softinstigate.com>}
 */
public class Representation {
    /**
     * Supported content types
     */
    public static final String HAL_JSON_MEDIA_TYPE = "application/hal+json";
    public static final String JSON_MEDIA_TYPE = "application/json";
    public static final String APP_FORM_URLENCODED_TYPE = "application/x-www-form-urlencoded";
    public static final String MULTIPART_FORM_DATA_TYPE = "multipart/form-data";

    private final BsonDocument properties;
    private final BsonDocument embedded;
    private final BsonDocument links;

    /**
     *
     * @param href
     */
    public Representation(String href) {
        properties = new BsonDocument();
        embedded = new BsonDocument();
        links = new BsonDocument();

        if (href != null) {
            links.put("self", new BsonDocument("href", new BsonString(href)));
        }
    }

    /**
     *
     */
    public Representation() {
        this(null);
    }

    public RequestContext.TYPE getType() {
        if (properties == null) {
            return null;
        }

        Object _type = properties.get("_type");

        if (_type == null) {
            return null;
        }

        return RequestContext.TYPE.valueOf(_type.toString());
    }

    public BsonDocument asBsonDocument() {
        if (embedded == null || embedded.isEmpty()) {
            properties.remove("_embedded");
        } else {
            properties.append("_embedded", embedded);
        }

        if (links == null || links.isEmpty()) {
            properties.remove("_links");
        } else {
            properties.append("_links", links);
        }

        if (links != null && !links.isEmpty()) {
            properties.append("_links", links);
        }

        return properties;
    }

    /**
     *
     * @param link
     */
    public void addLink(Link link) {
        links.putAll(link.getBsonDocument());
    }

    /**
     *
     * @param linkArrayRef
     * @return the created or existing link array
     */
    public BsonArray addLinkArray(String linkArrayRef) {
        if (!links.containsKey(linkArrayRef)) {
            links.append(linkArrayRef, new BsonArray());
        }

        BsonArray linkArray = links.getArray(linkArrayRef);

        return linkArray;
    }

    /**
     *
     * @param link
     * @param inArray
     */
    public void addLink(Link link, boolean inArray) {
        BsonArray linkArray = addLinkArray(link.getRef());

        linkArray.add(link.getBsonDocument().get(link.getRef()));

        links.put(link.getRef(), linkArray);
    }

    /**
     *
     * @param key
     * @param value
     */
    public void addProperty(String key, BsonValue value) {
        properties.append(key, value);
    }

    /**
     *
     * @param props
     */
    public void addProperties(BsonDocument props) {
        if (props == null) {
            return;
        }

        properties.putAll(props);
    }

    /**
     *
     * @param rel
     * @param rep
     */
    public void addRepresentation(String rel, Representation rep) {
        if (!embedded.containsKey(rel)) {
            embedded.append(rel, new BsonArray());
        }

        BsonArray repArray = embedded.getArray(rel);

        repArray.add(rep.asBsonDocument());
    }

    public void addWarning(String warning) {
        Representation nrep = new Representation("#warnings");
        nrep.addProperty("message", new BsonString(warning));
        addRepresentation("rh:warnings", nrep);
    }

    @Override
    public String toString() {
        return asBsonDocument().toJson();
    }

    @Override
    public int hashCode() {
        return Objects.hash(embedded, links, properties);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Representation other = (Representation) obj;
        if (!Objects.equals(this.properties, other.properties)) {
            return false;
        }
        if (!Objects.equals(this.embedded, other.embedded)) {
            return false;
        }
        return Objects.equals(this.links, other.links);
    }
}

@@ -1067,16 +1067,17 @@
 ation %7B%0A
+%0A
     /**%0A
@@ -1436,16 +1436,170 @@
 m-data%22;
+%0A    private static final String TYPE = %22_type%22;%0A    private static final String EMBEDDED = %22_embedded%22;%0A    private static final String LINKS = %22_links%22;
 %0A%0A    pr
@@ -2270,23 +2270,20 @@
 ies.get(
-%22_type%22
+TYPE
 );%0A%0A    
@@ -2539,27 +2539,24 @@
 .remove(
-%22_embedded%22
+EMBEDDED
 );%0A     
@@ -2597,27 +2597,24 @@
 .append(
-%22_embedded%22
+EMBEDDED
 , embedd
@@ -2707,24 +2707,21 @@
 .remove(
-%22_links%22
+LINKS
 );%0A     
@@ -2758,32 +2758,29 @@
 ties.append(
-%22_links%22
+LINKS
 , links);%0A  
@@ -2867,24 +2867,21 @@
 .append(
-%22_links%22
+LINKS
 , links)

Replace strings with constants