""" PlotBase is a base class for various Graphs plots

    The DIRAC Graphs package is derived from the GraphTool plotting package of the
    CMS/Phedex Project by ... <to be added>
"""

from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
from DIRAC.Core.Utilities.Graphs.Palette import Palette
from DIRAC.Core.Utilities.Graphs.GraphData import GraphData
from DIRAC.Core.Utilities.Graphs.GraphUtilities import pixelToPoint, evalPrefs
from matplotlib.axes import Axes
from matplotlib.pylab import setp

__RCSID__ = "$Id$"


class PlotBase(object):

  def __init__(self, data=None, axes=None, *aw, **kw):

    self.ax_contain = axes
    self.canvas = None
    self.figure = None
    if self.ax_contain:
      self.figure = self.ax_contain.get_figure()
      self.canvas = self.figure.canvas
      self.dpi = self.ax_contain.figure.get_dpi()
      self.ax_contain.set_axis_off()
    self.prefs = evalPrefs(*aw, **kw)
    self.coords = {}
    self.palette = Palette()
    if isinstance(data, dict):
      self.gdata = GraphData(data)
    elif isinstance(data, object) and data.__class__ == GraphData:
      self.gdata = data

  def dumpPrefs(self):

    for key in self.prefs:
      print(key.rjust(20), ':', str(self.prefs[key]).ljust(40))

  def setAxes(self, axes):

    self.ax_contain = axes
    self.ax_contain.set_axis_off()
    self.figure = self.ax_contain.get_figure()
    self.canvas = self.figure.canvas
    self.dpi = self.ax_contain.figure.get_dpi()

  def draw(self):

    prefs = self.prefs
    dpi = self.ax_contain.figure.get_dpi()

    # Update palette
    palette = prefs.get('colors', {})
    if palette:
      self.palette.addPalette(palette)

    xlabel = prefs.get('xlabel', '')
    ylabel = prefs.get('ylabel', '')
    xticks_flag = prefs.get('xticks', True)
    yticks_flag = prefs.get('yticks', True)

    text_size = prefs['text_size']
    text_padding = prefs['text_padding']

    label_text_size = prefs.get('label_text_size', text_size)
    label_text_size_point = pixelToPoint(label_text_size, dpi)
    tick_text_size = prefs.get('tick_text_size', text_size)
    tick_text_size_point = pixelToPoint(tick_text_size, dpi)

    ytick_length = prefs.get('ytick_length', 7 * tick_text_size)

    plot_title = prefs.get('plot_title', '')
    if not plot_title or plot_title == 'NoTitle':
      plot_title_size = 0
      plot_title_padding = 0
    else:
      plot_title_size = prefs.get('plot_title_size', text_size)
      plot_title_padding = prefs.get('plot_text_padding', text_padding)
    plot_title_size_point = pixelToPoint(plot_title_size, dpi)

    stats_flag = prefs.get('statistics_line', False)
    stats_line = ''
    stats_line_space = 0.
    if stats_flag:
      stats_line = self.gdata.getStatString()
      stats_line_size = label_text_size
      stats_line_padding = label_text_size * 2.
      stats_line_space = stats_line_size + stats_line_padding

    plot_padding = prefs['plot_padding']
    plot_left_padding = prefs.get('plot_left_padding', plot_padding)
    plot_right_padding = prefs.get('plot_right_padding', 0)
    plot_bottom_padding = prefs.get('plot_bottom_padding', plot_padding)
    plot_top_padding = prefs.get('plot_top_padding', 0)
    frame_flag = prefs['frame']

    # Create plot axes, and set properties
    left, bottom, width, height = self.ax_contain.get_window_extent().bounds
    l, b, f_width, f_height = self.figure.get_window_extent().bounds

    # Space needed for labels and ticks
    x_label_space = 0
    if xticks_flag:
      x_label_space += tick_text_size * 1.5
    if xlabel:
      x_label_space += label_text_size * 1.5
    y_label_space = 0
    if yticks_flag:
      y_label_space += ytick_length
    if ylabel:
      y_label_space += label_text_size * 1.5

    ax_plot_rect = (float(plot_left_padding + left + y_label_space) / f_width,
                    float(plot_bottom_padding + bottom + x_label_space + stats_line_space) / f_height,
                    float(width - plot_left_padding - plot_right_padding - y_label_space) / f_width,
                    float(height - plot_bottom_padding - plot_top_padding - x_label_space -
                          plot_title_size - 2 * plot_title_padding - stats_line_space) / f_height)
    ax = Axes(self.figure, ax_plot_rect)
    if prefs['square_axis']:
      l, b, a_width, a_height = ax.get_window_extent().bounds
      delta = abs(a_height - a_width)
      if a_height > a_width:
        a_height = a_width
        ax_plot_rect = (
            float(
                plot_left_padding +
                left) /
            f_width,
            float(
                plot_bottom_padding +
                bottom +
                delta /
                2.) /
            f_height,
            float(
                width -
                plot_left_padding -
                plot_right_padding) /
            f_width,
            float(
                height -
                plot_bottom_padding -
                plot_title_size -
                2 *
                plot_title_padding -
                delta) /
            f_height)
      else:
        a_width = a_height
        ax_plot_rect = (float(plot_left_padding + left + delta / 2.) / f_width,
                        float(plot_bottom_padding + bottom) / f_height,
                        float(width - plot_left_padding - delta) / f_width,
                        float(height - plot_bottom_padding - plot_title_size - 2 * plot_title_padding) / f_height)
      ax.set_position(ax_plot_rect)

    self.figure.add_axes(ax)
    self.ax = ax
    frame = ax.patch
    frame.set_fill(False)

    if frame_flag.lower() == 'off':
      self.ax.set_axis_off()
      self.log_xaxis = False
      self.log_yaxis = False
    else:
      # If requested, make x/y axis logarithmic
      if prefs.get('log_xaxis', 'False').find('r') >= 0:
        ax.semilogx()
        self.log_xaxis = True
      else:
        self.log_xaxis = False
      if prefs.get('log_yaxis', 'False').find('r') >= 0:
        ax.semilogy()
        self.log_yaxis = True
      else:
        self.log_yaxis = False

      if xticks_flag:
        setp(ax.get_xticklabels(), family=prefs['font_family'])
        setp(ax.get_xticklabels(), fontname=prefs['font'])
        setp(ax.get_xticklabels(), size=tick_text_size_point)
      else:
        setp(ax.get_xticklabels(), size=0)

      if yticks_flag:
        setp(ax.get_yticklabels(), family=prefs['font_family'])
        setp(ax.get_yticklabels(), fontname=prefs['font'])
        setp(ax.get_yticklabels(), size=tick_text_size_point)
      else:
        setp(ax.get_yticklabels(), size=0)

      setp(ax.get_xticklines(), markeredgewidth=pixelToPoint(0.5, dpi))
      setp(ax.get_xticklines(), markersize=pixelToPoint(text_size / 2., dpi))
      setp(ax.get_yticklines(), markeredgewidth=pixelToPoint(0.5, dpi))
      setp(ax.get_yticklines(), markersize=pixelToPoint(text_size / 2., dpi))
      setp(ax.get_xticklines(), zorder=4.0)

      line_width = prefs.get('line_width', 1.0)
      frame_line_width = prefs.get('frame_line_width', line_width)
      grid_line_width = prefs.get('grid_line_width', 0.1)
      plot_line_width = prefs.get('plot_line_width', 0.1)

      setp(ax.patch, linewidth=pixelToPoint(plot_line_width, dpi))
      # setp( ax.spines, linewidth=pixelToPoint(frame_line_width,dpi) )
      # setp( ax.axvline(), linewidth=pixelToPoint(1.0,dpi) )
      axis_grid_flag = prefs.get('plot_axis_grid', True)
      if axis_grid_flag:
        ax.grid(True, color='#555555', linewidth=pixelToPoint(grid_line_width, dpi))

      plot_axis_flag = prefs.get('plot_axis', True)
      if plot_axis_flag:
        # Set labels
        if xlabel:
          t = ax.set_xlabel(xlabel)
          t.set_fontname(prefs['font'])
          t.set_fontsize(label_text_size)

        if ylabel:
          t = ax.set_ylabel(ylabel)
          t.set_fontname(prefs['font'])
          t.set_fontsize(label_text_size)
      else:
        self.ax.set_axis_off()

    # Create a plot title, if necessary
    if plot_title:
      self.ax.title = self.ax.text(0.5,
                                   1. + float(plot_title_padding) / height,
                                   plot_title,
                                   verticalalignment='bottom',
                                   horizontalalignment='center',
                                   size=pixelToPoint(plot_title_size, dpi),
                                   family=prefs['font_family'],
                                   fontname=prefs['font'])
      self.ax.title.set_transform(self.ax.transAxes)
      self.ax.title.set_fontname(prefs['font'])
    if stats_line:
      self.ax.stats = self.ax.text(0.5, (-stats_line_space) / height,
                                   stats_line,
                                   verticalalignment='top',
                                   horizontalalignment='center',
                                   size=pixelToPoint(stats_line_size, dpi))

      self.ax.stats.set_transform(self.ax.transAxes)
