'''
This is a modified version of cbanack's fnamparser module from his
ComicVineScraper plugin (https://github.com/cbanack/comic-vine-scraper)

This module contains functions for extracting and parsing details out
of comic book filenames.

Created on Oct 23, 2011
@author: cbanack

Originally modified on Aug 10, 2016
@author: hmhrex
'''
import re,os
from . import utils


#==============================================================================
def extract( filename_s ):
   '''
   Takes the filename of a comic book, and extracts three strings out of it: the
   series name, the issue number, and the issue year. These three pieces
   of information are returned as a triple, i.e. ("batman", "344", "2004").

   This function never returns None, and it will ALWAYS return the triple with
   at least a non-empty series name (even if it is just "unknown"), but the
   issue number and year may be "" if they couldn't be determined.
   '''
   # remove the file extension, unless it's the whole filename
   name_s = os.path.basename(filename_s)
   last_period = name_s.rfind(r".")
   name_s = name_s if last_period <= 0 else name_s[0:last_period]

   # see if the comic matches the following format, and if so, remove everything
   # after the first number:
   # "nnn series name #xx (etc) (etc)" -> "series name #xx (etc) (etc)"
   match = re.match(r"^\s*(\d+)[\s._-]+" +     # "nnn"
                    r"([^#]+?" +               # "series name"
                    r"#-?\d+.*)", name_s)      # "#xx (etc) (etc)"
   if match: name_s = match.group(2)

   # see if the comic matches the following format, and if so, remove everything
   # after the first number that isn't in brackets:
   # "series name #xxx - title (etc) (etc)" -> "series name #xxx (ect) (etc)
   match = re.match(r"^((?:[a-zA-Z,.-]+\s+)+" +        # "series name"
                    r"#?(?:\d+[.0-9]*))\s*(?:-)" +     # "#xxx -"
                    r".*?((\(.*)?)$", name_s)          # "title (etc) (etc)"

   # TOCHANGE: log.debug()
   if match:
      #log.debug(name_s)
      name_s = match.group(1) + " " + match.group(2)
      #log.debug("     -> ", name_s)

   # try the extraction.  if anything goes wrong, or if we come up with a blank
   # series name, revert to the filename (without extension) as series name
   try:
      retval = __extract(name_s)
      if retval[0].strip() == "":
         raise Exception("parsed blank series name")

   # TOCHANGE: log.debug()
   except:
      #log.debug_exc("Recoverable error extracting from '" + name_s + "':")
      retval = name_s, "", ""
   return retval



#==============================================================================
def __extract(name_s):
   ''' Internal implementation of the similarly named method in this package '''

   # 1. 's' is the name of our 'working' series name.  we'll slowly strip the
   #    'non-series name' data out of it, til what's left is the series name
   s = name_s

   # 2. but first, see if there's a volume/year in there.
   volume_year_s =  __extract_year(s)

   # 3. strip out all bracketed data from the name
   def recurse_sub(pattern, s):
      while re.search(pattern, s):
         s = re.sub(pattern, "", s)
      return s
   s = recurse_sub(r"\([^\(]*?\)", s)
   s = recurse_sub(r"\{[^\{]*?\}", s)
   s = recurse_sub(r"\[[^\[]*?\]", s)

   # 4. clean out underscores
   s = re.sub(r"_", " ", s)

   # 5. remove all trace of volume from the name (like "vol. 2a" and "vol -3.1")
   s = re.sub(r"(?i)(\b((vol)\.?|volume))", "", s)

   # 6. remove all page counts, ie. "245p" or "50 pages"
   s = re.sub(r"(?i)\b[.,]?\s*\d+\s*(p|pg|pgs|pages)\b[.,]?", "", s)

   # 7. remove anything following a similar pattern to "02 of 02 covers"
   s = re.sub(r"(?i)(\d+\s*of\s*\d+\s*covers)", "", s)

   # 8. if the name has things like "4 of 5", remove the " of 5" part
   #    also, if the name has 3-6, remove the -6 part.  note that we'll
   #    try to handle the word "of" in a few common languages, like french/
   #    spanish (de), italian (di), german (von), dutch (van) or polish (z)
   s = re.sub(r"(?i)(?<=\d)(\s*(of|de|di|von|van|z)\s*#*\d+)", "", s)
   s = re.sub(r"(?<=\d)(-\d+)", "", s)

   # 9. if this is one of those comic books that replaces all spaces with
   #    dashes or periods, then strip the dashes and/or periods out. otherwise
   #    leave them in (because they might be important, like minus signs or
   #    something.)
   if "-" in s and " " not in s:
      s = re.sub(r"(?<![-_# ])-", " ", s)
   if "." in s and " " not in s:
      s = re.sub(r"(?<![._# ])\.", " ", s)

   # 10. get an ordered list of issue number-like strings in the filename
   #    for example:  3, #4, 6.00, .5, -1.0
   #    also, remove numbers that look like years, EXCEPT on the "2000AD" series
   matches = __extract_numbers(s)

   # 11. if there's multiple numbers in the filename, and it starts with
   #    something like "05. " or "12 - " we assuming these files are part of
   #    a reading list, and we strip out that first part.
   pattern = r"^\s*\d+(\.\s+|\s*-\s*(?=\D))"
   if len(matches) > 1 and re.match(pattern,s):
      s = re.sub(pattern, "", s, 1)
      matches = __extract_numbers(s)

   # 12. if we parsed out some potential issue numbers, designate the LAST
   #    (rightmost) one as the actual issue number, and remove it from the name
   if len(matches) > 0:
      issue_num_s = matches[-1].group(2)
      series_s = s[:matches[-1].start(0)] +s[matches[-1].end(0):]
      # 10a. strip off leading/trailing zeroes
      matches = re.match("^(0+)([0-9].*)$", issue_num_s)
      issue_num_s = matches.group(2) if matches else issue_num_s

      #TOCHANGE: utils.is_number() and utils.sstr()
      if re.match("^-?[.0-9]+$", issue_num_s) and utils.is_number(issue_num_s):
         issue_num_s = utils.sstr(float(issue_num_s) \
             if '.' in issue_num_s else int(issue_num_s))
   else:
      issue_num_s = ""
      series_s = s

   # 13. contract repeating whitespace, and strip bad chars off the ends
   series_s = re.sub(r"\s{2,}", " ", series_s).strip(" ,-_")

   return [series_s, issue_num_s, volume_year_s]


#==============================================================================
def __extract_year(s):
   '''
   Searches through the given string left-to-right, seeing if an intelligible
   publication year can be extracted.  if it can, it will be returned as a
   four digit string, otherwise "" will be returned.
   '''

   retval = ""

   # type one years appear exactly as "V2003".  there's a popular comicrack
   # script that creates dates that look like this, so parse em if we can
   results = [ x[1] for x in
      re.findall(r"(?i)(^|[, -_])v(\d{4})($|[, -_])",s) if __isYear(x[1]) ]