#
# Copyright (C) 2000-2005 by Yasushi Saito (yasushi.saito@gmail.com)
# 
# Jockey is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any
# later version.
#
# Jockey 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 General Public License
# for more details.
#
from . import chart_object
from . import fill_style
from . import font
from . import legend_doc
from . import line_style
from . import theme
from . import tick_mark
from . import pychart_util
from .pychart_types import *


class Entry(chart_object.T):
    keys = {"line_len": (UnitType, None,
                         "Length of the sample line for line plots. If omitted, it is set to be theme.default_font_size"),
            "rect_size": (UnitType, None,
                          "Size of the sample 'blob' for bar range charts. If omitted, it is set to be 70% of theme.default_size"),
            "tick_mark": (tick_mark.T, None, ""),
            "line_style": (line_style.T, None, ""),
            "fill_style": (fill_style.T, None, ""),
            "label": (StringType, "???", ""),
            }
    __doc__ = legend_doc.doc_entry

    ##AUTOMATICALLY GENERATED

    ##END AUTOMATICALLY GENERATED

    def label_width(self):
        return font.text_width(" " + self.label)

    def get_line_len(self):
        return self.line_len or theme.default_font_size

    def get_rect_size(self):
        return self.rect_size or theme.default_font_size * 7 / 10.0

    def sample_width(self):
        w = 0
        if self.fill_style != None:
            w += self.get_line_len()
        elif self.line_style != None:
            w += self.get_line_len()
        elif self.tick_mark != None:
            w += self.tick_mark.size
        return w

    def height(self):
        h = font.text_height(self.label)[0]
        return h

    def draw(self, ar, can, x_tick, x_label, y):
        """Draw a legend entry. X_TICK and X_LABEL are the X location \
        (in points) of where the sample and label are drawn."""

        rect_size = self.get_rect_size()
        line_len = self.get_line_len()

        nr_lines = len(self.label.split("\n"))
        text_height = font.text_height(self.label)[0]
        line_height = text_height / float(nr_lines)
        y_center = y + text_height - line_height / 1.5

        if self.fill_style != None:
            can.rectangle(self.line_style, self.fill_style,
                          x_tick, y_center - rect_size / 2.0,
                          x_tick + rect_size,
                          y_center + rect_size / 2.0)
        elif self.line_style != None:
            can.line(self.line_style, x_tick, y_center,
                     x_tick + line_len, y_center)
            if self.tick_mark != None:
                self.tick_mark.draw(can, x_tick + line_len / 2.0, y_center)
        elif self.tick_mark != None:
            self.tick_mark.draw(can, x_tick, y_center)

        can.show(x_label, y, self.label)


__doc__ = """Legend is a rectangular box drawn in a chart to describe
the meanings of plots. The contents of a legend box is extracted from
plots' "label", "line-style", and "tick-mark" attributes.

This module exports a single class, legend.T.  Legend.T is a part of
an area.T object, and is drawn automatically when area.draw() method
is called. """


class T(chart_object.T):
    __doc__ = legend_doc.doc
    keys = {
        "inter_row_sep": (UnitType, 0,
                          "Space between each row in the legend."),
        "inter_col_sep": (UnitType, 0,
                          "Space between each column in the legend."),
        "frame_line_style": (line_style.T, line_style.default, ""),
        "frame_fill_style": (fill_style.T, fill_style.white, ""),
        "top_fudge": (UnitType, 0,
                      "Amount of space above the first line."),
        "bottom_fudge": (UnitType, 3,
                         "Amount of space below the last line."),
        "left_fudge": (UnitType, 5,
                       "Amount of space left of the legend."),
        "right_fudge": (UnitType, 5,
                        "Amount of space right of the legend."),
        "loc": (CoordType, None,
                """Bottom-left corner of the legend.
                The default location of a legend is the bottom-right end of the chart."""),
        "shadow": (ShadowType, None, pychart_util.shadow_desc),
        "nr_rows": (IntType, 9999,
                    "Number of rows in the legend. If the number of plots in a chart is larger than nr_rows, multiple columns are created in the legend."),

    }

    ##AUTOMATICALLY GENERATED

    ##END AUTOMATICALLY GENERATED
    def draw(self, ar, entries, can):
        if not self.loc:
            x = ar.loc[0] + ar.size[0] * 1.1
            y = ar.loc[1]
        else:
            x = self.loc[0]
            y = self.loc[1]

        nr_rows = min(self.nr_rows, len(entries))
        nr_cols = (len(entries) - 1) / nr_rows + 1

        ymin = y
        max_label_width = [0] * nr_cols
        max_sample_width = [0] * nr_cols
        heights = [0] * nr_rows

        for i in range(len(entries)):
            l = entries[i]
            (col, row) = divmod(i, nr_rows)
            max_label_width[col] = max(l.label_width(), max_label_width[col])
            max_sample_width[col] = max(l.sample_width(), max_sample_width[col])
            heights[row] = max(l.height(), heights[row])

        for h in heights:
            y += h
        y += self.inter_row_sep * (nr_rows - 1)
        ymax = y

        tot_width = self.inter_col_sep * (nr_cols - 1)
        for w in max_label_width:
            tot_width += w
        for w in max_sample_width:
            tot_width += w

        can.rectangle(self.frame_line_style, self.frame_fill_style,
                      x - self.left_fudge,
                      ymin - self.bottom_fudge,
                      x + tot_width + self.right_fudge,
                      ymax + self.top_fudge,
                      self.shadow)

        for col in range(nr_cols):
            this_y = y
            this_x = x
            for row in range(nr_rows):
                idx = col * nr_rows + row
                if idx >= len(entries):
                    continue
                this_y -= heights[row]
                l = entries[idx]
                if row != 0:
                    this_y -= self.inter_row_sep

                l.draw(ar, can, this_x, this_x + max_sample_width[col], this_y)
            x += max_label_width[col] + max_sample_width[col] + self.inter_col_sep
