from collections import namedtuple
import re
from urllib import parse
from bs4 import BeautifulSoup
import os.path
import requests
__author__ = 'zz'


island_netloc_table = {}
island_class_table = {}


DivInfo = namedtuple('DivInfo', ['content', 'link', 'response_num'])


class IslandNotDetectError(Exception):
    pass





class IslandMeta(type):

    def __init__(cls, name, bases, ns):
        if name != 'BaseIsland':
            island_name = ns.get('_island_name')
            island_netloc = ns.get('_island_netloc')
            assert island_name , 'Not define _island_name in {} class'.format(name)
            assert island_netloc , 'Not define _island_netloc in {} class'.format(name)

             # register island and netloc
            island_netloc_table.update({island_netloc: island_name})

            # register island class
            island_class_table.update({island_name: cls})

        super().__init__(name, bases, ns)


class BaseIsland(metaclass=IslandMeta):

    _island_name = ''
    _island_netloc = ''
    _island_scheme = 'http'
    _count_pattern = re.compile(r'\s(\d+)\s')
    json_data = False

    def __init__(self, current_url, res):
        if not self.json_data:
            self.pd = BeautifulSoup(res.content)
        else:
            self.pd = res.json()

        self.current_url = current_url

    @property
    def root_url(self):
        return parse.urlunsplit((self._island_scheme, self._island_netloc, '', '', ''))

    def get_div_response_num(self, tip):
        """
        return response count
        """
        text = tip.text
        match = self._count_pattern.search(text)
        if match:
            return match.group(1)
        else:
            # may be the text is 'sega'
            return 0



    def get_tips(self, pd):
        """
        :param pd: a BeautifulSoup object or json object, determine by json_data
        return a list of  object that contain tips content
        """
        raise NotImplementedError

    def get_div_link(self, tip):
        """
        tip is a BeautifulSoup object contain response tip
        return the link href string, eg, 'http://xx.com', or /xx/xx.html """
        raise NotImplementedError

    def get_div_content(self, tip):
        """
        return content
        """
        raise NotImplementedError

    def get_next_page_url(self):
        raise NotImplementedError

    def next_page_valid(self, next_page_url):
        raise NotImplementedError

    def next_page(self):
        """
        return next page url
        """
        next_page_url = self.get_next_page_url()
        if self.next_page_valid(next_page_url):
            return next_page_url
        else:
            return None

    def island_split_page(self):
        """
        must return DivInfo object
        """
        result = []

        pd = self.pd
        tips = self.get_tips(pd)
        for tip in tips:
            response_num = int(self.get_div_response_num(tip))
            link = self.complete_link(self.get_div_link(tip))
            content = self.get_div_content(tip)
            div = DivInfo(content=content, link=link, response_num=response_num)
            result.append(div)

        return result


    def complete_link(self, url):
        return parse.urljoin(self.root_url, url)


class NextPageStaticHtmlMixin:
    _static_count_pattern = re.compile(r'(\d+)')

    def get_next_page_url(self):
        path = parse.urlparse(self.current_url).path
        basename = os.path.basename(path)
        # static html basename must be d.htm(l)
        current_page_num, suffix  = basename.split('.')

        if current_page_num == 'index':
            current_page_num = 0

        next_page_num = int(current_page_num) + 1
        next_basename = '.'.join((str(next_page_num), suffix))


        # In [73]: parse.urljoin('gg/h.html','gg.html')
        # Out[73]: 'gg/gg.html'
        return parse.urljoin(self.current_url, next_basename)

    def next_page_valid(self, next_page_url):
        return requests.head(next_page_url).ok


class NextPageJsonParameterMixin:
    _has_next_page = True


    def get_max_page(self):
        return int(self.pd['page']['size'])

    def get_next_page_url(self):
        max_page = self.get_max_page()


        base_url, query = parse.splitquery(self.current_url)
        if not query:
            query='page=0'

        _, count = parse.parse_qsl(query)[0]
        count = int(count) + 1
        if count > max_page:
            self._has_next_page = False

        next_query = parse.urlencode({'page': count})
        url = base_url+ '?' + next_query
        return url


    def next_page_valid(self, url):
        return self._has_next_page
@@ -261,19 +261,28 @@
 nse_num'
+, 'image'
 %5D)%0A
-
 %0A%0Aclass 
@@ -1130,24 +1130,46 @@
 data = False
+%0A    show_image = True
 %0A%0A    def __
@@ -2346,32 +2346,101 @@
 plementedError%0A%0A
+    def get_div_image(self, tip):%0A        raise NotImplementedError%0A%0A
     def get_next
@@ -3184,16 +3184,87 @@
 nt(tip)%0A
+            image = self.get_div_image(tip) if self.show_image else ''%0A
         
@@ -3334,16 +3334,29 @@
 onse_num
+, image=image
 )%0A      

add image