/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.biohackathon.SPARQLBuilder.OWL;

/**
 *
 * @author atsuko
 */
import java.util.*;

public class OWLClassGraph extends LabeledMultiDigraph{
    int nsteps = 4;
    int limit = 100;
    
    List<String> nodeType;
    String sparqlEndpoint;
    
    public OWLClassGraph(){ // not used
        super();
        nodeType = new LinkedList<String>();
    }
        
    public OWLClassGraph(RDFSchemaAnalyzer rdfsa){ // for experiment
        super();
        nodeType = new LinkedList<String>();
        setClassGraph(rdfsa);
    }
    
    public OWLClassGraph(RDFSchemaAnalyzerFactory rdfsaf){ 
        super();
        nodeType = new LinkedList<String>();
        //setClassGraph(rdfsaf);
    }
    
    public Path[] getPaths(String startClass, String endClass){
        List<List<ClassLink>> paths = searchPaths(startClass, endClass);

        List<Path> sortedpaths = new LinkedList<Path>();
        ListIterator<List<ClassLink>> pit = paths.listIterator();
        int j = 0;
        while ( pit.hasNext() ){
            Path path = new Path();
            path.setStartClass(startClass);
            List<ClassLink> crrpath = pit.next();
            path.setClassLinks(crrpath);
            ListIterator<ClassLink> cit = crrpath.listIterator();
            int min = Integer.MAX_VALUE;
            while ( cit.hasNext() ){
                ClassLink cl = cit.next();
                if ( cl.getNumOfLinks() < min ){
                    min = cl.getNumOfLinks();
                }
            }
            // using length of path
            path.setWidth(500000 - crrpath.size()*100000 + min);
            sortedpaths.add(path);
            j++;
        }
        Path[] patharray = new Path[paths.size()];
        Collections.sort(sortedpaths);
        Iterator<Path> pait = sortedpaths.listIterator();
        int i = 0;
        while ( pait.hasNext() ){
            patharray[paths.size()-i-1] = pait.next();
            i++;
        }
        return patharray;
    }
    
    private List<List<ClassLink>> searchPaths(String startClass, String endClass){
        List<List<ClassLink>> paths = new ArrayList<>();
        Integer snode = labelednodes.get(startClass);
        Integer enode = labelednodes.get(endClass);
        List<List<Integer>> simplePaths = searchSimplePaths(snode, enode);
        
        ListIterator<List<Integer>> pit = simplePaths.listIterator();
        while( pit.hasNext()){
            List<Integer> spath = pit.next();
            List<List<ClassLink>> convertedPaths = convertSimplePathToPaths(spath);
            paths.addAll(convertedPaths);
        }
        //System.out.println("PATH:");
        //System.out.println(paths.size());
        return paths;
    }

    private List<List<Integer>> searchSimplePaths(Integer snode, Integer enode){
        List<List<Integer>> simplePaths = new LinkedList<>();
        List<List<Integer>> lp = new LinkedList<>();
        List<Integer> ini = new LinkedList<Integer>(); // initial path
        ini.add(snode);
        lp.add(ini);
        for (int i = 0; i < nsteps; i++ ){
            ListIterator<List<Integer>> lit = lp.listIterator();
            List<List<Integer>> nextlp = new LinkedList<>();
            while ( lit.hasNext() ){ 
                List<Integer> crrpath = lit.next();
                Integer crrnode = crrpath.get(crrpath.size()-1);
                Set<Integer> nexts = labelededges.get(crrnode).keySet();
                Iterator<Integer> nit = nexts.iterator();
                while( nit.hasNext() ){
                    Integer nextnode = nit.next();
                    if ( crrpath.contains(nextnode) ){ continue; }
                    List<Integer> nextpath = new LinkedList<Integer>(crrpath); // copy
                    nextpath.add(nextnode);
                    if ( nextnode.equals(enode) ){
                        simplePaths.add(nextpath);
                        continue;
                    }
                    nextlp.add(nextpath);
                }
	    }
            lp = nextlp;
        }
        return simplePaths;
    }
    
    
    private List<List<ClassLink>> convertSimplePathToPaths(List<Integer> simplePath){
        List<List<ClassLink>> paths = new LinkedList<List<ClassLink>>();
        ListIterator<Integer> spit = simplePath.listIterator();
        Integer start = spit.next();
        String startClass = this.labels.get(start);
        Integer end = spit.next();
        List<LabeledEdge> edges = labelededges.get(start).get(end);
        ListIterator<LabeledEdge> eit = edges.listIterator();
        while ( eit.hasNext() ){
            List<ClassLink> cl = new LinkedList<ClassLink>();
            cl.add((ClassLink)eit.next().getLabel());
            paths.add(cl);
        }
        start = end;
        while( spit.hasNext() ){
            end = spit.next();
            // start-end
            edges = labelededges.get(start).get(end);
            List<List<ClassLink>> tmppaths = new LinkedList<List<ClassLink>>();            
            // current path
            ListIterator<List<ClassLink>> pit = paths.listIterator();
            while ( pit.hasNext() ){
                List<ClassLink> basepath = pit.next();
                eit = edges.listIterator();
                while ( eit.hasNext() ){
                    ClassLink cl = (ClassLink) eit.next().label;
                    List<ClassLink> addedpath = new LinkedList<ClassLink>(basepath);
                    addedpath.add(cl);
                    tmppaths.add(addedpath);
                }
            }
            paths = tmppaths;
            start = end;
        }
        return paths;
    }
    
    private void setClassGraph(RDFSchemaAnalyzer rdfsa){
        // setNodes
        SClass[] classes = null;
        try{
            classes = rdfsa.getOWLClasses(null, null);
        }catch(Exception e){
            System.err.println(e); return;
        }
        for (int i = 0 ; i < classes.length; i++){
            addNode(classes[i].getClassURI());
            nodeType.add("class");
        }
        // setEdges
        for (int i = 0 ; i < classes.length; i++ ){
            try{
                ClassLink[] classLinks = rdfsa.getNextClass(classes[i].getClassURI(), limit);
                for (int j = 0 ; j < classLinks.length; j++){
                    Integer n = labelednodes.get(classLinks[j].getLinkedClassURI());
                    if ( n != null ){
                        addEdge(i, n, classLinks[j]);
                    }else{
                        n = labelednodes.get(classLinks[j].getLinkedLiteralDatatypeURI());
                        if ( n == null ){
                           addNode(classLinks[j].getLinkedLiteralDatatypeURI());
                           n = nodeType.size();
                           nodeType.add("literal");
                        }
                        addEdge(i, n, classLinks[j]);
                    }
                }
            }catch(Exception e){
                System.err.println(e);
            }
        }       
    }    
}
