"""
Load and clean player/team tournament data from play.usaultimate.org.
"""

from __future__ import print_function

from collections import OrderedDict
import logging
import os
import re
import sys

from bs4 import BeautifulSoup
import pandas as pd
import requests
from six import string_types  # py2/3 compat

_logger = logging.getLogger(__name__)

_table_cache = {}
def memoize_read_html(url, match, header):
    """Memoized wrapper around pandas.read_html"""
    global _table_cache
    key = (url, match, header)
    if key not in _table_cache:
        _table_cache[key] = pd.read_html(url, match=match, header=header)
    return _table_cache[key]


def title_name(name):
    """Capitalize first letter of each name"""
    if name.isupper():
        return name.title()
    return name  # Leave capitalizations in middle of names, like 'McCray'


class PickleSoup(object):
    """Minor helper for pickling a few pieces of a BeautifulSoup object"""

    def __init__(self, soup):
        self.attrs = dict(soup.attrs)
        self.text = soup.text


class USAUResults(object):
    """Container and helpers for accessing player statistics on USAU website"""
    BASE_URL = "http://play.usaultimate.org"

    def __init__(self, event_info, gender, year,
                 executor=None):
        assert gender in self.__class__._GENDERS
        self.event_info = event_info
        self.gender = gender
        self.year = year
        self.event_full = event_info["url"].format(y=year)
        # TODO: flesh out competition parser?
        self.competition = ("College" if "college" in self.event_info["level"]
                            else "Club")

        if "full_url" in event_info:
            self.event_url = event_info["full_url"]
        else:
            self.event_url = ("{url}/events/{evt}/schedule/"
                              "{gender}/{comp}{gender}"
                              .format(url=self.BASE_URL,
                                      evt=self.event_full,
                                      # Silly USAU and the different URLs ..
                                      comp=self.competition + ("-" if self.competition != "College" else ""),
                                      gender=self.gender.capitalize()))

        self.event_page_soup = None
        self.roster_dfs = None
        self.match_report_dfs = None
        self.match_result_dfs = None
        self.score_progression_dfs = None
        self.data_dir = None
        self.executor = executor

    def __str__(self):
        # TODO:
        return repr(self)

    def __repr__(self):
        return ("USAUResults<{name}>"
                .format(name=self._name()))

    def _name(self):
        event = self.event_info["event"][0].replace(' ', '-')
        name = ("{year}_{level}_{event}_{gender}"
                .format(year=self.year,
                        level=self.event_info["level"],
                        event=event,
                        gender=self.gender,
                        ))
        return name

    def set_executor(self, mode, max_workers=4):
        if mode == "thread":
            from concurrent.futures import ThreadPoolExecutor
            self.executor = ThreadPoolExecutor(max_workers=max_workers)
        elif mode == "process":
            from concurrent.futures import ProcessPoolExecutor
            self.executor = ProcessPoolExecutor(max_workers=max_workers)

    def to_csvs(self, data_dir=None, encoding='utf-8'):
        """Write data to given directory in the form of csv files"""
        if data_dir is None:
            data_dir = os.path.join(os.path.dirname(
                os.path.abspath(__file__)), "data")
        assert isinstance(data_dir, string_types)

        # TODO: put in subfolders instead?
        base_path = os.path.join(os.path.expanduser(data_dir),
                                 self._name())

        self.rosters.to_csv(
            base_path + "_rosters.csv", encoding=encoding)
        self.match_reports.to_csv(
            base_path + "_match_reports.csv", encoding=encoding)
        self.match_results.to_csv(
            base_path + "_match_results.csv", encoding=encoding)
        self.score_progressions.to_csv(
            base_path + "_scores.csv", encoding=encoding)

        print("Finished writing CSVs to {data_dir}".format(data_dir=data_dir))

    def load_from_csvs(self, data_dir=None, mandatory=True, write=True):
        """Load data from offline csv files"""
        if data_dir is None:
            data_dir = os.path.join(os.path.dirname(
                os.path.abspath(__file__)), "data")
        assert isinstance(data_dir, string_types)
        base_path = os.path.join(os.path.expanduser(data_dir),
                                 self._name())

        try:
            self.roster_dfs = pd.read_csv(
                base_path + "_rosters.csv")
            self.match_report_dfs = pd.read_csv(
                base_path + "_match_reports.csv")
            self.match_result_dfs = pd.read_csv(
                base_path + "_match_results.csv")
            self.score_progression_dfs = pd.read_csv(