from builtins import str, super

from ..constant import *
from ..exception import *
from ..session import Style
from ..tecutil import color_spec, inherited_property, lock_attributes, sv, Index

class Scatter(Style):
    """Plot-local scatter style settings.

    This class controls the style of drawn scatter points on a specific plot.
    """
    def __init__(self, plot):
        self.plot = plot
        super().__init__(sv.GLOBALSCATTER, uniqueid=self.plot.frame.uid)

    @property
    def variable_index(self):
        """Zero-based index of the `Variable` used for size of scatter symbols.

        .. code-block:: python

            >>> plot.scatter.variable_index = dataset.variable('P').index
            >>> plot.fieldmap(0).scatter.size_by_variable = True

        The `Dataset` attached to this contour group's `Frame` is used, and
        the variable itself can be obtained through it::

            >>> scatter = plot.scatter
            >>> scatter_var = dataset.variable(scatter.variable_index)
            >>> scatter_var.index == scatter.variable_index
            True
        """
        return self._get_style(Index, sv.VAR)

    @variable_index.setter
    def variable_index(self, index):
        self._set_style(Index(index), sv.VAR)

    @property
    def variable(self):
        """The `Variable` to be used when sizing scatter symbols.

        The variable must belong to the `Dataset` attached to the `Frame`
        that holds this `ContourGroup`. Example usage::

            >>> plot.scatter.variable = dataset.variable('P')
            >>> plot.fieldmap(0).scatter.size_by_variable = True
        """
        return self.plot.frame.dataset.variable(self.variable_index)

    @variable.setter
    def variable(self, variable):
        self.variable_index = variable.index


@lock_attributes
class Symbol(object):
    def __init__(self, parent, svarg=sv.SYMBOLSHAPE):
        self.parent = parent
        self._sv = [svarg]

    def _get_style(self, rettype, *svargs):
        return self.parent._get_style(rettype, *(self._sv + list(svargs)))
    def _set_style(self, value, *svargs):
        self.parent._set_style(value, *(self._sv + list(svargs)))

    @property
    def _symbol_type(self):
        if self._get_style(bool, sv.ISASCII):
            return SymbolType.Text
        else:
            return SymbolType.Geometry

    @_symbol_type.setter
    def _symbol_type(self, value):
        value = SymbolType(value)
        if value is SymbolType.Text:
            self._set_style(True, sv.ISASCII)
        else:
            self._set_style(False, sv.ISASCII)


class TextSymbol(Symbol):
    """Text character for linemap symbols.

    Only a single character can be used.

    .. code-block:: python
        :emphasize-lines: 23,28

        from os import path
        import tecplot as tp
        from tecplot.constant import PlotType, Color, SymbolType, FillMode

        examples_dir = tp.session.tecplot_examples_directory()
        infile = path.join(examples_dir, 'SimpleData', 'Rainfall.dat')
        dataset = tp.data.load_tecplot(infile)

        frame = tp.active_frame()
        frame.plot_type = PlotType.XYLine
        plot = frame.plot()
        plot.show_symbols = True

        cols = [Color.DeepRed, Color.Blue, Color.Fern]
        chars = ['S','D','M']

        for lmap,color,character in zip(plot.linemaps(), cols, chars):
            lmap.show = True
            lmap.line.color = color

            syms = lmap.symbols
            syms.show = True
            syms.symbol_type = SymbolType.Text
            syms.size = 2.5
            syms.color = Color.White
            syms.fill_mode = FillMode.UseSpecificColor
            syms.fill_color = color
            syms.symbol().text = character

        plot.view.fit()

        # save image to file
        tp.export.save_png('linemap_symbols_text.png', 600, supersample=3)

    .. figure:: /_static/images/linemap_symbols_text.png
        :width: 300px
        :figwidth: 300px
    """
    def __init__(self, parent, svarg=sv.SYMBOLSHAPE):
        super().__init__(parent, svarg)
        self._sv += [sv.ASCIISHAPE]

    @property
    def text(self):
        """The ASCII character to use as the symbol to show

        .. note:: This is limited to a single character.

        Example usage::

            >>> from tecplot.constant import SymbolType
            >>> symbols = plot.linemap(0).symbols
            >>> symbols.symbol_type = SymbolType.Text
            >>> symbols.symbol().text = 'X'
        """
        return self._get_style(str, sv.ASCIICHAR)

    @text.setter
    def text(self, value):
        self._set_style(str(value)[0], sv.ASCIICHAR)

    @property
    def use_base_font(self):
        """Use the base typeface when rendering text-based symbols.

        :type: `boolean <bool>`

        When `False`, the ``font_override`` attribute takes effect::

            >>> from tecplot.constant import SymbolType, Font
            >>> symbols = plot.linemap(0).symbols
            >>> symbols.symbol_type = SymbolType.Text
            >>> symbols.symbol().use_base_font = False
            >>> symbols.symbol().font_override = Font.Greek
        """
        return self._get_style(bool, sv.USEBASEFONT)

    @use_base_font.setter
    def use_base_font(self, value):
        self._set_style(bool(value), sv.USEBASEFONT)

    @property
    def font_override(self):
        """Typeface to use when rendering text-based symbols.

        :type: `constant.Font`

        Possible values: `constant.Font.Greek`, `constant.Font.Math` or `constant.Font.UserDefined`.

        The ``use_base_font`` attribute must be set to `False`::

            >>> from tecplot.constant import SymbolType, Font
            >>> symbols = plot.linemap(0).symbols
            >>> symbols.symbol_type = SymbolType.Text
            >>> symbols.symbol().use_base_font = False
            >>> symbols.symbol().font_override = Font.Greek
        """
        return self._get_style(Font, sv.FONTOVERRIDE)

    @font_override.setter
    def font_override(self, value):
        if __debug__:
            valid_typefaces = [Font.Greek, Font.Math, Font.UserDefined]
            if value not in valid_typefaces:
                msg = 'font_override must be one of: '
                msg += ' '.join(str(x) for x in valid_typefaces)
                raise TecplotLogicError(msg)
        self._set_style(Font(value), sv.FONTOVERRIDE)


class TextScatterSymbol(TextSymbol):
    """Text character for scatter plots.

    Only a single character can be used.

    .. code-block:: python
        :emphasize-lines: 14,20-25

        from os import path
        import tecplot as tp
        from tecplot.constant import (Color, PlotType, PointsToPlot, SymbolType,
                                          GeomShape, FillMode)

        examples_dir = tp.session.tecplot_examples_directory()
        infile = path.join(examples_dir, 'SimpleData', 'HeatExchanger.plt')
        dataset = tp.data.load_tecplot(infile)

        frame = tp.active_frame()
        frame.plot_type = PlotType.Cartesian2D
        plot = frame.plot()
        plot.show_shade = True
        plot.show_scatter = True

        for i,fmap in enumerate(plot.fieldmaps()):
            fmap.points.points_to_plot = PointsToPlot.SurfaceCellCenters
            fmap.points.step = (4,4)

            fmap.scatter.color = Color((i%4)+13)
            fmap.scatter.fill_mode = FillMode.UseSpecificColor
            fmap.scatter.fill_color = Color.Yellow
            fmap.scatter.size = 3
            fmap.scatter.symbol_type = SymbolType.Text
            fmap.scatter.symbol().text = hex(i)[-1]

            fmap.shade.color = Color.LightBlue


        tp.export.save_png('fieldmap_scatter_text.png', 600, supersample=3)

    .. figure:: /_static/images/fieldmap_scatter_text.png
        :width: 300px
        :figwidth: 300px
    """

    @inherited_property(TextSymbol)
    def text(self):
        """The ASCII character to use as the symbol to show

        .. note:: This is limited to a single character.

        Example usage::

            >>> from tecplot.constant import SymbolType
            >>> scatter = plot.fieldmap(0).scatter
            >>> scatter.symbol_type = SymbolType.Text
            >>> scatter.symbol().text = 'X'
        """

    @inherited_property(TextSymbol)
    def use_base_font(self):
        """Use the base typeface when rendering text-based scatter.

        :type: `boolean <bool>`

        When `False`, the ``font_override`` attribute takes effect::

            >>> from tecplot.constant import SymbolType, Font
            >>> scatter = plot.fieldmap(0).scatter
            >>> scatter.symbol_type = SymbolType.Text
            >>> scatter.symbol().use_base_font = False
            >>> scatter.symbol().font_override = Font.Greek
        """

    @inherited_property(TextSymbol)
    def font_override(self):
        """Typeface to use when rendering text-based scatter.

        :type: `constant.Font`

        Possible values: `constant.Font.Greek`, `constant.Font.Math` or `constant.Font.UserDefined`.

        The ``use_base_font`` attribute must be set to `False`::

            >>> from tecplot.constant import SymbolType, Font
            >>> scatter = plot.fieldmap(0).scatter
            >>> scatter.symbol_type = SymbolType.Text
            >>> scatter.symbol().use_base_font = False
            >>> scatter.symbol().font_override = Font.Math
        """


class GeometrySymbol(Symbol):
    """Geometric shape for linemap symbols.

    .. code-block:: python
        :emphasize-lines: 28-29

        from os import path
        import tecplot as tp
        from tecplot.constant import (PlotType, Color, GeomShape, SymbolType,
                                      FillMode)

        examples_dir = tp.session.tecplot_examples_directory()
        infile = path.join(examples_dir, 'SimpleData', 'Rainfall.dat')
        dataset = tp.data.load_tecplot(infile)

        frame = tp.active_frame()
        frame.plot_type = PlotType.XYLine
        plot = frame.plot()
        plot.show_symbols = True

        cols = [Color.DeepRed, Color.Blue, Color.Fern]
        shapes = [GeomShape.Square, GeomShape.Circle, GeomShape.Del]

        for lmap,color,shape in zip(plot.linemaps(), cols, shapes):
            lmap.show = True
            lmap.line.color = color

            symbols = lmap.symbols
            symbols.show = True
            symbols.size = 4.5
            symbols.color = color
            symbols.fill_mode = FillMode.UseSpecificColor
            symbols.fill_color = color
            symbols.symbol_type = SymbolType.Geometry
            symbols.symbol().shape = shape

        plot.view.fit()

        # save image to file
        tp.export.save_png('linemap_symbols_geometry.png', 600, supersample=3)

    .. figure:: /_static/images/linemap_symbols_geometry.png
        :width: 300px
        :figwidth: 300px
    """

    @property
    def shape(self):
        """Geometric shape to use when plotting linemap symbols.

        :type: `GeomShape`

        Possible values: `Square <GeomShape.Square>`, `Del`, `Grad`, `RTri`,
        `LTri`, `Diamond`, `Circle <GeomShape.Circle>`, `Cube`, `Sphere`,
        `Octahedron`, `Point <GeomShape.Point>`.

        Example usage::

            >>> from tecplot.constant import SymbolType, GeomShape
            >>> symbols = plot.linemap(0).symbols
            >>> symbols.symbol_type = SymbolType.Geometry
            >>> symbols.symbol().shape = GeomShape.Diamond
        """
        return self._get_style(GeomShape, sv.GEOMSHAPE)

    @shape.setter
    def shape(self, value):
        self._set_style(GeomShape(value), sv.GEOMSHAPE)


class GeometryScatterSymbol(GeometrySymbol):
    """Geometric shape for scatter plots.

    .. code-block:: python
        :emphasize-lines: 13,21-28

        from os import path
        import tecplot as tp
        from tecplot.constant import (Color, PlotType, PointsToPlot, SymbolType,
                                      GeomShape, FillMode)

        examples_dir = tp.session.tecplot_examples_directory()
        infile = path.join(examples_dir, 'SimpleData', 'HeatExchanger.plt')
        dataset = tp.data.load_tecplot(infile)

        frame = tp.active_frame()
        frame.plot_type = PlotType.Cartesian2D
        plot = frame.plot()
        plot.show_scatter = True


        for i,fmap in enumerate(plot.fieldmaps()):
            points = fmap.points
            points.points_to_plot = PointsToPlot.SurfaceCellCenters
            points.step = (2,2)

            scatter = fmap.scatter
            scatter.color = Color(i)
            scatter.fill_mode = FillMode.UseSpecificColor
            scatter.fill_color = Color(i+plot.num_fieldmaps)
            scatter.size = 2
            scatter.line_thickness = 0.5
            scatter.symbol_type = SymbolType.Geometry
            scatter.symbol().shape = GeomShape(i%7)

        tp.export.save_png('fieldmap_scatter_geometry.png', 600, supersample=3)

    .. figure:: /_static/images/fieldmap_scatter_geometry.png
        :width: 300px
        :figwidth: 300px
    """

    @inherited_property(GeometrySymbol)
    def shape(self):
        """Geometric shape to use when plotting scatter points.

        :type: `GeomShape`

        Possible values: `Square <GeomShape.Square>`, `Del`, `Grad`, `RTri`,
        `LTri`, `Diamond`, `Circle <GeomShape.Circle>`, `Cube`, `Sphere`,
        `Octahedron`, `Point <GeomShape.Point>`.

        Example usage::

            >>> from tecplot.constant import SymbolType, GeomShape
            >>> scatter = plot.fieldmap(0).scatter
            >>> scatter.symbol_type = SymbolType.Geometry
            >>> scatter.symbol().shape = GeomShape.Diamond
        """
