#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""nhl.py

Reads playerstats and careerstats from nhl.com,
that is <http://www.nhl.com/ice/playerstats.htm> and
<http://www.nhl.com/ice/player.htm?id=..>.


Example usage, reading playerstats:

q = Query()
q.season("20142015")
q.gametype("regular")
q.report("summary")

for row in q:
    print (row)


Example usage, getting career stats tables for a specific Player:

p = Player(8474577)
print (p.tables)

"""

from urllib.parse import urlencode, parse_qs
from urllib.request import urlparse
from urllib.request import urlopen
from lxml import etree
import re


PAGES = {}


class NHlException(Exception):
    pass


def getdoc(url):
    """Returns the HTML DOM as an etree Elementree"""
    if url not in PAGES:
        try:
            response = urlopen(url)
            content = response.read().decode('utf-8')
            parser = etree.HTMLParser()
        except Exception as e:
            raise SystemExit(e)

        PAGES[url] = etree.fromstring(content, parser)

    return PAGES[url]


def stringify(element):
    """Concatenates all text in the subelements into one string"""
    return u"".join([x for x in element.itertext()]).strip().replace("\n",
                                                                     " ")

def get_nhlid_from_tablerow(tr):
    """Get player ID from href inside the row"""
    anchor_tag = tr.find(".//a[@href]")

    if anchor_tag is not None:
        href = anchor_tag.attrib['href']
        if re.match(r"^/ice/player.htm", href):
            qs = urlparse(href).query
            return parse_qs(qs).get("id", None)[0]


def get_table_columns(table):
    """Returns the column names for the table.
    We skips first col, as it's only the row number.
    We add NHL ID and Number columns in the beginnnig.
    """
    thead = table.find("thead")
    columns = [stringify(th) for th in thead.findall(".//th")]
    return ['nhl_id', 'number'] + columns[1:]


def get_table_pages_urls(url):
    """Gets URLS for pages of the table at the given URL"""

    doc = getdoc(url)

    urls = []
    pages_div = doc.find(".//div[@class='pages']")

    #Check for empty table
    if pages_div is None:
        return urls

    #Check for one page table
    page_anchors = pages_div.findall("a")
    if len(page_anchors) < 1:
        urls.append(url)  # One page table
        return urls

    #Get the last page anchor
    last_anchor = page_anchors[-1]
    last_anchor_href = last_anchor.get("href")

    #Get the number of the last page
    pattern = re.compile(r"(\d+)")
    number_of_pages = pattern.findall(last_anchor_href)[-1]

    #Load all pages
    nhl_base_url = "http://www.nhl.com"
    for p in range(1, int(number_of_pages) + 1):
        page_url = last_anchor_href.replace("pg=" + number_of_pages,
                                            "pg=" + str(p))
        urls.append(nhl_base_url + page_url)

    return urls


def readrows(urls, limit=None):
    """Reads all or a limited numbers of rows from the table"""

    row_counter = 0
    for url in urls:

        doc = getdoc(url)

        table = doc.find(".//table[@class='data stats data-table table-origin']")

        if row_counter == 0:
            yield get_table_columns(table)

        tbody = table.find("tbody")

        if tbody is None:
            raise StopIteration

        for tr in tbody.findall('tr'):

            if limit is not None and row_counter == limit:
                raise StopIteration

            nhl_id = get_nhlid_from_tablerow(tr)

            data = [nhl_id] + [stringify(td) for td in tr.findall("td")]

            yield data

            row_counter += 1


class Query:
    """Query for playerstats"""

    PLAYERSTATS_URL = "http://www.nhl.com/ice/playerstats.htm"

    def __str__(self):
        return self.url()

    def season(self, s):
        if re.match(r"\d{8}", s):
            self.season = s
        return self

    def gametype(self, gt):
        if gt == 'regular':
            self.gameType = 2
        elif gt == 'playoffs':
            self.gameType = 3
        return self

    def team(self, t):
        if re.match(r"[A-Z]{3}", t):
            self.team = t
        return self

    def country(self, c):
        if re.match(r"[A-Z]{3}", c):
            self.country = c
        return self

    def position(self, p):
        if p in ("S", "C", "D", "F", "G", "L", "R"):
            self.position = p
        return self

    def report(self, r):
        if r in ('bios', 'summary'):
            self.viewName = r
        return self

    def url(self):
        """Builds the URL based on parameters"""
        if self.position == 'G' and self.viewName == 'bios':
            self.viewName = 'goalieBios'

        query = self.__dict__

        url = Query.PLAYERSTATS_URL + "?" + urlencode(query)

        return url

    def run(self, limit=None):
        urls = get_table_pages_urls(self.url())
        print (urls)
        return readrows(urls, limit)

    def fetch(self, limit=None):
        result = []
        for p in self.run(limit):
            result.append(p)
        return result

    def __iter__(self):
        return self.run()


class Player:
    """Represent an NHL player on nhl.com"""

    CAREER_URL = "http://www.nhl.com/ice/player.htm?id={}"

    def __init__(self, player_id):
        """Loads the player stats page as an ElementTree"""
        url = Player.CAREER_URL.format(player_id)
        self.doc = getdoc(url)

    @property
    def twitter(self):
        """Gets the players twitter handle or None"""
        twitter_tag = self.doc.find(".//a[@class='twitter-follow-button']")
        if twitter_tag is not None:
            return twitter_tag.get("href").split("/")[-1]

    @property
    def tables(self):
        """Grabs all career tables from the player page."""

        playerstats_tables = []

        for table in self.doc.findall(".//table[@class='data playerStats']"):

            headers = [th.text for th in table.findall(".//th")]

            table_group = [headers]

            for row_i in table.findall(".//tr")[1:]:

                data = [stringify(td) for td in row_i.findall("td")]

                table_group.append(data)

            playerstats_tables.append(table_group)

        return playerstats_tables

def main():

    parser = argparse.ArgumentParser(description='Read playerstats from nhl.com')
    parser.add_argument('seasons', metavar='Seasons', help='e.g. 20142015')
    parser.add_argument('-p', '--pos', dest='position',
                        action='store',
                        default="S",
                        choices=('S', 'G', 'D', 'L', 'R', 'C'),
                        help='Player position')
    parser.add_argument('-g', '--gametype', dest='gametype',
                        action='store',
                        default="regular",
                        choices=('regular', 'playoffs'),
                        help='Gametype')
    parser.add_argument('-r', '--report', dest='report',
                        action='store',
                        default="summary",
                        choices=('bios', 'summary'),
                        help='Report')
    args = parser.parse_args()

    q = Query()
    q.season(args.seasons)
    q.gametype(args.gametype)
    q.position(args.position)
    q.report(args.report)

    writer = csv.writer(sys.stdout)
    writer.writerows(q)


if __name__ == '__main__':
    import argparse
    import csv
    import sys
    main()
