"""
Models the game data retrieved via JSON.
"""

import logging
import pprint
import time

from datetime import datetime
from datetime import timedelta
from dateutil import parser

import mlbv.mlbam.mlbapidata as mlbapidata
import mlbv.mlbam.common.config as config
import mlbv.mlbam.common.displayutil as displayutil
import mlbv.mlbam.common.gamedata as gamedata
import mlbv.mlbam.common.request as request
import mlbv.mlbam.common.util as util

from mlbv.mlbam.common.displayutil import ANSI


LOG = logging.getLogger(__name__)


# this map is used to transform the statsweb feed name to something shorter
FEEDTYPE_MAP = {
    'away': 'a',
    'away-resume': 'a-res',
    'away2': 'a2',
    'away3': 'a3',
    'home': 'h',
    'home-resume': 'h-res',
    'home2': 'h2',
    'home3': 'h3',
    'french': 'fr',
    'national': 'nat',
    'in_market_away': 'ima',
    'in_market_home': 'imh',
    'condensed': 'cnd',
    'recap': 'rcp',
    # 'audio-away': 'aud-a',
    # 'audio-home': 'aud-h',
}


class GameDataRetriever:
    """Retrieves and parses game data from statsapi.mlb.com"""

    def _get_games_by_date(self, date_str=None):
        if date_str is None:
            date_str = time.strftime("%Y-%m-%d")

        # https://statsapi.mlb.com/api/v1/schedule?sportId=1&startDate=2018-03-26&endDate=2018-03-26&hydrate=schedule.teams,schedule.linescore,schedule.game.content.media.epg
        # hydrate = 'hydrate=schedule.teams,schedule.linescore,schedule.game.content.media.epg'
        hydrate = 'hydrate=broadcasts(all),game(content(all),editorial(preview,recap)),linescore,team,probablePitcher(note)'
        # hydrate = 'hydrate=linescore,team,game(content(summary,media(epg),editorial(preview,recap),highlights(highlights(items))))'

        # "&hydrate=linescore,team,game(content(summary,media(epg),editorial(preview,recap),highlights(highlights(items))))"

        # hydrate = 'hydrate=linescore,team,game(content(summary,media(epg)),tickets)'
        url = '{0}/api/v1/schedule?sportId=1&startDate={1}&endDate={1}&{2}'.format(config.CONFIG.parser['api_url'], date_str, hydrate)

        json_data = request.request_json(url, 'gamedata-{}'.format(date_str), cache_stale=request.CACHE_SHORT)

        game_records = dict()  # we return this dictionary

        if json_data['dates'] is None or len(json_data['dates']) < 1:
            LOG.debug("_get_games_by_date: no game data for %s", date_str)
            return None

        for game in json_data['dates'][0]['games']:
            # LOG.debug('game: {}'.format(game))
            game_pk_str = str(game['gamePk'])
            game_records[game_pk_str] = dict()
            game_rec = game_records[game_pk_str]
            game_rec['game_pk'] = game_pk_str

            game_rec['abstractGameState'] = str(game['status']['abstractGameState'])  # Preview, Live, Final
            game_rec['codedGameState'] = str(game['status']['codedGameState'])  # is something like: F, O, C, I
            # is something like: Scheduled, Live, Final, In Progress, Critical, Postponed:
            game_rec['detailedState'] = str(game['status']['detailedState'])
            game_rec['doubleHeader'] = str(game['doubleHeader'])
            game_rec['gameNumber'] = str(game['gameNumber'])
            game_rec['mlbdate'] = parser.parse(str(game['gameDate']))

            # Issue #23 handle resumed games
            if 'resumeDate' in game:
                game_rec['resumeDate'] = parser.parse(str(game['resumeDate']))
            if 'resumedFrom' in game:
                game_rec['resumedFrom'] = parser.parse(str(game['resumedFrom']))

            if 'gamesInSeries' in game:
                game_rec['gamesInSeries'] = str(game['gamesInSeries'])
                game_rec['seriesGameNumber'] = str(game['seriesGameNumber'])
            else:
                game_rec['gamesInSeries'] = "0"
                game_rec['seriesGameNumber'] = "0"

            game_rec['linescore'] = dict()
            if 'linescore' in game:
                game_rec['linescore']['raw'] = game['linescore']
                if 'Delayed' in game_rec['detailedState']:
                    game_rec['linescore']['currentInning'] = str(game_rec['detailedState'])
                    game_rec['linescore']['currentInningOrdinal'] = 'Not Started'
                    game_rec['linescore']['inningState'] = ''
                elif 'currentInning' in game['linescore']:
                    game_rec['linescore']['currentInning'] = str(game['linescore']['currentInning'])
                else:
                    game_rec['linescore']['currentInningOrdinal'] = '0'
                if 'currentInningOrdinal' in game['linescore']:
                    game_rec['linescore']['currentInningOrdinal'] = str(game['linescore']['currentInningOrdinal'])
                    if 'inningState' in game['linescore']:
                        game_rec['linescore']['inningState'] = str(game['linescore']['inningState'])[:3]
                    else:
                        game_rec['linescore']['inningState'] = str(game['linescore']['inningHalf'])[:3]
                else:
                    game_rec['linescore']['currentInningOrdinal'] = 'Not Started'
                    game_rec['linescore']['inningState'] = ''
            else:
                game_rec['linescore']['currentInning'] = 'n/a'
                game_rec['linescore']['inningState'] = ''
                game_rec['linescore']['currentInningOrdinal'] = game_rec['detailedState']

            for teamtype in ('home', 'away'):
                # pprint.pprint(game['teams'])
                game_rec[teamtype] = dict()
                # seems to be two different formats for away/home team info(!)
                if 'name' in game['teams'][teamtype]['team'] and 'abbrev' in game['teams'][teamtype]['team']['name']:
                    game_rec[teamtype] = {
                        'abbrev':   str(game['teams'][teamtype]['team']['name']['abbrev']).lower(),
                        'display':  str(game['teams'][teamtype]['team']['name']['display']),
                        'brief':    str(game['teams'][teamtype]['team']['name']['brief']),
                        'full':     str(game['teams'][teamtype]['team']['name']['full']),
                        'league':   str(game['teams'][teamtype]['league']),
                        'division': str(game['teams'][teamtype]['division']),
                    }
                elif 'abbreviation' in game['teams'][teamtype]['team']:
                    game_rec[teamtype] = {
                        'abbrev':   str(game['teams'][teamtype]['team']['abbreviation']).lower(),
                        'display':  str(game['teams'][teamtype]['team']['shortName']),
                        'brief':    str(game['teams'][teamtype]['team']['teamName']),
                        'full':     str(game['teams'][teamtype]['team']['name']),
                        'league':   'n/a',
                        'division': 'n/a',
                    }
                else:
                    LOG.error("Unexpected game['teams'] for teamtype=%s", teamtype)
                    pprint.pprint(game['teams'][teamtype])
                    game_rec[teamtype] = {
                        'abbrev': 'n/a', 'display': 'n/a', 'brief': 'n/a', 'full': 'n/a', 'league': 'n/a', 'division': 'n/a',
                    }

                if 'linescore' in game and teamtype in game['linescore']['teams'] and 'runs' in game['linescore']['teams'][teamtype]:
                    game_rec['linescore'][teamtype] = {
                        'runs':  str(game['linescore']['teams'][teamtype]['runs']),
                        'hits':  str(game['linescore']['teams'][teamtype]['hits']),
                        'errors': str(game['linescore']['teams'][teamtype]['errors']),
                    }
                else:
                    game_rec['linescore'][teamtype] = {'runs':  '0', 'hits':  '0', 'errors': '0'}

            game_rec['favourite'] = gamedata.is_fav(game_rec)

            game_rec['preview'] = list()
            try:
                if 'probablePitcher' in game['teams']['away'] or 'probablePitcher' in game['teams']['home']:
                    game_rec['preview'].append('Probable Pitchers')
                    game_rec['preview'].append('-----------------')
                    for teamtype in ('away', 'home'):
                        if 'probablePitcher' in game['teams'][teamtype]:
                            # if config.CONFIG.parser['info_display_articles'] and 'fullName' in game['teams'][teamtype]['probablePitcher']:
                            if 'fullName' in game['teams'][teamtype]['probablePitcher']:
                                pitcher_name = ' '.join(reversed(game['teams'][teamtype]['probablePitcher']['fullName'].split(','))).strip()
                                if config.CONFIG.parser.getboolean('info_display_articles') and 'note' in game['teams'][teamtype]['probablePitcher']:
                                    note = game['teams'][teamtype]['probablePitcher']['note']
                                    game_rec['preview'].append('{}: {}: {}'.format(game['teams'][teamtype]['team']['teamName'],
                                                                                   pitcher_name, note))
                                else:
                                    game_rec['preview'].append('{}: {}'.format(game['teams'][teamtype]['team']['teamName'], pitcher_name))
                                if config.CONFIG.parser.getboolean('info_display_articles') and teamtype == 'away':
                                    game_rec['preview'].append('')

            except:
                game_rec['preview'] = None

            game_rec['summary'] = list()
            try:
                if 'headline' in game['content']['editorial']['recap']['mlb']:
                    game_rec['summary'].append('SUMMARY: ' + game['content']['editorial']['recap']['mlb']['headline'])
                if 'subhead' in game['content']['editorial']['recap']['mlb']:
                    game_rec['summary'].append('         ' + game['content']['editorial']['recap']['mlb']['subhead'])
                if config.CONFIG.parser.getboolean('info_display_articles', True):
                    if len(game_rec['summary']) > 0:
                        game_rec['summary'].append('')
                    if 'seoTitle' in game['content']['editorial']['recap']['mlb']:
                        # game_rec['summary'].append('TITLE: ' + game['content']['editorial']['recap']['mlb']['seoTitle'])
                        game_rec['summary'].append(game['content']['editorial']['recap']['mlb']['seoTitle'])
                        game_rec['summary'].append('-' * len(game['content']['editorial']['recap']['mlb']['seoTitle']))
                    if 'body' in game['content']['editorial']['recap']['mlb']:
                        game_rec['summary'].append(game['content']['editorial']['recap']['mlb']['body'])
            except:
                game_rec['summary'] = None

            game_rec['feed'] = dict()
            if game_rec['abstractGameState'] == 'Preview':
                continue

            # epg
            if 'media' in game['content'] and 'epg' in game['content']['media']:
                for media in game['content']['media']['epg']:
                    if media['title'] == 'MLBTV':
                        for stream in media['items']:
                            if stream['mediaFeedType'] != 'COMPOSITE' and stream['mediaFeedType'] != 'ISO':
                                feedtype = str(stream['mediaFeedType']).lower()  # home, away, national, french, ...
                                # Fix Issue #23 - resumed games show up on original day media feeds, with multiple entries for home and away
                                # Handle it by naming the feed away-resume, home-resume, etc
                                if 'resumeDate' in game_rec or 'resumedFrom' in game_rec:
                                    resume_feedtype = feedtype + '-resume'
                                    if resume_feedtype not in game_rec['feed']:
                                        feedtype = resume_feedtype
                                else:
                                    # Maybe there is other cases where there is multiple home/away feeds?
                                    extrafeednum = 2
                                    while feedtype in game_rec['feed']:
                                        feedtype += '{}'.format(extrafeednum)
                                game_rec['feed'][feedtype] = dict()
                                if 'mediaId' in stream:
                                    game_rec['feed'][feedtype]['mediaPlaybackId'] = str(stream['mediaId'])
                                    game_rec['feed'][feedtype]['mediaState'] = str(stream['mediaState'])
                                    game_rec['feed'][feedtype]['eventId'] = str(stream['id'])
                                    game_rec['feed'][feedtype]['callLetters'] = str(stream['callLetters'])
                if 'epgAlternate' in game['content']['media']:
                    for media in game['content']['media']['epgAlternate']:
                        if media['title'] == 'Extended Highlights':
                            feedtype = 'condensed'
                            if len(media['items']) > 0:
                                game_rec['feed'][feedtype] = dict()
                                stream = media['items'][0]
                                game_rec['feed'][feedtype]['mediaPlaybackId'] = str(stream['mediaPlaybackId'])
                                for playback_item in stream['playbacks']:
                                    if playback_item['name'] == config.CONFIG.parser['playback_scenario']:
                                        game_rec['feed'][feedtype]['playback_url'] = playback_item['url']
                        elif media['title'] == 'Daily Recap':
                            feedtype = 'recap'
                            if len(media['items']) > 0:
                                game_rec['feed'][feedtype] = dict()
                                stream = media['items'][0]
                                game_rec['feed'][feedtype]['mediaPlaybackId'] = str(stream['mediaPlaybackId'])
                                for playback_item in stream['playbacks']:
                                    if playback_item['name'] == config.CONFIG.parser['playback_scenario']:
                                        game_rec['feed'][feedtype]['playback_url'] = playback_item['url']
                        # elif media['title'] == 'Audio':
                        #     for stream in media['items']:
                        #         feedtype = 'audio-' + str(stream['mediaFeedType']).lower()  # home, away, national, french, ...
                        #         game_rec['feed'][feedtype] = dict()
                        #         game_rec['feed'][feedtype]['mediaPlaybackId'] = str(stream['mediaId'])
                        #         game_rec['feed'][feedtype]['eventId'] = str(stream['id'])
                        #         game_rec['feed'][feedtype]['callLetters'] = str(stream['callLetters'])

        return game_records

    def get_audio_stream_url(self):
        # http://hlsaudio-akc.med2.med.nhl.com/ls04/nhl/2017/12/31/NHL_GAME_AUDIO_TORVGK_M2_VISIT_20171231_1513799214035/master_radio.m3u8
        pass

    def process_game_data(self, game_date, num_days=1):
        game_days_list = list()
        for i in range(0, num_days):
            game_records = self._get_games_by_date(game_date)
            if game_records is not None:
                game_days_list.append((game_date, game_records))
            game_date = datetime.strftime(datetime.strptime(game_date, "%Y-%m-%d") + timedelta(days=1), "%Y-%m-%d")
        return game_days_list

    @staticmethod
    def get_boxscore(game_pk):
        url = '{0}/api/v1/game/{1}/boxscore'.format(config.CONFIG.parser['api_url'], game_pk)
        json_data = request.request_json(url, 'boxscore-{}'.format(game_pk), cache_stale=request.CACHE_SHORT)
        return json_data


class GameDatePresenter:
    """Formats game data for CLI output."""

    def __get_feeds_for_display(self, game_rec):
        non_highlight_feeds = list()
        use_short_feeds = config.CONFIG.parser.getboolean('use_short_feeds', True)
        for feed in sorted(game_rec['feed'].keys()):
            if feed not in config.HIGHLIGHT_FEEDTYPES and not feed.startswith('audio-'):
                if use_short_feeds:
                    non_highlight_feeds.append(gamedata.convert_feedtype_to_short(feed, FEEDTYPE_MAP))
                else:
                    non_highlight_feeds.append(feed)
        highlight_feeds = list()
        for feed in game_rec['feed'].keys():
            if feed in config.HIGHLIGHT_FEEDTYPES and not feed.startswith('audio-'):
                if use_short_feeds:
                    highlight_feeds.append(gamedata.convert_feedtype_to_short(feed, FEEDTYPE_MAP))
                else:
                    highlight_feeds.append(feed)
        if len(highlight_feeds) > 0:
            return '{} {}'.format(','.join(non_highlight_feeds), ','.join(highlight_feeds))
        return '{}'.format(','.join(non_highlight_feeds))

    @staticmethod
    def _get_header(border, game_date, show_scores, show_linescore):
        header = list()
        date_hdr = '{:7}{} {}'.format('', game_date, datetime.strftime(datetime.strptime(game_date, "%Y-%m-%d"), "%a"))
        if show_scores:
            if show_linescore:
                header.append("{:56}".format(date_hdr))
                header.append('{c_on}{dash}{c_off}'
                              .format(c_on=border.border_color, dash=border.thickdash*92, c_off=border.color_off))
            else:
                header.append("{:48} {:^7} {pipe} {:^5} {pipe} {:^9} {pipe} {}"
                              .format(date_hdr, 'Series', 'Score', 'State', 'Feeds', pipe=border.pipe))
                header.append("{c_on}{}{pipe}{}{pipe}{}{pipe}{}{c_off}"
                              .format(border.thickdash * 57, border.thickdash * 7, border.thickdash * 11, border.thickdash * 16,
                                      pipe=border.junction, c_on=border.border_color, c_off=border.color_off))
        else:
            header.append("{:48} {:^7} {pipe} {:^9} {pipe} {}".format(date_hdr, 'Series', 'State', 'Feeds', pipe=border.pipe))
            header.append("{c_on}{}{pipe}{}{pipe}{}{c_off}"
                          .format(border.thickdash * 57, border.thickdash * 11, border.thickdash * 16,
                                  pipe=border.junction, c_on=border.border_color, c_off=border.color_off))
        return header

    def display_game_data(self, game_date, game_records, filter, show_info):
        show_scores = config.CONFIG.parser.getboolean('scores')
        # might as well show linescore if show_info is given
        show_linescore = show_scores and (config.CONFIG.parser.getboolean('linescore') or config.CONFIG.parser.getboolean('boxscore') or show_info)
        show_boxscore = show_scores and config.CONFIG.parser.getboolean('boxscore')
        border = displayutil.Border(use_unicode=config.UNICODE)
        if game_records is None:
            # outl.append("No game data for {}".format(game_date))
            LOG.info("No game data for {}".format(game_date))
            # LOG.info("No game data to display")
            return

        outl = list()  # holds list of strings for output

        # print header
        header = self._get_header(border, game_date, show_scores, show_linescore)
        outl.extend(header)

        games_displayed_count = 0
        for game_pk in game_records:
            if gamedata.apply_filter(game_records[game_pk], filter, mlbapidata.FILTERS) is not None:
                games_displayed_count += 1
                outl.extend(self._display_game_details(header, game_pk, game_records[game_pk],
                                                       show_linescore,
                                                       show_boxscore,
                                                       show_info,
                                                       games_displayed_count))
        if games_displayed_count > 0:
            for line in outl:
                print(line)

    def _display_game_details(self, header, game_pk, game_rec, show_linescore, show_boxscore, show_info, games_displayed_count):
        show_scores = config.CONFIG.parser.getboolean('scores')
        outl = list()
        if games_displayed_count > 1:
            if show_info or show_linescore or show_boxscore:
                outl.append('')
            if show_info:
                outl.extend(header)
        border = displayutil.Border(use_unicode=config.UNICODE)
        color_on = ''
        color_off = ''
        # odd_even = games_displayed_count % 2
        # if odd_even:
        #     color_on = ANSI.fg('yellow')
        # else:
        #     color_on = display'reset'.ANSI.fg('lightblue')
        color_off = ANSI.reset()
        if gamedata.is_fav(game_rec):
            if config.CONFIG.parser['fav_colour'] != '':
                color_on = ANSI.fg(config.CONFIG.parser['fav_colour'])
                color_off = ANSI.reset()
        if game_rec['abstractGameState'] == 'Live':
            color_on += ANSI.control_code('bold')
            color_off = ANSI.reset()
        if game_rec['doubleHeader'] == 'N':
            series_info = "{sgn}/{gis}".format(sgn=game_rec['seriesGameNumber'], gis=game_rec['gamesInSeries'])
        else:
            # series_info = "DH{gn} {sgn}/{gis}".format(sgn=game_rec['seriesGameNumber'],
            #                                           gis=game_rec['gamesInSeries'],
            #                                           gn=game_rec['gameNumber'])
            series_info = "DH-{gn}".format(gn=game_rec['gameNumber'])

        game_info_str = "{time}: {a1} ({a2}) at {h1} ({h2})"\
            .format(time=util.convert_time_to_local(game_rec['mlbdate']),
                    a1=game_rec['away']['display'], a2=game_rec['away']['abbrev'].upper(),
                    h1=game_rec['home']['display'], h2=game_rec['home']['abbrev'].upper())
        game_state = ''
        game_state_color_on = color_on
        game_state_color_off = color_off

        if game_rec['abstractGameState'] in ('Preview', ):
            if game_rec['detailedState'] != 'Scheduled':
                if 'Delayed' in game_rec['detailedState']:
                    game_state = 'Delayed'
                else:
                    game_state = game_rec['detailedState']
        else:
            if show_scores:
                if game_rec['detailedState'] in ('Critical', ):
                    game_state_color_on = ANSI.fg(config.CONFIG.parser['game_critical_colour'])
                    game_state_color_off = ANSI.reset()
                if game_rec['detailedState'] in ('Final', ):
                    game_state = game_rec['detailedState']
                    if 'currentInning' in game_rec['linescore'] and int(game_rec['linescore']['currentInning']) != 9:
                        game_state += '({})'.format(game_rec['linescore']['currentInning'])
                else:
                    if game_rec['linescore']['inningState'] != '':
                        game_state = '{} {}'.format(game_rec['linescore']['inningState'].title(),
                                                    game_rec['linescore']['currentInningOrdinal'])
                    else:
                        game_state = game_rec['linescore']['currentInningOrdinal']
            else:
                game_state = game_rec['abstractGameState']
                if 'In Progress - ' in game_rec['detailedState']:
                    game_state = game_rec['detailedState'].split('In Progress - ')[-1]
                elif game_rec['detailedState'] not in ('Live', 'Final', 'Scheduled', 'In Progress'):
                    game_state = game_rec['detailedState']

        if show_scores:
            score = ''
            if game_rec['abstractGameState'] not in ('Preview', ) and game_rec['detailedState'] not in ('Postponed', ):
                score = '{}-{}'.format(game_rec['linescore']['away']['runs'], game_rec['linescore']['home']['runs'])

            # linescore
            if show_linescore:
                if games_displayed_count > 1 and not show_info:
                    outl.append('{coloron}{dash}{coloroff}'.format(coloron=ANSI.fg('darkgrey'),
                                                                   dash=border.dash*92,
                                                                   coloroff=ANSI.reset()))
                linescore_dict = self._format_linescore(game_rec)
                """
                18:05: LA Dodgers (LAD) at San Francisco (SF)            1  2  3  4  5  6  7  8  9 10 11 12 13 14  R  H  E
                1/2    Final(14): 5-7                              LAD   0  0  1  0  0  2  1  0  0  0  0  0  0  1  5 12  0
                       Feeds: a,h / cnd,rcp                        SF    1  0  0  2  0  1  0  0  0  0  0  0  0  3  7 17  1
                """
                line_fmt = "{coloron}{ginfo:<50} {lscore}{coloroff}"
                # if game_rec['abstractGameState'] not in ('Live', 'Final'):  # or game_rec['detailedState'] in ('Postponed', ):
                #     outl.append(line_fmt.format(coloron=color_on, coloroff=color_off, ginfo=game_info_str, lscore=''))
                #     return outl

                outl.append(line_fmt.format(coloron=color_on, coloroff=color_off,
                                            ginfo=game_info_str, lscore=linescore_dict['header'], pipe=border.pipe))
                if game_state == '':
                    # game_info_str = '{series:7}Not Started'.format(series=series_info)
                    game_info_str = '{series:7}'.format(series=series_info)
                else:
                    if game_rec['abstractGameState'] in ('Live',) \
                            and game_rec['linescore']['inningState'] != 'Mid' and 'raw' in game_rec['linescore']:
                        outs_info = ', {} out'.format(game_rec['linescore']['raw']['outs'])
                    else:
                        outs_info = ''
                    if score:
                        game_info_str = '{series:7}{gstate}: {score}{outs}'.format(series=series_info,
                                                                                   gstate=game_state, score=score, outs=outs_info)
                    else:
                        game_info_str = '{series:7}{gstate}'.format(series=series_info, gstate=game_state)
                outl.append(line_fmt.format(coloron=color_on, coloroff=color_off,
                                            ginfo=game_info_str, lscore=linescore_dict['away']))

                feeds = self.__get_feeds_for_display(game_rec)
                if feeds:
                    game_info_str = '{:7}Feeds: {feeds}'.format('', feeds=self.__get_feeds_for_display(game_rec))
                    outl.append(line_fmt.format(coloron=color_on, coloroff=color_off,
                                                ginfo=game_info_str, lscore=linescore_dict['home']))
                else:
                    outl.append(line_fmt.format(coloron=color_on, coloroff=color_off,
                                                ginfo='', lscore=linescore_dict['home']))
            else:
                # single-line game score
                outl.append(("{coloron}{ginfo:<48} {series:^7}{coloroff} "
                             "{pipe} {coloron}{score:^5}{coloroff} {pipe} "
                             "{gscoloron}{gstate:<9}{gscoloroff} {pipe} {coloron}{feeds}{coloroff}")
                            .format(coloron=color_on, coloroff=color_off,
                                    ginfo=game_info_str, series=series_info, score=score,
                                    gscoloron=game_state_color_on, gstate=game_state, gscoloroff=game_state_color_off,
                                    feeds=self.__get_feeds_for_display(game_rec), pipe=border.pipe))
        else:  # no scores
            outl.append(("{coloron}{ginfo:<48} {series:^7}{coloroff} {pipe} "
                         "{coloron}{gstate:^9}{coloroff} {pipe} {coloron}{feeds}{coloroff}")
                        .format(coloron=color_on, coloroff=color_off,
                                ginfo=game_info_str, series=series_info, gstate=game_state,
                                feeds=self.__get_feeds_for_display(game_rec), pipe=border.pipe))

        if 'resumeDate' in game_rec:
            outl.append('  --> Will resume on: {} at {}'.format(datetime.strftime(game_rec['resumeDate'], '%Y-%m-%d'),
                                                                util.convert_time_to_local(game_rec['resumeDate'])))
        if 'resumedFrom' in game_rec:
            outl.append('  --> Resumed from: {} at {}'.format(datetime.strftime(game_rec['resumedFrom'], '%Y-%m-%d'),
                                                              util.convert_time_to_local(game_rec['resumedFrom'])))

        if show_info:
            # found_info = False
            for text_type in ('summary', 'preview'):
                if text_type in game_rec and game_rec[text_type]:
                    # if text_type == 'summary':
                    #     outl.append('')
                    outl.append('')
                    for line in game_rec[text_type]:
                        outl.append('{coloron}{text}{coloroff}'.format(coloron=color_on,
                                                                       text=util.strip_html_tags(line, True),
                                                                       coloroff=color_off))
                    # outl.append('')
                    # only show one of summary or preview
                    break

        if show_boxscore:
            outl.extend(self._get_formatted_boxscore(game_rec, color_on, color_off))

        return outl

    def _format_linescore(self, game_rec):
        """Returns a dictionary indexed by keys: 'header', 'away', 'home'
             1  2  3  4  5  6  7  8  9 10 11  R  H  E
        TOR  1  0  0  0  0  0  0  3  0  0  0  4  8  0
        NYY  0  0  0  0  1  0  0  0  4  0  0  5  8  0
        """
        if 'raw' in game_rec['linescore']:
            linescore_json = game_rec['linescore']['raw']
        else:
            return {'header': '', 'away': '', 'home': ''}
        outd = dict()
        outd['header'] = '{title:<4}'.format(title='')
        outd['away'] = '{title:<4}'.format(title=game_rec['away']['abbrev'].upper())
        outd['home'] = '{title:<4}'.format(title=game_rec['home']['abbrev'].upper())
        if 'currentInning' in linescore_json:
            current_inning = int(linescore_json['currentInning'])
        else:
            current_inning = 0
        inning_fmt = '{:>3}'
        # inning_fmt = '{:>2}'
        # if current_inning > 9:
        #     inning_fmt = '{:>3}'
        for inning in linescore_json['innings']:
            outd['header'] += inning_fmt.format(inning['num'])
            for team in ('away', 'home'):
                if 'runs' in inning[team]:
                    outd[team] += inning_fmt.format(inning[team]['runs'])
                else:
                    outd[team] += inning_fmt.format('')
        for inning_num in range(current_inning+1, 10):  # fill in remaining innings, if any
            # inning_fmt = '{:>2}'
            outd['header'] += inning_fmt.format(inning_num)
            outd['away'] += inning_fmt.format('')
            outd['home'] += inning_fmt.format('')
        # outd['header'] += '{:>3}{:>3}{:>3}'.format('R', 'H', 'E')
        outd['header'] += ' '
        for inning_hdr in ('R', 'H', 'E'):
            outd['header'] += inning_fmt.format(inning_hdr)
        for team in ('away', 'home'):
            if 'teams' in linescore_json and team in linescore_json['teams'] \
                    and 'runs' in linescore_json['teams'][team]:
                outd[team] += ' '
                for inning_val in (linescore_json['teams'][team]['runs'],
                                   linescore_json['teams'][team]['hits'],
                                   linescore_json['teams'][team]['errors']):
                    outd[team] += inning_fmt.format(inning_val)
        return outd

    def _get_formatted_boxscore(self, game_rec, color_on, color_off):
        outl = list()
        outl.append('')
        # fetch boxscore
        json_data = GameDataRetriever.get_boxscore(game_rec['game_pk'])
        batfmt = '{coloron}{num:<2} {name:<30} {pos:>3}  {ab:>3} {hit:>3} {bb:>3} {so:>3} {run:>3} {hr:>3} {rbi:>3} {lob:>3}   {avg:>5} {ops:>5}{coloroff}'
        pitchfmt = '{coloron}{num:<2} {name:<30} {pos:>3}  {ip:>4} {hit:>3} {run:>3} {er:>3} {bb:>3} {so:>3} {hr:>3}   {era:>5} {whip:>5}{coloroff}'
        for teamtype in ('away', 'home'):
            outl.append('{coloron}{name}{coloroff}'.format(coloron=color_on, coloroff=color_off,
                                                           name=json_data['teams'][teamtype]['team']['name']))
            outl.append('{coloron}{name}{coloroff}'.format(coloron=color_on, coloroff=color_off,
                                                           name='-' * len(json_data['teams'][teamtype]['team']['name'])))
            # batters
            outl.append(batfmt.format(coloron=color_on, coloroff=color_off,
                                      num='', name='BATTING', pos='',
                                      ab='AB', hit='H', bb='BB', so='SO', run='R', hr='HR', rbi='RBI',
                                      lob='LOB', avg='AVG', ops='OPS'))
            index = 0
            for batter in json_data['teams'][teamtype]['batters']:
                index += 1
                player_info = json_data['teams'][teamtype]['players']['ID' + str(batter)]
                stats = player_info['stats']['batting']
                season_stats = player_info['seasonStats']['batting']
                if stats:
                    outl.append(batfmt.format(coloron=color_on, coloroff=color_off, num=index,
                                              name=player_info['person']['fullName'],
                                              pos=player_info['position']['abbreviation'],
                                              ab=stats['atBats'], run=stats['runs'], hit=stats['hits'],
                                              hr=stats['homeRuns'],
                                              rbi=stats['rbi'], bb=stats['baseOnBalls'], so=stats['strikeOuts'],
                                              lob=stats['leftOnBase'],
                                              avg=season_stats['avg'], ops=season_stats['ops']))
            team_stats = json_data['teams'][teamtype]['teamStats']
            if team_stats and 'batting' in team_stats:
                team_batting = team_stats['batting']
                outl.append(batfmt.format(coloron=color_on, coloroff=color_off, num='',
                                          name='TOTALS',
                                          pos='',
                                          ab=team_batting['atBats'], run=team_batting['runs'], hit=team_batting['hits'],
                                          hr=team_batting['homeRuns'],
                                          rbi=team_batting['rbi'], bb=team_batting['baseOnBalls'], so=team_batting['strikeOuts'],
                                          lob=team_batting['leftOnBase'],
                                          avg=team_batting['avg'], ops=team_batting['ops']))
            outl.append('')

            # pitchers
            outl.append(pitchfmt.format(coloron=color_on, coloroff=color_off, num='', name='PITCHING', pos='',
                                        ip='IP', hit='H', run='R', er='ER', bb='BB', so='SO', hr='HR',
                                        era='ERA', whip='WHIP'))
            index = 0
            for pitcher in json_data['teams'][teamtype]['pitchers']:
                index += 1
                player_info = json_data['teams'][teamtype]['players']['ID' + str(pitcher)]
                stats = player_info['stats']['pitching']
                season_stats = player_info['seasonStats']['pitching']
                if stats:
                    outl.append(pitchfmt.format(coloron=color_on, coloroff=color_off, num=index,
                                                name=player_info['person']['fullName'],
                                                pos=player_info['position']['abbreviation'],
                                                ip=stats['inningsPitched'],
                                                hit=stats['hits'],
                                                run=stats['runs'],
                                                er=stats['earnedRuns'],
                                                bb=stats['baseOnBalls'],
                                                so=stats['strikeOuts'],
                                                hr=stats['homeRuns'],
                                                era=season_stats['era'],
                                                whip=season_stats['whip']))
            if team_stats and 'pitching' in team_stats:
                team_pitching = team_stats['pitching']
                outl.append(pitchfmt.format(coloron=color_on, coloroff=color_off, num='',
                                            name='TOTALS',
                                            pos='',
                                            ip=team_pitching['inningsPitched'],
                                            hit=team_pitching['hits'],
                                            run=team_pitching['runs'],
                                            er=team_pitching['earnedRuns'],
                                            bb=team_pitching['baseOnBalls'],
                                            so=team_pitching['strikeOuts'],
                                            hr=team_pitching['homeRuns'],
                                            era=team_pitching['era'],
                                            whip=team_pitching['whip']))
            outl.append('')

            # team game info
            for info in json_data['teams'][teamtype]['info']:
                if 'title' in info:
                    outl.append('{coloron}{name}{coloroff}'.format(coloron=color_on, coloroff=color_off, name=info['title']))
                    if 'fieldList' in info:
                        for field in info['fieldList']:
                            if 'label' in field and 'value' in field:
                                outl.append('{coloron}{label}: {value}{coloroff}'.format(coloron=color_on, coloroff=color_off,
                                                                                         label=field['label'], value=field['value']))
                    outl.append('')

        # info
        if json_data['info']:
            # excluded_labels = ('Venue', )
            excluded_labels = ()
            # title = 'Other Game info:'
            # outl.append('{coloron}{name}{coloroff}'.format(coloron=color_on, coloroff=color_off, name=title))
            # outl.append('{coloron}{name}{coloroff}'.format(coloron=color_on, coloroff=color_off, name='-' * len(title)))
            weather = { 'Weather': '', 'Wind': '' }
            game_length = { 'First pitch': '', 'T': '' }
            venue = { 'Att': '', 'Venue': '' }
            for info in json_data['info']:
                if 'label' in info and 'value' in info and info['label'] not in excluded_labels:
                    if info['label'] == 'Weather':
                        weather['Weather'] = info['value']
                    elif info['label'] == 'Wind':
                        weather['Wind'] = info['value']
                    elif info['label'] == 'First pitch':
                        game_length['First pitch'] = info['value']
                    elif info['label'] == 'T':
                        game_length['T'] = info['value']
                    elif info['label'] == 'Att':
                        venue['Att'] = info['value']
                    elif info['label'] == 'Venue':
                        venue['Venue'] = info['value']
                    else:
                        outl.append('{coloron}{label}: {value}{coloroff}'.format(coloron=color_on, coloroff=color_off,
                                                                                 label=info['label'], value=info['value']))
            if weather['Weather'] or weather['Wind']:
                outl.append('{coloron}Weather: {weather}, Wind: {wind}{coloroff}'.format(coloron=color_on, coloroff=color_off,
                                                                                         weather=weather['Weather'],
                                                                                         wind=weather['Wind']))
            if game_length['First pitch'] or game_length['T']:
                outl.append('{coloron}First pitch: {fp}  Game length: {time}'\
                            .format(coloron=color_on, coloroff=color_off,
                                    fp=game_length['First pitch'],
                                    time=game_length['T']))
            if venue['Att'] or venue['Venue']:
                outl.append('{coloron}Venue: {venue}  Att: {att}{coloroff}'\
                            .format(coloron=color_on, coloroff=color_off,
                                    venue=venue['Venue'],
                                    att=venue['Att']))

        return outl