text: # -*- coding: utf-8 -*-
  
  # Copyright 2013 Fanficdownloader team, 2018 FanFicFare team
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  #     http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  #
  
  # Software: eFiction
  from __future__ import absolute_import
  import logging
  logger = logging.getLogger(__name__)
  import re
  from ..htmlcleanup import stripHTML
  from .. import exceptions as exceptions
  
  # py2 vs py3 transition
  from ..six import text_type as unicode
  from ..six.moves.urllib.error import HTTPError
  
  from .base_adapter import BaseSiteAdapter,  makeDate
  
  def getClass():
      return ImagineEFicComAdapter
  
  # Class name has to be unique.  Our convention is camel case the
  # sitename with Adapter at the end.  www is skipped.
  class ImagineEFicComAdapter(BaseSiteAdapter):
  
      def __init__(self, config, url):
          BaseSiteAdapter.__init__(self, config, url)
  
          self.username = "NoneGiven" # if left empty, site doesn't return any message at all.
          self.password = ""
          self.is_adult=False
  
          # get storyId from url--url validation guarantees query is only sid=1234
          self.story.setMetadata('storyId',self.parsedUrl.query.split('=',)[1])
  
  
          # normalized story URL.
          self._setURL('https://' + self.getSiteDomain() + '/viewstory.php?sid='+self.story.getMetadata('storyId'))
  
          # Each adapter needs to have a unique site abbreviation.
          self.story.setMetadata('siteabbrev','ime')
  
          # The date format will vary from site to site.
          # http://docs.python.org/library/datetime.html#strftime-strptime-behavior
          self.dateformat = "%Y.%m.%d"
  
      @staticmethod # must be @staticmethod, don't remove it.
      def getSiteDomain():
          # The site domain.  Does have www here, if it uses it.
          return 'imagine.e-fic.com'
  
      @classmethod
      def getSiteExampleURLs(cls):
          return "https://"+cls.getSiteDomain()+"/viewstory.php?sid=1234"
  
      def getSiteURLPattern(self):
          return r"https?://"+re.escape(self.getSiteDomain()+"/viewstory.php?sid=")+r"\d+$"
  
      ## Login seems to be reasonably standard across eFiction sites.
      def needToLoginCheck(self, data):
          if 'Registered Users Only' in data \
                  or 'There is no such account on our website' in data \
                  or "That password doesn't match the one in our database" in data:
              return True
          else:
              return False
  
      def performLogin(self, url):
          params = {}
  
          if self.password:
              params['penname'] = self.username
              params['password'] = self.password
          else:
              params['penname'] = self.getConfig("username")
              params['password'] = self.getConfig("password")
          params['cookiecheck'] = '1'
          params['submit'] = 'Submit'
  
          loginUrl = 'https://' + self.getSiteDomain() + '/user.php?action=login'
          logger.debug("Will now login to URL (%s) as (%s)" % (loginUrl,
                                                                params['penname']))
  
          d = self._fetchUrl(loginUrl, params)
  
          if "Member Account" not in d : #Member Account
              logger.info("Failed to login to URL %s as %s" % (loginUrl,
                                                                params['penname']))
              raise exceptions.FailedToLogin(url,params['penname'])
              return False
          else:
              return True
  
      ## Getting the chapter list and the meta data, plus 'is adult' checking.
      def extractChapterUrlsAndMetadata(self):
  
          if self.is_adult or self.getConfig("is_adult"):
              # Weirdly, different sites use different warning numbers.
              # If the title search below fails, there's a good chance
              # you need a different number.  print data at that point
              # and see what the 'click here to continue' url says.
              addurl = "&ageconsent=ok&warning=4"
          else:
              addurl=""
  
          # index=1 makes sure we see the story chapter index.  Some
          # sites skip that for one-chapter stories.
          url = self.url+'&index=1'+addurl
          logger.debug("URL: "+url)
  
          try:
              data = self._fetchUrl(url)
          except HTTPError as e:
              if e.code == 404:
                  raise exceptions.StoryDoesNotExist(self.url)
              else:
                  raise e
  
          if self.needToLoginCheck(data):
              # need to log in for this one.
              self.performLogin(url)
              data = self._fetchUrl(url)
  
          m = re.search(r"'viewstory.php\?sid=\d+((?:&amp;ageconsent=ok)?&amp;warning=\d+)'",data)
          if m != None:
              if self.is_adult or self.getConfig("is_adult"):
                  # We tried the default and still got a warning, so
                  # let's pull the warning number from the 'continue'
                  # link and reload data.
                  addurl = m.group(1)
                  # correct stupid &amp; error in url.
                  addurl = addurl.replace("&amp;","&")
                  url = self.url+'&index=1'+addurl
                  logger.debug("URL 2nd try: "+url)
  
                  try:
                      data = self._fetchUrl(url)
                  except HTTPError as e:
                      if e.code == 404:
                          raise exceptions.StoryDoesNotExist(self.url)
                      else:
                          raise e
              else:
                  raise exceptions.AdultCheckRequired(self.url)
  
          if "Access denied. This story has not been validated by the adminstrators of this site." in data:
              raise exceptions.AccessDenied(self.getSiteDomain() +" says: Access denied. This story has not been validated by the adminstrators of this site.")
  
          # use BeautifulSoup HTML parser to make everything easier to find.
          soup = self.make_soup(data)
          # print data
  
          # Now go hunting for all the meta data and the chapter list.
  
          ## Title
          a = soup.find('a', href=re.compile(r'viewstory.php\?sid='+self.story.getMetadata('storyId')+"$"))
          self.story.setMetadata('title',stripHTML(a))
  
          # Find authorid and URL from... author url.
          a = soup.find('a', href=re.compile(r"viewuser.php\?uid=\d+"))
          self.story.setMetadata('authorId',a['href'].split('=')[1])
          self.story.setMetadata('authorUrl','https://'+self.host+'/'+a['href'])
          self.story.setMetadata('author',a.string)
  
          # Find the chapters:
          for chapter in soup.findAll('a', href=re.compile(r'viewstory.php\?sid='+self.story.getMetadata('storyId')+r"&chapter=\d+$")):
              # just in case there's tags, like <i> in chapter titles.
              self.add_chapter(chapter,'https://'+self.host+'/'+chapter['href']+addurl)
  
  
          # eFiction sites don't help us out a lot with their meta data
          # formating, so it's a little ugly.
  
          # utility method
          def defaultGetattr(d,k):
              try:
                  return d[k]
              except:
                  return ""
  
  
          # <span class="label">Rated:</span> NC-17<br /> etc
          labels = soup.findAll('span',{'class':'label'})
          for labelspan in labels:
              value = labelspan.nextSibling
              label = labelspan.string
  
              if 'Summary' in label:
                  ## Everything until the next span class='label'
                  svalue = ""
                  while 'label' not in defaultGetattr(value,'class'):
                      svalue += unicode(value)
                      value = value.nextSibling
                  self.setDescription(url,svalue)
                  #self.story.setMetadata('description',stripHTML(svalue))
  
              if 'Rated' in label:
                  self.story.setMetadata('rating', value)
  
              if 'Word count' in label:
                  self.story.setMetadata('numWords', value)
  
              if 'Categories' in label:
                  cats = labelspan.parent.findAll('a',href=re.compile(r'browse.php\?type=categories'))
                  for cat in cats:
                      self.story.addToList('category',cat.string)
  
              if 'Characters' in label:
                  chars = labelspan.parent.findAll('a',href=re.compile(r'browse.php\?type=characters'))
                  for char in chars:
                      self.story.addToList('characters',char.string)
  
              if 'Genre' in label:
                  genres = labelspan.parent.findAll('a',href=re.compile(r'browse.php\?type=class&type_id=1'))
                  for genre in genres:
                      self.story.addToList('genre',genre.string)
  
              if 'Warnings' in label:
                  warnings = labelspan.parent.findAll('a',href=re.compile(r'browse.php\?type=class&type_id=2'))
                  for warning in warnings:
                      self.story.addToList('warnings',warning.string)
  
              if 'Completed' in label:
                  if 'Yes' in value:
                      self.story.setMetadata('status', 'Completed')
                  else:
                      self.story.setMetadata('status', 'In-Progress')
  
              if 'Published' in label:
                  self.story.setMetadata('datePublished', makeDate(stripHTML(value), self.dateformat))
  
              if 'Updated' in label:
                  self.story.setMetadata('dateUpdated', makeDate(stripHTML(value), self.dateformat))
  
          try:
              # Find Series name from series URL.
              a = soup.find('a', href=re.compile(r"viewseries.php\?seriesid=\d+"))
              series_name = a.string
              series_url = 'https://'+self.host+'/'+a['href']
  
              # use BeautifulSoup HTML parser to make everything easier to find.
              seriessoup = self.make_soup(self._fetchUrl(series_url))
              # can't use ^viewstory...$ in case of higher rated stories with javascript href.
              storyas = seriessoup.findAll('a', href=re.compile(r'viewstory.php\?sid=\d+'))
              i=1
              for a in storyas:
                  # skip 'report this' and 'TOC' links
                  if 'contact.php' not in a['href'] and 'index' not in a['href']:
                      if a['href'] == ('viewstory.php?sid='+self.story.getMetadata('storyId')):
                          self.setSeries(series_name, i)
                          self.story.setMetadata('seriesUrl',series_url)
                          break
                      i+=1
  
          except:
              # I find it hard to care if the series parsing fails
              pass
  
      # grab the text for an individual chapter.
      def getChapterText(self, url):
  
          logger.debug('Getting chapter text from: %s' % url)
  
          soup = self.make_soup(self._fetchUrl(url))
  
          div = soup.find('div', {'id' : 'story'})
  
          if None == div:
              raise exceptions.FailedToDownload("Error downloading Chapter: %s!  Missing required element!" % url)
  
          return self.utf8FromSoup(url,div)
  