package it.unibz.inf.ontop.si.dag;

/*
 * #%L
 * ontop-quest-owlapi
 * %%
 * Copyright (C) 2009 - 2014 Free University of Bozen-Bolzano
 * %%
 * 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.
 * #L%
 */


import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import it.unibz.inf.ontop.si.repository.impl.SemanticIndexBuilder;
import it.unibz.inf.ontop.spec.ontology.*;
import it.unibz.inf.ontop.si.repository.impl.SemanticIndex;
import org.jgrapht.DirectedGraph;
import org.jgrapht.Graphs;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.EdgeReversedGraph;
import org.jgrapht.graph.SimpleDirectedGraph;
import org.jgrapht.traverse.BreadthFirstIterator;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.stream.Stream;

/**
 * Representation of the named part of the property and class DAGs  
 *     based on the NamedDAG abstraction
 * 
 * WARNING: THIS CLASS IS FOR TESTING ONLY 
 */

@Deprecated
public class TestClassifiedTBoxImpl_OnNamedDAG implements ClassifiedTBox {

	private final EquivalencesDAGImpl<ClassExpression> classDAG;
	private final EquivalencesDAGImpl<ObjectPropertyExpression> objectPropertyDAG;
	private final EquivalencesDAGImpl<DataPropertyExpression> dataPropertyDAG;
	private final EquivalencesDAGImpl<DataRangeExpression> dataRangeDAG;

	private final ClassifiedTBox reasoner;

	/**
	 * Constructor using a DAG or a named DAG
	 * @param reasoner DAG to be used for reasoning
	 */
	public TestClassifiedTBoxImpl_OnNamedDAG(ClassifiedTBox reasoner) {

		this.objectPropertyDAG = new EquivalencesDAGImpl<>(
				SemanticIndexBuilder.getNamedDAG(reasoner.objectPropertiesDAG()), reasoner.objectPropertiesDAG());
		this.dataPropertyDAG = new EquivalencesDAGImpl<>(
				SemanticIndexBuilder.getNamedDAG(reasoner.dataPropertiesDAG()), reasoner.dataPropertiesDAG());
		this.classDAG = new EquivalencesDAGImpl<>(
				SemanticIndexBuilder.getNamedDAG(reasoner.classesDAG()), reasoner.classesDAG());
		this.dataRangeDAG = new EquivalencesDAGImpl<>(
				SemanticIndexBuilder.getNamedDAG(reasoner.dataRangesDAG()), reasoner.dataRangesDAG());
		this.reasoner = reasoner;
	}


    @Override
    public OntologyVocabularyCategory<ObjectPropertyExpression> objectProperties() { return reasoner.objectProperties(); }

    @Override
    public OntologyVocabularyCategory<DataPropertyExpression> dataProperties() { return reasoner.dataProperties(); }

    @Override
    public OntologyVocabularyCategory<OClass> classes() {
        return reasoner.classes();
    }


    // DUMMIES

	@Override
	public ImmutableList<NaryAxiom<ClassExpression>> disjointClasses() { return null; }

	@Override
	public ImmutableList<NaryAxiom<ObjectPropertyExpression>> disjointObjectProperties() { return null; }

	@Override
	public ImmutableList<NaryAxiom<DataPropertyExpression>> disjointDataProperties() { return null; }

	@Override
	public ImmutableSet<ObjectPropertyExpression> reflexiveObjectProperties() { return null; }

	@Override
	public ImmutableSet<ObjectPropertyExpression> irreflexiveObjectProperties() { return null; }

	@Override
	public ImmutableSet<ObjectPropertyExpression> functionalObjectProperties() { return null; }

	@Override
	public ImmutableSet<DataPropertyExpression> functionalDataProperties() { return null; }



	@Override
    public EquivalencesDAG<ClassExpression> classesDAG() {
        return classDAG;
    }

    @Override
    public EquivalencesDAG<ObjectPropertyExpression> objectPropertiesDAG() {
        return objectPropertyDAG;
    }

    @Override
    public EquivalencesDAG<DataPropertyExpression> dataPropertiesDAG() {
        return dataPropertyDAG;
    }

    @Override
    public EquivalencesDAG<DataRangeExpression> dataRangesDAG() {
        return dataRangeDAG;
    }


    /**
	 * Reconstruction of the Named DAG (as EquivalencesDAG) from a NamedDAG
	 *
	 * @param <T> Property or BasicClassDescription
	 */
	
	public static final class EquivalencesDAGImpl<T> implements EquivalencesDAG<T> {

		private SimpleDirectedGraph <T,DefaultEdge> dag;
		private EquivalencesDAG<T> reasonerDAG;
		
		public EquivalencesDAGImpl(SimpleDirectedGraph<T, DefaultEdge> dag, EquivalencesDAG<T> reasonerDAG) {
			this.dag = dag;
			this.reasonerDAG = reasonerDAG;
		}

		@Override
		public Iterator<Equivalences<T>> iterator() {
			LinkedHashSet<Equivalences<T>> result = new LinkedHashSet<Equivalences<T>>();

			for (T vertex : dag.vertexSet()) 
				result.add(getVertex(vertex));
			
			return result.iterator();
		}

		@Override
		public Equivalences<T> getVertex(T v) {		
			// either all or none
			Equivalences<T> vertex = reasonerDAG.getVertex(v);
			if (dag.containsVertex(vertex.getRepresentative()))
				return vertex;
			else
				return null;
		}

		@Override
		public ImmutableSet<Equivalences<T>> getDirectSub(Equivalences<T> v) {
			return getDirectSub(v.getRepresentative());
		}
		public ImmutableSet<Equivalences<T>> getDirectSub(T node) {
			LinkedHashSet<Equivalences<T>> result = new LinkedHashSet<>();

			for (T source : Graphs.predecessorListOf(dag, node)) {

				// get the child node and its equivalent nodes
				Equivalences<T> namedEquivalences = getVertex(source);
				if (namedEquivalences != null)
					result.add(namedEquivalences);
				else 
					result.addAll(getDirectSub(source));
			}

			return ImmutableSet.copyOf(result);
		}

		@Override
		public ImmutableSet<Equivalences<T>> getSub(Equivalences<T> v) {
			
			T node = v.getRepresentative();
			
			LinkedHashSet<Equivalences<T>> result = new LinkedHashSet<Equivalences<T>>();
			// reverse the dag
			DirectedGraph<T, DefaultEdge> reversed = new EdgeReversedGraph<T, DefaultEdge>(dag);
			BreadthFirstIterator<T, DefaultEdge>  iterator = new BreadthFirstIterator<T, DefaultEdge>(reversed, node);

			while (iterator.hasNext()) {
				T child = iterator.next();

				// add the node and its equivalent nodes
				Equivalences<T> sources = getVertex(child);
				if (sources != null)
					result.add(sources);
			}
			
			return ImmutableSet.copyOf(result);
		}

		@Override
		public ImmutableSet<Equivalences<T>> getDirectSuper(Equivalences<T> v) {
			return getDirectSuper(v.getRepresentative());
		}

		public ImmutableSet<Equivalences<T>> getDirectSuper(T node) {
			LinkedHashSet<Equivalences<T>> result = new LinkedHashSet<>();
			
			for (T target : Graphs.successorListOf(dag, node)) {

				// get the child node and its equivalent nodes
				Equivalences<T> namedEquivalences = getVertex(target);
				if (namedEquivalences != null)
					result.add(namedEquivalences);
				else 
					result.addAll(getDirectSuper(target));
			}

			return ImmutableSet.copyOf(result);
		}

		@Override
		public ImmutableSet<Equivalences<T>> getSuper(Equivalences<T> v) {

			T node = v.getRepresentative();
			
			LinkedHashSet<Equivalences<T>> result = new LinkedHashSet<>();
			BreadthFirstIterator<T, DefaultEdge>  iterator = new BreadthFirstIterator<>(dag, node);

			while (iterator.hasNext()) {
				T parent = iterator.next();

				// add the node and its equivalent nodes
				Equivalences<T> sources = getVertex(parent);
				if (sources != null)
					result.add(sources);
			}

			return ImmutableSet.copyOf(result);
		}

		@Override
		public Stream<Equivalences<T>> stream() {
			return null;
		}

		@Override
		public ImmutableSet<T> getSubRepresentatives(T v) {
			return null;
		}

		@Override
		public T getCanonicalForm(T v) {
			return null;
		}
	}
}
