# -*- coding: utf-8 -*-
#------------------------------------------------------------------------------
# file: $Id$
# auth: Philip J Grabner <grabner@cadit.com>
# date: 2013/09/17
# copy: (C) Copyright 2013 Cadit Health Inc., All Rights Reserved.
#------------------------------------------------------------------------------

import sys
from pyramid.settings import aslist
from pyramid.path import AssetResolver, DottedNameResolver
from docutils import nodes, core
from docutils.parsers.rst import Directive, directives
from docutils.transforms import misc
from six.moves import urllib

from .util import resolve, runFilters

#------------------------------------------------------------------------------
class IdAttribute(misc.Transform):

  # copy of docutils.transforms.misc.ClassAttribute and adjusted
  # for "id" attribute

  """
  Move the "id" attribute specified in the "pending" node into the
  immediately following non-comment element.
  """
  default_priority = 210

  def apply(self):
    pending = self.startnode
    parent = pending.parent
    child = pending
    while parent:
      # Check for appropriate following siblings:
      for index in range(parent.index(child) + 1, len(parent)):
        element = parent[index]
        if (isinstance(element, nodes.Invisible) or
          isinstance(element, nodes.system_message)):
          continue
        # note: *replacing*, not appending, the ids since the ids
        # generated by docutils are not very useful...
        element['ids'] = pending.details['id']
        pending.parent.remove(pending)
        return
      else:
        # At end of section or container; apply to sibling
        child = parent
        parent = parent.parent
    error = self.document.reporter.error(
      'No suitable element following "%s" directive'
      % pending.details['directive'],
      nodes.literal_block(pending.rawsource, pending.rawsource),
      line=pending.line)
    pending.replace_self(error)

#------------------------------------------------------------------------------
class Id(Directive):

  # copy of docutils.parsers.rst.misc.Class and adjusted
  # for "id" attribute

  """
  Set a "id" attribute on the directive content or the next element.
  When applied to the next element, a "pending" element is inserted, and a
  transform does the work later.
  """

  required_arguments = 1
  optional_arguments = 0
  final_argument_whitespace = True
  has_content = True

  def run(self):
    try:
      #class_value = directives.class_option(self.arguments[0])
      class_value = [directives.unchanged_required(self.arguments[0])]
    except ValueError:
      raise self.error(
        'Invalid id attribute value for "%s" directive: "%s".'
        % (self.name, self.arguments[0]))
    node_list = []
    if self.content:
      container = nodes.Element()
      self.state.nested_parse(self.content, self.content_offset,
                  container)
      for node in container:
        node['classes'].extend(class_value)
      node_list.extend(container.children)
    else:
      pending = nodes.pending(
        IdAttribute,
        {'id': class_value, 'directive': self.name},
        self.block_text)
      self.state_machine.document.note_pending(pending)
      node_list.append(pending)
    return node_list

#------------------------------------------------------------------------------
# TODO: when https://sourceforge.net/p/docutils/feature-requests/38/ is
#       implemented, move this to a per-parser registration.
directives.register_directive('id', Id)

#------------------------------------------------------------------------------
# TODO: don't do this. instead, open a feature-request...
from docutils.writers.html4css1 import HTMLTranslator
def better_stylesheet_call(self, path):
  upath = urllib.parse.unquote(path or '')
  if not upath or not upath.startswith('data:text/css'):
    return self._real_stylesheet_call(path)
  content = upath.split(',', 1)[1]
  return self.embedded_stylesheet % (content,)
if not hasattr(HTMLTranslator, '_real_stylesheet_call'):
  HTMLTranslator._real_stylesheet_call = HTMLTranslator.stylesheet_call
  HTMLTranslator.stylesheet_call = better_stylesheet_call

#------------------------------------------------------------------------------
def resolvecss(data, spec):
  if ':' in spec:
    pkg, name = spec.split(':', 1)
    return AssetResolver(pkg).resolve(name).stream().read()
  return resolve(spec)(data)

#------------------------------------------------------------------------------
def rst2html(data, text):

  css = [
    urllib.parse.quote('data:text/css;charset=UTF-8,' + resolvecss(data, e))
    for e in aslist(data.options.cssPath or '')]
  # todo: add the docutils default css as well...

  settings = {
    # 'input_encoding': 'UTF-8',
    'output_encoding':  data.options.encoding,
    'embed_stylesheet': data.options.cssEmbed,
    'stylesheet_path':  css,
    }

  parts = core.publish_parts(
    text, writer_name='html', settings_overrides=settings)

  parts = runFilters(data.options.filters, parts, data.options)

  order = (
    'head_prefix',
    'head',
    'stylesheet',
    'body_prefix',
    'body_pre_docinfo',
    'docinfo',
    'body',
    'body_suffix',
    )

  html = ''.join([parts[part] for part in order]).encode(data.options.encoding)

  return html

#------------------------------------------------------------------------------
# end of $Id$
#------------------------------------------------------------------------------
