#!/bin/python

"""
APIs to lookup into the baseball map stored at http://crunchtimebaseball.com.

All of the from_* APIs return a DataFrame that has baseball player
particulars for the IDs in the lookup.  For each player that it finds
it will a return row in a panda's DataFrame that has:

>>> Index(['mlb_id', 'mlb_name', 'mlb_pos', 'mlb_team', 'mlb_team_long',
>>>        'bats', 'throws', 'birth_year', 'bp_id', 'bref_id', 'bref_name',
>>>        'cbs_id', 'cbs_name', 'cbs_pos', 'espn_id', 'espn_name', 'espn_pos',
>>>        'fg_id', 'fg_name', 'fg_pos', 'lahman_id', 'nfbc_id', 'nfbc_name',
>>>        'nfbc_pos', 'retro_id', 'retro_name', 'debut', 'yahoo_id',
>>>        'yahoo_name', 'ottoneu_id', 'ottoneu_name', 'ottoneu_pos',
>>>        'rotowire_id', 'rotowire_name', 'rotowire_pos'],
>>>       dtype='object')
"""
import pandas as pd


def from_mlb_ids(ids):
    """Lookup given a list of mlb_ID's

    Accepts a list of MLB IDs.  It will return a DataFrame containing
    Series for players that match the MLB IDs passed in.  If nothing was
    found an empty DataFrame is returned.

    :param ids: mlb_ID's to lookup
    :type ids: int list
    :return: Players that match the given IDs.  If none are found an empty
             DataFrame is returned.
    :rtype: DataFrame

    >>> In [1]: lookup.from_mlb_ids([430945, 607680, 669456])
    >>> Out[1]:
    >>>       mlb_id      mlb_name mlb_pos mlb_team  ... ottoneu_pos rotowire_id rotowire_name  rotowire_pos
    >>> 39    430945    Adam Jones      CF      ARI  ...          OF      8165.0    Adam Jones            OF
    >>> 1746  607680  Kevin Pillar      CF       SF  ...          OF     12678.0  Kevin Pillar            OF
    >>> 2545  669456  Shane Bieber       P      CLE  ...          SP     14383.0  Shane Bieber             P
    >>>
    >>> [3 rows x 35 columns]

    """ # noqa
    c = Cache()
    return c.from_mlb_ids(ids)


def from_yahoo_ids(ids):
    """Lookup given a list of Yahoo! IDs

    Accepts a list of IDs from Yahoo! fantasy baseball.  It will return a
    DataFrame containing Series for players that match the Yahoo! IDs.  If
    nothing was found an empty DataFrame is returned.

    :param ids: Yahoo! IDs to lookup
    :type ids: int list
    :return: Players that match the given IDs.  If none are found an empty
             DataFrame is returned.
    :rtype: DataFrame

    >>> In [1]: c.from_yahoo_ids([10794, 9542, 7578])
    >>> Out[1]:
    >>>       mlb_id        mlb_name mlb_pos mlb_team  ... ottoneu_pos rotowire_id   rotowire_name  rotowire_pos
    >>> 5     621345     A.J. Minter       P      ATL  ...          RP     13889.0     A.J. Minter             P
    >>> 204   605151  Archie Bradley       P      ARI  ...          RP     12131.0  Archie Bradley             P
    >>> 2340  448179       Rich Hill       P      LAD  ...          SP      7965.0       Rich Hill             P
    >>>
    >>> [3 rows x 35 columns]

    """ # noqa
    c = Cache()
    return c.from_yahoo_ids(ids)


def from_cbs_ids(ids):
    """Lookup given a list of CBS IDs

    Accepts a list of IDs from CBS fantasy baseball.  It will return a
    DataFrame containing Series for players that match the IDs.  If nothing
    was found an empty DataFrame is returned.

    :param ids: CBS IDs to lookup
    :type ids: int list
    :return: Players that match the given IDs.  If none are found an empty
             DataFrame is returned.
    :rtype: DataFrame

    >>> In [1]: lookup.from_cbs_ids([1660162, 2507367])
    >>> Out[1]:
    >>>       mlb_id      mlb_name mlb_pos mlb_team  ... ottoneu_pos rotowire_id rotowire_name  rotowire_pos
    >>> 423   457763  Buster Posey       C       SF  ...        C/1B     10426.0  Buster Posey             C
    >>> 1657  665742     Juan Soto      LF      WSH  ...          OF     13960.0     Juan Soto            OF
    >>>
    >>> [2 rows x 35 columns]

    """ # noqa
    c = Cache()
    return c.from_cbs_ids(ids)


def from_espn_ids(ids):
    """Lookup given a list of ESPN IDs

    Accepts a list of IDs from ESPN fantasy baseball.  It will return a
    DataFrame containing Series for players that match the IDs.  If nothing
    was found an empty DataFrame is returned.

    :param ids: ESPN IDs to lookup
    :type ids: int list
    :return: Players that match the given IDs.  If no Series are found an
             empty DataFrame is returned.
    :rtype: DataFrame

    >>> In [1]: c.from_espn_ids([29252])
    >>> Out[1]:
    >>>      mlb_id       mlb_name mlb_pos mlb_team  ... ottoneu_pos rotowire_id  rotowire_name  rotowire_pos
    >>> 836  451594  Dexter Fowler      RF      STL  ...          OF      8271.0  Dexter Fowler            OF
    >>>
    >>> [1 rows x 35 columns]

    """ # noqa
    c = Cache()
    return c.from_espn_ids(ids)


def from_fangraphs_ids(ids):
    """Lookup given a list of FanGraph IDs

    Accepts a list of IDs as maintained at fangraphs.com.  It will return a
    DataFrame containing Series for players that match the IDs.  If nothing
    was found an empty DataFrame is returned.

    :param ids: FanGraph IDs to lookup
    :type ids: int list
    :return: Players that match the given IDs.  If no Series are found an
             empty DataFrame is returned.
    :rtype: DataFrame

    >>> In [35]: c.from_fangraphs_ids([19753, 19566])
    >>> Out[35]:
    >>>       mlb_id           mlb_name mlb_pos  ... rotowire_id      rotowire_name rotowire_pos
    >>> 1510  642528  Jonathan Loaisiga       P  ...     15256.0  Jonathan Loaisiga            P
    >>> 2133  663993          Nate Lowe      1B  ...         NaN                NaN          NaN
    >>>
    >>> [2 rows x 35 columns]

    """ # noqa
    c = Cache()
    return c.from_fangraphs_ids(ids)


class Cache:
    """Class that caches results of baseball ID lookups.

    You can use this to cut down on network traffic if you intend to do many
    calls to the APIs.  The first time we use an API, we'll cache the results
    for subsequent callers.

    All of the from_* APIs share the same signature as documented above and so
    aren't repeated again.
    """
    def __init__(self):
        self.source = 'http://crunchtimebaseball.com/master.csv'
        self.df = None
        pass

    def set_source(self, source):
        self.source = source

    def _read_source(self):
        if self.df is None:
            self.df = pd.read_csv(self.source, encoding='iso-8859-1')

    def from_mlb_ids(self, ids):
        self._read_source()
        return self.df[self.df.mlb_id.isin(ids)]

    def from_yahoo_ids(self, ids):
        self._read_source()
        return self.df[self.df.yahoo_id.isin(ids)]

    def from_cbs_ids(self, ids):
        self._read_source()
        return self.df[self.df.cbs_id.isin(ids)]

    def from_espn_ids(self, ids):
        self._read_source()
        return self.df[self.df.espn_id.isin(ids)]

    def from_fangraphs_ids(self, ids):
        self._read_source()
        # The DataFrame for the fangraph ID column is type str.  This is
        # because FanGraph ids can have character values.  Convert all of
        # the input IDs to strings so that it finds the all numeric ones.
        ids_as_str = [str(i) for i in ids]
        return self.df[self.df.fg_id.isin(ids_as_str)]
