package ru.yandex.webmaster3.core.semantic.semantic_document_parser.rdfa;

import org.json.*;
import ru.yandex.common.util.Su;
import ru.yandex.common.util.collections.MultiMap;
import ru.yandex.common.util.xml.Xmler;
import ru.yandex.webmaster3.core.semantic.semantic_document_parser.rdfa.data.RDFaComplexProperty;
import ru.yandex.webmaster3.core.semantic.semantic_document_parser.rdfa.data.RDFaEntity;
import ru.yandex.webmaster3.core.semantic.semantic_document_parser.rdfa.data.RDFaProperty;
import ru.yandex.webmaster3.core.semantic.semantic_document_parser.rdfa.data.RDFaValueProperty;
import ru.yandex.webmaster3.core.semantic.semantic_document_parser.serialize.util.APIVersion;

import java.util.LinkedList;
import java.util.List;

import static ru.yandex.common.util.StringUtils.isEmpty;
import static ru.yandex.common.util.xml.Xmler.tag;
import static ru.yandex.webmaster3.core.semantic.semantic_document_parser.microformats.FrontEnd.cropString;
import static ru.yandex.webmaster3.core.semantic.semantic_document_parser.microformats.FrontEnd.verifierNode;

/**
 * Created by IntelliJ IDEA.
 * User: rasifiel
 * Date: 16.08.12
 * Time: 14:07
 */
public class RDFaUtils {

    public static Xmler.Tag toXml(final RDFaEntity entity, final boolean firstLevel, final String tagName) {
        final List<Xmler.Tag> tags = new LinkedList<Xmler.Tag>();
        if(firstLevel && entity.isIdFromUrl()){

        }
        if (!isEmpty(entity.id)) {
            tags.add(verifierNode(entity.getResourceTag(), null, false, tag("v", entity.id)));
        }
        if (!isEmpty(entity.type)) {
            for (final String type : Su.split(entity.type)) {
                tags.add(verifierNode(entity.getTypeTag(), null, false, tag("v", type)));
            }
        }
        for (final RDFaProperty entry : entity.getValuePairs()) {
            tags.add(propertyXml(entry));
        }
        if (tags.size() == 1 && tagName == null) {
            return tags.get(0);
        }
        return verifierNode(tagName != null ? tagName : entity.getTagName(), entity.count, firstLevel, tags);
    }

    private static Xmler.Tag propertyXml(final RDFaValueProperty property) {
        final List<Xmler.Tag> tags = new LinkedList<Xmler.Tag>();
        boolean hasText = false;
        if (property.textValue != null && !property.textValue.isEmpty()) {
            hasText = true;
            tags.add(verifierNode("text", null, false, tag("v", cropString(property.textValue))));
        }
        if (property.hrefValue != null && !property.hrefValue.isEmpty()) {
            tags.add(verifierNode("href", null, false, tag("v", property.hrefValue)));
        }
        if (tags.size() == 1) {
            return verifierNode(property.propId, null, false,
                    tag("v", hasText ? cropString(property.textValue) : property.hrefValue));
        }
        return verifierNode(property.propId, null, false, tags);
    }

    private static Xmler.Tag propertyXml(final RDFaComplexProperty property) {
        return toXml(property.entity, false, property.propId);
    }

    private static Xmler.Tag propertyXml(final RDFaProperty property) {
        if (property instanceof RDFaValueProperty) {
            return propertyXml((RDFaValueProperty) property);
        } else if (property instanceof RDFaComplexProperty) {
            return propertyXml((RDFaComplexProperty) property);
        } else {
            return verifierNode(property.propId, null, false);
        }
    }

    public static List<Xmler.Tag> getVerifierNodes(final List<RDFaEntity> entities, final boolean ignoreRoot) {
        final List<Xmler.Tag> result = new LinkedList<Xmler.Tag>();
        for (final RDFaEntity entity : entities) {
            if ((ignoreRoot || entity.isRoot) && (!"".equals(entity.id) || !entity.isEmpty())) {
                result.add(toXml(entity, true, null));
            }
        }
        return result;
    }

    public static JSONObject toAPIJson(final RDFaEntity entity,
                                       final MultiMap<Integer, JSONObject> exceptions,
                                       final boolean only_errors,
                                       APIVersion version) throws JSONException {
        JSONObject result = new JSONObject();
        if(!only_errors) {
            if (!Su.isEmpty(entity.id)) {
                if (!entity.isIdFromUrl()) {
                    result.append(APIVersion.getResourceKey(version), entity.id);
                }
            }
            if (!Su.isEmpty(entity.type)) {
                result.put("@type", Su.split(entity.type));
            }
            if (!Su.isEmpty(entity.type) || !entity.isRoot) {
                switch (version) {
                    case VERSION_1_1:
                        result.put("#location", entity.getLocation());
                        break;
                }
            }
        }
        if (exceptions != null) {
            if (exceptions.containsKey(entity.count)) {
                for (JSONObject e : exceptions.get(entity.count)) {
                    result.append(APIVersion.getErrorKey(version), APIVersion.serializeToArrayForOldVersion(version, e));
                }
            }
        }
        for (final String prop : entity.getPropertyList()) {
            for (final RDFaProperty val : entity.getProperty(prop)) {
                if (val instanceof RDFaComplexProperty) {
                    result.append(prop, toAPIJson(((RDFaComplexProperty) val).entity, exceptions, only_errors, version));
                } else if (val instanceof RDFaValueProperty && !only_errors) {

                    switch(version){
                        case VERSION_0_1:
                        case VERSION_1_0:
                            if ((((RDFaValueProperty) val).textValue != null) && (((RDFaValueProperty) val).hrefValue == null)) {
                                result.append(prop, ((RDFaValueProperty) val).textValue);
                            }
                            if (((RDFaValueProperty) val).hrefValue != null) {
                                result.append(prop,((RDFaValueProperty) val).hrefValue);
                            }
                            break;
                        case VERSION_1_1:
                            if ("@value".equals(prop)) {
                                result.put("@value", ((RDFaValueProperty) val).getValue()).put("#location", val.getLocation());
                            } else if("@id".equals(prop)) {
                                result.put("@id", ((RDFaValueProperty) val).getValue()).put("#location", val.getLocation());
                            }else if ("@type".equals(prop)) {

                                if ((((RDFaValueProperty) val).textValue != null) && (((RDFaValueProperty) val).hrefValue == null)) {
                                    result.append(prop, ((RDFaValueProperty) val).textValue);
                                }
                                if (((RDFaValueProperty) val).hrefValue != null) {
                                    result.append(prop,((RDFaValueProperty) val).hrefValue);
                                }
                            }else{
                                JSONObject valueObj = new JSONObject();

                                if ((((RDFaValueProperty) val).textValue != null) && (((RDFaValueProperty) val).hrefValue == null)) {
                                    valueObj.put("@value", ((RDFaValueProperty) val).textValue).put("#location", val.getLocation());
                                }
                                if (((RDFaValueProperty) val).hrefValue != null) {
                                    valueObj.put("@id", ((RDFaValueProperty) val).hrefValue).put("#location", val.getLocation());
                                }
                                result.append(prop, valueObj);
                            }
                            break;
                    }

                }
            }
        }
        return result;
    }



    public static JSONObject toTestJSON(final RDFaEntity entity) throws JSONException {
        JSONObject result = new JSONObject();
        for (final String prop : entity.getPropertyList()) {
            for (final RDFaProperty val : entity.getProperty(prop)) {
                if (val instanceof RDFaComplexProperty) {
                    result.append(prop, toTestJSON(((RDFaComplexProperty) val).entity));
                }
                if (val instanceof RDFaValueProperty) {
                    if (((RDFaValueProperty) val).textValue != null) {
                        if (!result.has(prop)) {
                            result.put(prop, ((RDFaValueProperty) val).textValue);
                        } else {
                            result.accumulate(prop, ((RDFaValueProperty) val).textValue);
                        }
                    } else if (((RDFaValueProperty) val).hrefValue != null) {
                        if (!result.has(prop)) {
                            result.put(prop, ((RDFaValueProperty) val).hrefValue);
                        } else {
                            result.accumulate(prop, ((RDFaValueProperty) val).hrefValue);
                        }
                    }
                }
            }
            if (prop.equals("@type")) {
                if (result.optJSONArray("@type") == null) {
                    result.put("@type", new JSONArray().put(result.get("@type")));
                } else {
                    result.put("@type", result.optJSONArray("@type"));
                }
            }
        }
        return result;

    }
}
