package com.simolecule.centres;

import com.simolecule.centres.config.Configuration;
import com.simolecule.centres.rules.Rule1a;
import com.simolecule.centres.rules.Rule1b;
import com.simolecule.centres.rules.Rule2;
import com.simolecule.centres.rules.Rule3;
import com.simolecule.centres.rules.Rule4a;
import com.simolecule.centres.rules.Rule4bNew;
import com.simolecule.centres.rules.Rule4c;
import com.simolecule.centres.rules.Rule5;
import com.simolecule.centres.rules.Rule6;
import com.simolecule.centres.rules.Rules;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Labeller<A, B> {

  public void label(BaseMol<A, B> mol, List<Configuration<A, B>> configs) {
    // constitutional rules
    final Rules<A, B> begRules = new Rules<>(new Rule1a<>(mol),
                                             new Rule1b<>(mol),
                                             new Rule2<>(mol)
    );
    // all rules
    final Rules<A, B> allRules = new Rules<>(new Rule1a<>(mol),
                                             new Rule1b<>(mol),
                                             new Rule2<>(mol),
                                             new Rule3<>(mol),
                                             new Rule4a<>(mol),
                                             new Rule4bNew<>(mol),
                                             new Rule4c<>(mol),
                                             new Rule5<>(mol),
                                             new Rule6<>(mol)
    );

    // Stats.INSTANCE.countNumCenters(configs.size());

    Map<Configuration<A, B>, Descriptor> finalLabels = new HashMap<>();
    for (Configuration<A, B> conf : configs) {
      conf.setDigraph(new Digraph<A, B>(mol));
      Descriptor desc = conf.label(begRules);
      if (desc != null && desc != Descriptor.Unknown) {
        conf.setPrimaryLabel(mol, desc);
      } else {

        //System.out.println("C"+(mol.getAtomIdx(conf.getFocus())+1));
        if (labelAux(configs, allRules, conf)) {

          //  Stats.INSTANCE.numAuxCalculated.incrementAndGet();
          desc = conf.label(allRules);

          // System.out.println(mol.dumpDigraph(conf.getDigraph()));
          if (desc != null && desc != Descriptor.Unknown) {
            //      Stats.INSTANCE.numAuxLabelled.incrementAndGet();
            conf.setPrimaryLabel(mol, desc);
          }
        }
      }
      //Stats.INSTANCE.measureDigraph(conf.getDigraph());
    }
    //Stats.INSTANCE.numConfigLabelled.addAndGet(finalLabels.size());
  }

  private boolean labelAux(List<Configuration<A, B>> configs,
                           Rules<A, B> rules,
                           Configuration<A, B> center) {
    List<Map.Entry<Node<A, B>, Configuration<A, B>>> aux = new ArrayList<>();

    Digraph<A, B> digraph = center.getDigraph();
    for (Configuration<A, B> config : configs) {
      if (config.equals(center))
        continue;
      A[] foci = config.getFoci();
      for (Node<A, B> node : digraph.getNodes(foci[0])) {
        if (node.isDuplicate())
          continue;
        Node<A, B> low = node;
        if (foci.length == 2) {
          for (Edge<A, B> edge : node.getEdges(foci[1])) {
            if (edge.getOther(node).getDistance() < node.getDistance())
              low = edge.getOther(node);
          }
        }
        if (!low.isDuplicate())
          aux.add(new AbstractMap.SimpleImmutableEntry<>(low, config));
      }
    }

    Collections.sort(aux,
                     new Comparator<Map.Entry<Node<A, B>, Configuration<A, B>>>() {
                       @Override
                       public int compare(
                               Map.Entry<Node<A, B>, Configuration<A, B>> a,
                               Map.Entry<Node<A, B>, Configuration<A, B>> b) {
                         return -Integer.compare(a.getKey().getDistance(),
                                                 b.getKey().getDistance());
                       }
                     });

    Map<Node<A, B>, Descriptor> queue = new HashMap<>();
    int                         prev  = Integer.MAX_VALUE;
    for (Map.Entry<Node<A, B>, Configuration<A, B>> e : aux) {
      Node<A, B> node = e.getKey();

      if (node.getDistance() < prev) {
        for (Map.Entry<Node<A, B>, Descriptor> e2 : queue.entrySet())
          e2.getKey().setAux(e2.getValue());
        queue.clear();
        prev = node.getDistance();
      }
      //System.out.println(node.getDistance());

      Configuration<A, B> config = e.getValue();
      Descriptor          label  = config.label(node, digraph, rules);
      queue.put(node, label);
    }

    for (Map.Entry<Node<A, B>, Descriptor> e : queue.entrySet())
      e.getKey().setAux(e.getValue());

    return true;
  }
}

@@ -2020,80 +2020,8 @@
 se %7B
-%0A%0A        //System.out.println(%22C%22+(mol.getAtomIdx(conf.getFocus())+1));
 %0A   
@@ -2176,77 +2176,8 @@
 );%0A%0A
-          // System.out.println(mol.dumpDigraph(conf.getDigraph()));%0A
     
@@ -4413,57 +4413,8 @@
   %7D%0A
-      //System.out.println(node.getDistance());%0A%0A
     

Remove redundant print statements.