package com.besil.neo4jsna.algorithms;

import com.besil.neo4jsna.engine.algorithm.VertexAlgorithm;
import it.unimi.dsi.fastutil.longs.Long2LongMap;
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;

import java.util.Map.Entry;

public class LabelPropagation implements VertexAlgorithm<Long2LongMap> {
    protected final String attName = "community";
    protected final RelationshipType relType;
    protected Long2LongMap communityMap;

    public LabelPropagation() {
        this(null);
    }

    public LabelPropagation(RelationshipType relType) {
        this.communityMap = new Long2LongOpenHashMap();
        this.relType = relType;
    }

	@Override
	public void init(Node node) {
		node.setProperty(attName, node.getId());
	}

	@Override
	public void apply(Node node) {
		long mostFrequentLabel = this.getMostFrequentLabel(node);
		node.setProperty(attName, mostFrequentLabel);
	}

	protected long getMostFrequentLabel(Node node) {
		Long2LongMap commMap = new Long2LongOpenHashMap();
        Iterable<Relationship> relationships = relType == null ? node.getRelationships() : node.getRelationships(relType);

        for (Relationship r : relationships) {
            Node other = r.getOtherNode(node);
			long otherCommunity = (long) other.getProperty(attName);
			// commMap.put(other.getId(), otherCommunity);	WRONG
			long count = commMap.getOrDefault(otherCommunity, 0L);
			commMap.put(otherCommunity, count+1);
		}

		long mostFrequentLabel = -1;
		long mostFrequentLabelCount = -1;
		for( Entry<Long, Long> e : commMap.entrySet() ) {
			if( e.getValue() > mostFrequentLabelCount ) {
				mostFrequentLabelCount = e.getValue();
				mostFrequentLabel = e.getKey();
			}
		}
		return mostFrequentLabel;
	}

	@Override
	public void collectResult(Node node) {
		this.communityMap.put(node.getId(), (long) node.getProperty(attName));
	}

	@Override
	public int getMaxIterations() {
		return 20;
	}

	@Override
	public String getName() {
		return "Label Propagation CD";
	}

	@Override
	public Long2LongMap getResult() {
		return communityMap;
	}

	@Override
	public String getAttributeName() {
		return attName;
	}

}