# Path: intelligine/core/exceptions.py
# class BestMoleculeHere(MoleculeException):
# 
#     def __init__(self, best_distance,  *args, **kwargs):
#         super().__init__(*args, **kwargs)
#         self._best_distance = best_distance
# 
#     def get_best_distance(self):
#         return self._best_distance
# 
# class MoleculeGlandDisabled(MoleculeException):
#     pass
# 
# Path: intelligine/simulation/molecule/DirectionMolecule.py
# class DirectionMolecule():
# 
#     WAY_UP = 'u'
#     WAY_DOWN = 'd'
# 
#     _positions_key = None
# 
#     @classmethod
#     def appose(cls, context, point, molecule):
#         context.molecules().increment_with_molecule(point, molecule, context.get_cycle())
#         context.metas.list.add(MOLECULES, MOLECULES, point, assert_not_in=False)
# 
#     @classmethod
#     def get_direction_for_point(cls, context, point, molecule_type, molecule_way=WAY_UP):
#         flavour = context.molecules().get_flavour(point)
#         molecule = flavour.get_molecule(category=MOLECULES_DIRECTION, type=molecule_type)
# 
#         distance = molecule.get_distance()
#         around_molecule_filter = lambda around_molecule: around_molecule.get_distance() <= distance #  TODO <= ?
#         if molecule_way == cls.WAY_DOWN:
#             around_molecule_filter = lambda around_molecule: around_molecule.get_distance() >= distance
#         around_molecules_points = cls._get_around_molecules(context, point, molecule_type,
#                                                             molecule_filter=around_molecule_filter)
# 
#         if not around_molecules_points \
#            or (len(around_molecules_points) == 1 and around_molecules_points[0][0] == point):
#             raise NoMolecule()
# 
#         shuffle(around_molecules_points)
#         around_molecules_sorted = sorted(around_molecules_points, key=lambda x: x[1].get_intensity(), reverse=True)
#         max_intensity = around_molecules_sorted[0][1].get_intensity()
# 
#         around_molecules_max = []
#         for around_molecule_sorted in around_molecules_sorted:
#             if around_molecule_sorted[1].get_intensity() == max_intensity:
#                 around_molecules_max.append(around_molecule_sorted)
# 
#         reverse = False
#         if molecule_way == cls.WAY_DOWN:
#             reverse = True
#         around_molecules_sorted_by_distance = sorted(around_molecules_max,
#                                                       key=lambda x: x[1].get_distance(),
#                                                       reverse=reverse)
# 
#         all_same_distance = True
#         for mol in around_molecules_sorted_by_distance:
#             mol_mol = mol[1]
#             if mol_mol.get_distance() != distance:
#                 all_same_distance = False
#                 break
# 
#         if all_same_distance:
#             raise NoMolecule()
# 
#         go_to_point = around_molecules_sorted_by_distance[0][0]
# 
#         direction_degrees = get_degree_from_north(point, go_to_point)
#         direction = get_direction_for_degrees(direction_degrees)
# 
#         return direction
# 
#     @classmethod
#     def _get_around_molecules(cls, context, reference_point, molecule_type,
#                               molecule_filter=lambda around_molecule: True):
#         around_points = context.get_around_points_of_point(reference_point)
#         around_molecules_points = []
#         for around_point in around_points:
#             flavour = context.molecules().get_flavour(around_point)
#             try:
#                 around_molecule = flavour.get_molecule(category=MOLECULES_DIRECTION, type=molecule_type)
#                 if molecule_filter(around_molecule):
#                     around_molecules_points.append((around_point, around_molecule))
#             except NoMolecule:
#                 pass  # No molecule, ok continue to sniff around
# 
#         return around_molecules_points
# 
#     @classmethod
#     def get_best_molecule_direction_in(cls, context, reference_point, points, molecule_type):
#         around_molecules_points = []
#         for around_point in points:
#             flavour = context.molecules().get_flavour(around_point)
#             try:
#                 around_molecule = flavour.get_molecule(category=MOLECULES_DIRECTION, type=molecule_type)
#                 around_molecules_points.append((around_point, around_molecule))
#             except NoMolecule:
#                 pass  # Ok, no molecule, continue to sniff around
# 
#         if not around_molecules_points \
#            or (len(around_molecules_points) == 1 and around_molecules_points[0][0] == reference_point):
#             raise NoMolecule()
# 
#         shuffle(around_molecules_points)
#         around_molecules_sorted = sorted(around_molecules_points, key=lambda x: x[1].get_intensity(), reverse=True)
#         go_to_point = around_molecules_sorted[0][0]
# 
#         direction_degrees = get_degree_from_north(reference_point, go_to_point)
#         direction = get_direction_for_degrees(direction_degrees)
# 
#         return direction


from intelligine.core.exceptions import BestMoleculeHere, MoleculeGlandDisabled
from intelligine.simulation.molecule.DirectionMolecule import DirectionMolecule
        self._enabled = False

    def set_molecule_type(self, molecule_type):
        self._molecule_type = molecule_type

    def get_molecule_type(self):
        if self._molecule_type is None:
            raise Exception("molecule_type not specified")
        return self._molecule_type

    def get_molecule(self):
        raise NotImplementedError()

    def appose(self):
        if not self._enabled:
            raise MoleculeGlandDisabled()

        try:
            DirectionMolecule.appose(self._context,
                                     self._host.get_position(),
                                     self.get_molecule())
        except BestMoleculeHere as best_molecule_here:
            self._host.get_brain().set_distance_from_objective(best_molecule_here.get_best_distance())

    def disable(self):
        self._enabled = False

    def enable(self):
        self._enabled = True


# Path: intelligine/core/exceptions.py
# class BestMoleculeHere(MoleculeException):
# 
#     def __init__(self, best_distance,  *args, **kwargs):
#         super().__init__(*args, **kwargs)
#         self._best_distance = best_distance
# 
#     def get_best_distance(self):
#         return self._best_distance
# 
# class MoleculeGlandDisabled(MoleculeException):
#     pass
# 
# Path: intelligine/simulation/molecule/DirectionMolecule.py
# class DirectionMolecule():
# 
#     WAY_UP = 'u'
#     WAY_DOWN = 'd'
# 
#     _positions_key = None
# 
#     @classmethod
#     def appose(cls, context, point, molecule):
#         context.molecules().increment_with_molecule(point, molecule, context.get_cycle())
#         context.metas.list.add(MOLECULES, MOLECULES, point, assert_not_in=False)
# 
#     @classmethod
#     def get_direction_for_point(cls, context, point, molecule_type, molecule_way=WAY_UP):
#         flavour = context.molecules().get_flavour(point)
#         molecule = flavour.get_molecule(category=MOLECULES_DIRECTION, type=molecule_type)
# 
#         distance = molecule.get_distance()
#         around_molecule_filter = lambda around_molecule: around_molecule.get_distance() <= distance #  TODO <= ?
#         if molecule_way == cls.WAY_DOWN:
#             around_molecule_filter = lambda around_molecule: around_molecule.get_distance() >= distance
#         around_molecules_points = cls._get_around_molecules(context, point, molecule_type,
#                                                             molecule_filter=around_molecule_filter)
# 
#         if not around_molecules_points \
#            or (len(around_molecules_points) == 1 and around_molecules_points[0][0] == point):
#             raise NoMolecule()
# 
#         shuffle(around_molecules_points)
#         around_molecules_sorted = sorted(around_molecules_points, key=lambda x: x[1].get_intensity(), reverse=True)
#         max_intensity = around_molecules_sorted[0][1].get_intensity()
# 
#         around_molecules_max = []
#         for around_molecule_sorted in around_molecules_sorted:
#             if around_molecule_sorted[1].get_intensity() == max_intensity:
#                 around_molecules_max.append(around_molecule_sorted)
# 
#         reverse = False
#         if molecule_way == cls.WAY_DOWN:
#             reverse = True
#         around_molecules_sorted_by_distance = sorted(around_molecules_max,
#                                                       key=lambda x: x[1].get_distance(),
#                                                       reverse=reverse)
# 
#         all_same_distance = True
#         for mol in around_molecules_sorted_by_distance:
#             mol_mol = mol[1]
#             if mol_mol.get_distance() != distance:
#                 all_same_distance = False
#                 break
# 
#         if all_same_distance:
#             raise NoMolecule()
# 
#         go_to_point = around_molecules_sorted_by_distance[0][0]
# 
#         direction_degrees = get_degree_from_north(point, go_to_point)
#         direction = get_direction_for_degrees(direction_degrees)
# 
#         return direction
# 
#     @classmethod
#     def _get_around_molecules(cls, context, reference_point, molecule_type,
#                               molecule_filter=lambda around_molecule: True):
#         around_points = context.get_around_points_of_point(reference_point)
#         around_molecules_points = []
#         for around_point in around_points:
#             flavour = context.molecules().get_flavour(around_point)
#             try:
#                 around_molecule = flavour.get_molecule(category=MOLECULES_DIRECTION, type=molecule_type)
#                 if molecule_filter(around_molecule):
#                     around_molecules_points.append((around_point, around_molecule))
#             except NoMolecule:
#                 pass  # No molecule, ok continue to sniff around
# 
#         return around_molecules_points
# 
#     @classmethod
#     def get_best_molecule_direction_in(cls, context, reference_point, points, molecule_type):
#         around_molecules_points = []
#         for around_point in points:
#             flavour = context.molecules().get_flavour(around_point)
#             try:
#                 around_molecule = flavour.get_molecule(category=MOLECULES_DIRECTION, type=molecule_type)
#                 around_molecules_points.append((around_point, around_molecule))
#             except NoMolecule:
#                 pass  # Ok, no molecule, continue to sniff around
# 
#         if not around_molecules_points \
#            or (len(around_molecules_points) == 1 and around_molecules_points[0][0] == reference_point):
#             raise NoMolecule()
# 
#         shuffle(around_molecules_points)
#         around_molecules_sorted = sorted(around_molecules_points, key=lambda x: x[1].get_intensity(), reverse=True)
#         go_to_point = around_molecules_sorted[0][0]
# 
#         direction_degrees = get_degree_from_north(reference_point, go_to_point)
#         direction = get_direction_for_degrees(direction_degrees)
# 
#         return direction


# Path: intelligine/simulation/object/molecule/MoleculeGland.py
from intelligine.core.exceptions import BestMoleculeHere, MoleculeGlandDisabled
from intelligine.simulation.molecule.DirectionMolecule import DirectionMolecule

        self._enabled = False

    def set_molecule_type(self, molecule_type):
        self._molecule_type = molecule_type

    def get_molecule_type(self):
        if self._molecule_type is None:
            raise Exception("molecule_type not specified")
        return self._molecule_type

    def get_molecule(self):
        raise NotImplementedError()

    def appose(self):
        if not self._enabled:
            raise MoleculeGlandDisabled()

        try:
            DirectionMolecule.appose(self._context,
                                     self._host.get_position(),
                                     self.get_molecule())
        except BestMoleculeHere as best_molecule_here:
            self._host.get_brain().set_distance_from_objective(best_molecule_here.get_best_distance())

    def disable(self):
        self._enabled = False

    def enable(self):
        self._enabled = True


    def is_enabled(self):