package ru.yandex.webmaster3.core.semantic.semantic_document_parser.microformats.transformer;

import org.htmlcleaner.TagNode;
import ru.yandex.common.util.collections.Cf;
import ru.yandex.common.util.collections.Cu;
import ru.yandex.common.util.functional.Filter;

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

/**
 * Created by aleksart on 24.07.15.
 */
public class HtmlCleanerLinkResolverContext implements Context<TagNode> {
    final LinkedList<TagNode> nodes;
    List<TagNode> result;
    final DocumentProperties documentProperties;

    public HtmlCleanerLinkResolverContext(final List<TagNode> nodes, final DocumentProperties documentProperties) {
        this.nodes = new LinkedList<TagNode>();
        for (final TagNode node : nodes) {
            this.nodes.add(node);
        }
        this.documentProperties = documentProperties;
    }

    @Override
    public TransformationStep getStep() {
        return TransformationStep.AFTER_LINK_RESOLVE;
    }

    @Override
    public List<TagNode> getInfo() {
        if (result == null) {
            result = new LinkedList<TagNode>();
            for (final TagNode doc : nodes) {
                final List<TagNode> nodes = Tu.findByTagName(doc, "A");
                final List<TagNode> nodesIncl = Cu.filterAsList(nodes, new Filter<TagNode>() {
                    @Override
                    public boolean fits(final TagNode node) {
                        final TagNode anch = node;
                        return (Tu.containsAnyClass(anch.getAttributeByName("class"), Cf.list("include")));
                    }
                });
                for (final TagNode nd : nodesIncl) {
                    final TagNode anch = nd;
                    final String includeId = anch.getAttributeByName("href").substring(1);
                    final TagNode includeElement = searchById(includeId);
                    if (includeElement != null) {
                        if (!isAinNonStrictSubtreeOfB(nd, includeElement)) {
                            //final Node cl = doc.adoptNode(includeElement.cloneNode(true));
                            final TagNode parent = anch.getParent();
                            parent.removeChild(anch);
                            parent.addChild(includeElement.makeCopy());
                        }
                    }
                }
                result.add(doc);
            }
            result = Collections.unmodifiableList(result);
        }
        return result;
    }

    private TagNode searchById(final String id) {
        for (final TagNode el : nodes) {
            final TagNode subTree = Tu.findById(el.getChildTagList().get(0), id);
            if (subTree != null) {
                return subTree;
            }
        }
        return null;
    }

    @Override
    public Context<?> nextStep() {
        /*final LinkedList<String> stubRes = new LinkedList<String>();
        for (DocumentFragment node : getInfo())
        //stubRes.add(Tu.serializeDoc(node));
        {
            stubRes.add(Tu.extractHtmlContent(node) + "\n");
        }
        return new StubContext(stubRes);*/
        /*for (final DocumentFragment df : getInfo()) {
            System.out.println(Tu.serializeDoc(df));
        }*/
        return new ParseTagNodeContext(getInfo(), documentProperties);
    }

    private boolean isAinNonStrictSubtreeOfB(TagNode a, TagNode b){
        return a==b || isAinStrictSubtreeOfB(a, b);
    }
    private boolean isAinStrictSubtreeOfB(TagNode a, TagNode b){
        while (a != null) {
            if (a.getParent() == b) {
                return true;
            }
            a = a.getParent();
        }
        return false;
    }
}
