# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
# SPDX-FileContributor: 2020-22 Bradley M. Bell
# ----------------------------------------------------------------------------
import re
import xrst
#
pattern_start_literal = re.compile( r'\n::{xrst_line [0-9]+@\n\n' )
pattern_end_literal   = re.compile( r'\n[^ \t]')
pattern_declare = re.compile(
   r'\n\.\. _([^:\n]+):([^\n]*)\{xrst_line ([0-9]+)@'
)
pattern_use = re.compile(
   r'`([^<\n]+)(<[^>\n]*>)`_[^\n]*\{xrst_line ([0-9]+)@'
)
# ----------------------------------------------------------------------------
# {xrst_begin sphinx_label dev}
#
# Get Labels Declared Using Sphinx Commands
# #########################################
#
# {xrst_comment_ch #}
#
# data_in
# *******
# is the data for one page.
# Line numbers have been added to this data; see
# :ref:`add_line_numbers-name` .
#
# file_name
# *********
# is the name of the xrst input file corresponding to data_in
# (only used for error reporting).
#
# page_name
# *********
# is the page name corresponding to data_in
# (only used for error reporting).
#
# external_line
# *************
# For each label declared in data_in using sphinx commands,
# and that links to an external web site,
# *external_line* [ *label*.lower() ] is the line number in
# *file_name* where the label was defined.
#
# internal_line
# *************
# For each label declared in data_in using sphinx commands,
# and that links to a page in this web site,
# *internal* [ *label* ] is the line number in
# *file_name* where the label was defined.
#
# Errors
# ******
# If two or external labels have the same lower case value,
# an error is reported using :ref:`system_exit-name` .
#
# {xrst_code py}
# external_line, internal_line =
def sphinx_label(data_in, file_name, page_name) :
   assert type(data_in) == str
   assert type(file_name) == str
   assert type(page_name) == str
   # {xrst_code}
   # {xrst_literal
   #     BEGIN_return
   #     END_return
   # }
   # {xrst_end sphinx_label}
   #
   # external_line, internal_line
   external_line  = dict()
   internal_line  = dict()
   #
   # data
   data = data_in
   #
   # m_start
   # remove literal blocks because no labels defined there
   m_start = pattern_start_literal.search(data)
   while m_start :
      #
      # m_end
      m_end = pattern_end_literal.search(data_in, m_start.end() )
      #
      # data, m_start
      if m_end == None :
         data    = data[: m_start.start() ]
         m_start = None
      else :
         data_before = data[: m_start.start() ]
         data_after  = data[m_end.end() : ]
         data        = data_before + data_after
         m_start     = pattern_start_literal.search(data, len(data_before) )
   #
   # pattern
   for pattern in [ pattern_declare, pattern_use ] :
      #
      # m_label
      m_label    = pattern.search(data)
      while m_label :
         #
         # label_lower, line
         label       = m_label.group(1).strip(' ')
         label_lower = label.lower()
         destination = m_label.group(2).strip(' ')
         line        = m_label.group(3)
         #
         for ending in [ '-name', '-title' ] :
            if label_lower.endswith(ending) :
               msg  = f'Labels that end with {ending} are not allowed\n'
               msg += 'because they are automatically generated by xrst\n'
               msg += f'label.lower() = {label_lower}'
               xrst.system_exit(msg,
                  file_name = file_name, page_name = page_name, line = line
               )
         if '@' in label_lower :
            msg  = f'Labels that use the @ character are not allowed\n'
            msg += 'because they are automatically generated by xrst\n'
            msg += f'label.lower() = {label_lower}'
            xrst.system_exit(msg,
               file_name = file_name, page_name = page_name, line = line
            )
         if label_lower == page_name :
            msg  = 'A label has the same lower case value as the page_name\n'
            msg += f'label.lower() = {label_lower}'
            xrst.system_exit(
               msg, file_name = file_name, page_name = page_name, line = line
            )
         #
         if label_lower in external_line :
            previous_line = external_line[label_lower]
            msg  = 'A previous label has the same lower case value\n'
            msg += f'label.lower() = {label_lower}\n'
            msg += f'previous_line = {previous_line}'
            xrst.system_exit(
               msg, file_name = file_name, page_name = page_name, line = line
            )
         #
         # external_line, internal_line
         external =  destination != ''
         if external :
            external_line[label_lower] = line
         else :
            internal_line[label] = line
         #
         # m_label
         m_label = pattern.search(data, m_label.end())
   # BEGIN_return
   for result in [ external_line, internal_line ] :
      assert type(result) == dict
      for key in result.keys() :
         assert type( result[key] ) == str
   #
   return external_line, internal_line
   # END_return
