class Topology {

    static Configuration toExplicit(Graph g, int u, Configuration c) {

        // already explicit
        if (c.type() != Implicit)
            return c;

        int deg     = g.degree(u);
        int valence = deg + g.atom(u).hydrogens();

        // tetrahedral topology, square planar must always be explicit
        if (valence == 4) {
            return c == ANTI_CLOCKWISE ? TH1 : TH2;
        }

        // tetrahedral topology with implicit lone pair or double bond (Sp2)
        // atoms (todo)
        else if (valence == 3) {

            // XXX: sulfoxide and selenium special case... would be better to compute
            // hybridization don't really like doing this here but is sufficient
            // for now
            if (g.atom(u).element() == Element.Sulfur || g.atom(u).element() == Element.Selenium) {
                int sb = 0, db = 0;
                final int d = g.degree(u);
                for (int j=0; j<d; ++j) {
                    final Edge e = g.edgeAt(u, j);
                    if (e.bond().order() == 1)
                        sb++;
                    else if (e.bond().order() == 2)
                        db++;
                    else return Configuration.UNKNOWN;
                }
                int q = g.atom(u).charge();
                if ((q == 0 && sb == 2 && db == 1) || (q == 1 && sb == 3))
                    return c == ANTI_CLOCKWISE ? TH1 : TH2;
                else
                    return Configuration.UNKNOWN;
            }
            
            if (g.atom(u).element() == Element.Phosphorus ||
                g.atom(u).element() == Element.Nitrogen) {
                if (g.bondedValence(u) == 3 && g.implHCount(u) == 0 && g.atom(u).charge() == 0)  {
                    return c == ANTI_CLOCKWISE ? TH1 : TH2;
                }
            }

            // for the atom centric double bond configuration check there is
            // a double bond and it's not sill tetrahedral specification such
            // as [C@-](N)(O)C
            int nDoubleBonds = 0;
            final int d = g.degree(u);
            for (int j=0; j<d; ++j) {
                final Edge e = g.edgeAt(u, j);
                if (e.bond() == Bond.DOUBLE)
                    nDoubleBonds++;
            }

            if (nDoubleBonds == 1) {
                return c == ANTI_CLOCKWISE ? DB1 : DB2;
            } else {
                return Configuration.UNKNOWN;
            }
        }

        // odd number of cumulated double bond systems (e.g. allene)
        else if (deg == 2) {

            int nDoubleBonds = 0;

            // check both bonds are double
            final int d = g.degree(u);
            for (int j = 0; j < d; ++j) {
                final Edge e = g.edgeAt(u, j);
                if (e.bond() != Bond.DOUBLE)
                    nDoubleBonds++;
            }

            if (nDoubleBonds == 1) {
                return c == ANTI_CLOCKWISE ? DB1 : DB2;
            } else {
                return c == ANTI_CLOCKWISE ? AL1 : AL2;
            }
        }

        // trigonal bipyramidal
        else if (valence == 5) {
            return c == ANTI_CLOCKWISE ? TB1 : TB2;
        }

        // octahedral
        else if (valence == 6) {
            return c == ANTI_CLOCKWISE ? OH1 : OH2;
        }

        return Configuration.UNKNOWN;
    }

}