from xentica.core.topology.mixins import DimensionsMixin

from xentica.core.mixins import BscaDetectorMixin
from xentica.core.variables import Constant


class Lattice(DimensionsMixin, BscaDetectorMixin):
    """
    Base class for all lattices.

    """
    width_prefix = "_w"

    def _define_constants_once(self):
        for i in range(self._bsca.topology.dimensions):
            constant = Constant("%s%d" % (self.width_prefix, i),
                                "size[%d]" % i)
            self._bsca.define_constant(constant)


class OrthogonalLattice(Lattice):
    supported_dimensions = list(range(1, 100))

    def index_to_coord_code(self, index_name, coord_prefix):
        self._define_constants_once()

        def wrap_format(s):
            return s.format(x=coord_prefix, i=i,
                            index=index_name, w=self.width_prefix)

        for i in range(self.dimensions):
            if i == 0:
                code = wrap_format("int _{index} = {index};\n")
                index_name = "_" + index_name
            if i < self.dimensions - 1:
                code += wrap_format("int {x}{i} = {index} % {w}{i};\n")
                code += wrap_format("{index} /= {w}{i};\n")
            else:
                code += wrap_format("int {x}{i} = {index};\n")
        return code

    def index_to_coord(self, idx, bsca):
        coord = []
        for i in range(bsca.topology.dimensions):
            if i < self.dimensions - 1:
                x_i = idx % bsca.size[i]
                idx //= bsca.size[i]
            else:
                x_i = idx
            coord.append(x_i)
        return tuple(coord)

    def coord_to_index_code(self, coord_prefix):
        self._define_constants_once()

        summands = []
        for i in range(self.dimensions):
            summand = coord_prefix + str(i)
            for j in range(i):
                summand = self.width_prefix + str(j) + " * " + summand
            summands.append(summand)
        return " + ".join(summands)

    def is_off_board_code(self, coord_prefix):
        self._define_constants_once()

        conditions = []
        for i in range(self.dimensions):
            condition = "{x}{i} < 0 || {x}{i} >= {w}{i}".format(
                x=coord_prefix, i=i, w=self.width_prefix
            )
            conditions.append(condition)
        return " || ".join(conditions)

@@ -1,258 +1,1068 @@
-from xentica.core.topology.mixins import DimensionsMixin%0A%0Afrom xentica.core.mixins import BscaDetectorMixin%0Afrom xentica.core.variables import Constant%0A%0A%0Aclass Lattice(DimensionsMixin, BscaDetectorMixin):%0A    %22%22%22%0A    Base class for all lattices.%0A%0A    %22%22%22
+%22%22%22%0AThe collection of classes describing different lattice topologies.%0A%0AAll classes there are intended to be used inside %60%60Topology%60%60 for%0A%60%60lattice%60%60 class variable definition. They are also available via%0A%60%60xentica.core%60%60 shortcut. The example::%0A%0A    from xentica.core import CellularAutomaton, OrthogonalLattice%0A%0A    class MyCA(CellularAutomaton)%0A        class Topology:%0A            lattice = OrthogonalLattice()%0A            # ...%0A        # ...%0A%0A%22%22%22%0Afrom xentica.core.topology.mixins import DimensionsMixin%0A%0Afrom xentica.core.mixins import BscaDetectorMixin%0Afrom xentica.core.variables import Constant%0A%0A%0Aclass Lattice(DimensionsMixin, BscaDetectorMixin):%0A    %22%22%22%0A    Base class for all lattices.%0A%0A    For correct behavior, lattice classes should be inherited from%0A    this class. You should also implement the following functions:%0A%0A    - %60%60index_to_coord_code%60%60%0A%0A    - %60%60index_to_coord%60%60%0A%0A    - %60%60coord_to_index_code%60%60%0A%0A    - %60%60is_off_board_code%60%60%0A%0A    See the detailed description below.%0A%0A    %22%22%22%0A%0A    #: The prefix to be used in C code for field size constants.
 %0A   
@@ -1121,16 +1121,69 @@
 (self):%0A
+        %22%22%22Define field size conctants in C code.%22%22%22%0A
         
@@ -1428,16 +1428,181 @@
 ttice):%0A
+    %22%22%22%0A    N-dimensional orthogonal lattice.%0A%0A    Points are all possible positive integer coordinates.%0A%0A    %22%22%22%0A%0A    #: Overridden value for supported dimensions.%0A
     supp
@@ -1694,32 +1694,94 @@
  coord_prefix):%0A
+        %22%22%22Implement coord obtaining by cell's index in C.%22%22%22%0A
         self._de
@@ -2437,16 +2437,83 @@
  bsca):%0A
+        %22%22%22Implement coord obtaining by cell's index in Python.%22%22%22%0A
         
@@ -2835,32 +2835,94 @@
  coord_prefix):%0A
+        %22%22%22Implement cell's index obtaining by coord in C.%22%22%22%0A
         self._de
@@ -3266,32 +3266,87 @@
  coord_prefix):%0A
+        %22%22%22Implement off board cell obtaining in C.%22%22%22%0A
         self._de

Add docstrings for core.topologe.lattice module (#23, #27)