Create a construction table for a Zmatrix.

        A construction table is basically a Zmatrix without the values
        for the bond lenghts, angles and dihedrals.
        It contains the whole information about which reference atoms
        are used by each atom in the Zmatrix.

        This method creates a so called "chemical" construction table,
        which makes use of the connectivity table in this molecule.

        By default the first atom is the one nearest to the centroid.
        (Compare with :meth:`~Cartesian.get_centroid()`)

        Args:
            start_atom: An index for the first atom may be provided.
            predefined_table (pd.DataFrame): An uncomplete construction table
                may be provided. The rest is created automatically.
            use_lookup (bool): Use a lookup variable for
                :meth:`~chemcoord.Cartesian.get_bonds`. The default is
                specified in ``settings['defaults']['use_lookup']``

        Returns:
            pd.DataFrame: Construction table

def _get_frag_constr_table(self, start_atom=None, predefined_table=None,
                               use_lookup=None, bond_dict=None):
        """Create a construction table for a Zmatrix.

        A construction table is basically a Zmatrix without the values
        for the bond lenghts, angles and dihedrals.
        It contains the whole information about which reference atoms
        are used by each atom in the Zmatrix.

        This method creates a so called "chemical" construction table,
        which makes use of the connectivity table in this molecule.

        By default the first atom is the one nearest to the centroid.
        (Compare with :meth:`~Cartesian.get_centroid()`)

        Args:
            start_atom: An index for the first atom may be provided.
            predefined_table (pd.DataFrame): An uncomplete construction table
                may be provided. The rest is created automatically.
            use_lookup (bool): Use a lookup variable for
                :meth:`~chemcoord.Cartesian.get_bonds`. The default is
                specified in ``settings['defaults']['use_lookup']``

        Returns:
            pd.DataFrame: Construction table
        """
        if use_lookup is None:
            use_lookup = settings['defaults']['use_lookup']

        def modify_priority(bond_dict, user_defined):
            def move_to_start(dct, key):
                "Due to PY27 compatibility"
                keys = dct.keys()
                if key in keys and key != keys[0]:
                    root = dct._OrderedDict__root
                    first = root[1]
                    link = dct._OrderedDict__map[key]
                    link_prev, link_next, _ = link
                    link_prev[1] = link_next
                    link_next[0] = link_prev
                    link[0] = root
                    link[1] = first
                    root[1] = first[0] = link
                else:
                    raise KeyError

            for j in reversed(user_defined):
                try:
                    try:
                        bond_dict.move_to_end(j, last=False)
                    except AttributeError:
                        # No move_to_end method in python 2.x
                        move_to_start(bond_dict, j)
                except KeyError:
                    pass

        if start_atom is not None and predefined_table is not None:
            raise IllegalArgumentCombination('Either start_atom or '
                                             'predefined_table has to be None')
        if bond_dict is None:
            bond_dict = self._give_val_sorted_bond_dict(use_lookup=use_lookup)
        if predefined_table is not None:
            self._check_construction_table(predefined_table)
            construction_table = predefined_table.copy()

        if predefined_table is None:
            if start_atom is None:
                molecule = self.get_distance_to(self.get_centroid())
                i = molecule['distance'].idxmin()
            else:
                i = start_atom
            order_of_def = [i]
            user_defined = []
            construction_table = {i: {'b': 'origin',
                                      'a': 'e_z',
                                      'd': 'e_x'}}
        else:
            i = construction_table.index[0]
            order_of_def = list(construction_table.index)
            user_defined = list(construction_table.index)
            construction_table = construction_table.to_dict(orient='index')

        visited = {i}
        if len(self) > 1:
            parent = {j: i for j in bond_dict[i]}
            work_bond_dict = OrderedDict(
                [(j, bond_dict[j] - visited) for j in bond_dict[i]])
            modify_priority(work_bond_dict, user_defined)
        else:
            parent, work_bond_dict = {}, {}

        while work_bond_dict:
            new_work_bond_dict = OrderedDict()
            for i in work_bond_dict:
                if i in visited:
                    continue
                if i not in user_defined:
                    b = parent[i]
                    if b in order_of_def[:3]:
                        if len(order_of_def) == 1:
                            construction_table[i] = {'b': b,
                                                     'a': 'e_z',
                                                     'd': 'e_x'}
                        elif len(order_of_def) == 2:
                            a = (bond_dict[b] & set(order_of_def))[0]
                            construction_table[i] = {'b': b, 'a': a,
                                                     'd': 'e_x'}
                        else:
                            try:
                                a = parent[b]
                            except KeyError:
                                a = (bond_dict[b] & set(order_of_def))[0]
                            try:
                                d = parent[a]
                                if d in set([b, a]):
                                    message = "Don't make self references"
                                    raise UndefinedCoordinateSystem(message)
                            except (KeyError, UndefinedCoordinateSystem):
                                try:
                                    d = ((bond_dict[a] & set(order_of_def))
                                         - set([b, a]))[0]
                                except IndexError:
                                    d = ((bond_dict[b] & set(order_of_def))
                                         - set([b, a]))[0]
                            construction_table[i] = {'b': b, 'a': a, 'd': d}
                    else:
                        a, d = [construction_table[b][k] for k in ['b', 'a']]
                        construction_table[i] = {'b': b, 'a': a, 'd': d}
                    order_of_def.append(i)

                visited.add(i)
                for j in work_bond_dict[i]:
                    new_work_bond_dict[j] = bond_dict[j] - visited
                    parent[j] = i

            work_bond_dict = new_work_bond_dict
            modify_priority(work_bond_dict, user_defined)
        output = pd.DataFrame.from_dict(construction_table, orient='index')
        output = output.loc[order_of_def, ['b', 'a', 'd']]
        return output