# -*- coding: utf-8 -*-
# This file is part of pygal
#
# A python svg graph plotting library
# Copyright © 2012-2025 Kozea
#
# This library is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# This library is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>.
"""pygal public api functions"""

import base64
import io

from pygal._compat import is_list_like
from pygal.graph.base import BaseGraph


class PublicApi(BaseGraph):
    """Chart public functions"""

    def add(self, title, values, **kwargs):
        """Add a serie to this graph, compat api"""
        if not is_list_like(values) and not isinstance(values, dict):
            values = [values]
        kwargs['title'] = title
        self.raw_series.append((values, kwargs))
        return self

    def __call__(self, *args, **kwargs):
        """Call api: chart(1, 2, 3, title='T')"""
        self.raw_series.append((args, kwargs))
        return self

    def add_xml_filter(self, callback):
        """Add an xml filter for in tree post processing"""
        self.xml_filters.append(callback)
        return self

    def render(self, is_unicode=False, **kwargs):
        """Render the graph, and return the svg string"""
        self.setup(**kwargs)
        svg = self.svg.render(
            is_unicode=is_unicode, pretty_print=self.pretty_print
        )
        self.teardown()
        return svg

    def render_tree(self, **kwargs):
        """Render the graph, and return (l)xml etree"""
        self.setup(**kwargs)
        svg = self.svg.root
        for f in self.xml_filters:
            svg = f(svg)
        self.teardown()
        return svg

    def render_table(self, **kwargs):
        """Render the data as a html table"""
        # Import here to avoid lxml import
        try:
            from pygal.table import Table
        except ImportError:
            raise ImportError('You must install lxml to use render table')
        return Table(self).render(**kwargs)

    def render_pyquery(self, **kwargs):
        """Render the graph, and return a pyquery wrapped tree"""
        from pyquery import PyQuery as pq
        return pq(self.render(**kwargs), parser='html')

    def render_in_browser(self, **kwargs):
        """Render the graph, open it in your browser with black magic"""
        try:
            from lxml.html import open_in_browser
        except ImportError:
            raise ImportError('You must install lxml to use render in browser')
        kwargs.setdefault('force_uri_protocol', 'https')
        open_in_browser(self.render_tree(**kwargs), encoding='utf-8')

    def render_response(self, **kwargs):
        """Render the graph, and return a Flask response"""
        from flask import Response
        return Response(self.render(**kwargs), mimetype='image/svg+xml')

    def render_django_response(self, **kwargs):
        """Render the graph, and return a Django response"""
        from django.http import HttpResponse
        return HttpResponse(
            self.render(**kwargs), content_type='image/svg+xml'
        )

    def render_data_uri(self, **kwargs):
        """Output a base 64 encoded data uri"""
        # Force protocol as data uri have none
        kwargs.setdefault('force_uri_protocol', 'https')
        return "data:image/svg+xml;charset=utf-8;base64,%s" % (
            base64.b64encode(self.render(**kwargs)
                             ).decode('utf-8').replace('\n', '')
        )

    def render_to_file(self, filename, **kwargs):
        """Render the graph, and write it to filename"""
        with io.open(filename, 'w', encoding='utf-8') as f:
            f.write(self.render(is_unicode=True, **kwargs))

    def render_to_png(self, filename=None, dpi=72, **kwargs):
        """Render the graph, convert it to png and write it to filename"""
        import cairosvg
        return cairosvg.svg2png(
            bytestring=self.render(**kwargs), write_to=filename, dpi=dpi
        )

    def render_sparktext(self, relative_to=None):
        """Make a mini text sparkline from chart"""
        bars = '▁▂▃▄▅▆▇█'
        if len(self.raw_series) == 0:
            return ''
        values = list(self.raw_series[0][0])
        if len(values) == 0:
            return ''

        chart = ''
        values = list(map(lambda x: max(x, 0), values))

        vmax = max(values)
        if relative_to is None:
            relative_to = min(values)

        if (vmax - relative_to) == 0:
            chart = bars[0] * len(values)
            return chart

        divisions = len(bars) - 1
        for value in values:
            chart += bars[int(
                divisions * (value - relative_to) / (vmax - relative_to)
            )]
        return chart

    def render_sparkline(self, **kwargs):
        """Render a sparkline"""
        spark_options = dict(
            width=200,
            height=50,
            show_dots=False,
            show_legend=False,
            show_x_labels=False,
            show_y_labels=False,
            spacing=0,
            margin=5,
            min_scale=1,
            max_scale=2,
            explicit_size=True,
            no_data_text='',
            js=(),
            classes=(Ellipsis, 'pygal-sparkline'),
        )
        spark_options.update(kwargs)
        return self.render(**spark_options)
