class PlaybackManager:
    _shared_state = {}

    def __init__(self):
        self.__dict__ = self._shared_state
        self.api = Api()
        self.play_item = PlayItem()
        self.state = State()
        self.player = Player()
        self.demo = DemoOverlay(12005)

    def log(self, msg, level=2):
        ulog(msg, name=self.__class__.__name__, level=level)

    def handle_demo(self):
        if get_setting_bool('enableDemoMode'):
            self.log(
                'Up Next DEMO mode enabled, skipping automatically to the end',
                0)
            self.demo.show()
            try:
                total_time = self.player.getTotalTime()
                self.player.seekTime(total_time - 15)
            except RuntimeError as exc:
                self.log('Failed to seekTime(): %s' % exc, 0)
        else:
            self.demo.hide()

    def launch_up_next(self):
        enable_playlist = get_setting_bool('enablePlaylist')
        episode, source = self.play_item.get_next()
        self.log('Playlist setting: %s' % enable_playlist)
        if source == 'playlist' and not enable_playlist:
            self.log('Playlist integration disabled', 2)
            return
        if not episode:
            # No episode get out of here
            self.log('Error: no episode could be found to play next...exiting',
                     1)
            return
        self.log('episode details %s' % episode, 2)
        play_next, keep_playing = self.launch_popup(episode, source)
        self.state.playing_next = play_next

        # Dequeue and stop playback if not playing next file
        if not play_next and self.state.queued:
            self.state.queued = self.api.dequeue_next_item()
        if not keep_playing:
            self.log('Stopping playback', 2)
            self.player.stop()

        self.api.reset_addon_data()

    def launch_popup(self, episode, source=None):
        episode_id = episode.get('episodeid')
        no_play_count = episode.get('playcount') is None or episode.get(
            'playcount') == 0
        include_play_count = True if self.state.include_watched else no_play_count
        if not include_play_count or self.state.current_episode_id == episode_id:
            # play_next = False
            # keep_playing = True
            # return play_next, keep_playing
            # Don't play next file, but keep playing current file
            return False, True

        # Add next file to playlist if existing playlist is not being used
        if source != 'playlist':
            self.state.queued = self.api.queue_next_item(episode)

        # We have a next up episode choose mode
        if get_setting_int('simpleMode') == 0:
            next_up_page = UpNext('script-upnext-upnext-simple.xml',
                                  addon_path(), 'default', '1080i')
            still_watching_page = StillWatching(
                'script-upnext-stillwatching-simple.xml', addon_path(),
                'default', '1080i')
        else:
            next_up_page = UpNext('script-upnext-upnext.xml', addon_path(),
                                  'default', '1080i')
            still_watching_page = StillWatching(
                'script-upnext-stillwatching.xml', addon_path(), 'default',
                '1080i')

        showing_next_up_page, showing_still_watching_page = self.show_popup_and_wait(
            episode, next_up_page, still_watching_page)
        should_play_default, should_play_non_default = self.extract_play_info(
            next_up_page, showing_next_up_page, showing_still_watching_page,
            still_watching_page)
        if not self.state.track:
            self.log('exit launch_popup early due to disabled tracking', 2)
            # play_next = False
            # keep_playing = showing_next_up_page
            # return play_next, keep_playing
            # Don't play next file
            # Stop if Still Watching? popup was shown to prevent unwanted playback when using FF or skip
            return False, showing_next_up_page

        play_item_option_1 = (should_play_default
                              and self.state.play_mode == 0)
        play_item_option_2 = (should_play_non_default
                              and self.state.play_mode == 1)
        if not play_item_option_1 and not play_item_option_2:
            # play_next = False
            # keep_playing = next_up_page.is_cancel() if showing_next_up_page else still_watching_page.is_cancel()
            # keep_playing = keep_playing and not get_setting_bool('stopAfterClose')
            # return play_next, keep_playing
            # Don't play next file, and stop current file if no playback option selected
            return False, ((next_up_page.is_cancel() if showing_next_up_page
                            else still_watching_page.is_cancel())
                           and not get_setting_bool('stopAfterClose'))

        self.log('playing media episode', 2)
        # Signal to trakt previous episode watched
        event(message='NEXTUPWATCHEDSIGNAL',
              data=dict(episodeid=self.state.current_episode_id),
              encoding='base64')
        if source == 'playlist' or self.state.queued:
            # Play playlist media
            if should_play_non_default:
                # Only start the next episode if the user asked for it specifically
                self.player.playnext()
        elif self.api.has_addon_data():
            # Play add-on media
            self.api.play_addon_item()
        else:
            # Play local media
            self.api.play_kodi_item(episode)

        # play_next = True
        # keep_playing = True
        # return play_next, keep_playing
        # Play next file, and keep playing current file
        return True, True

    def show_popup_and_wait(self, episode, next_up_page, still_watching_page):
        try:
            play_time = self.player.getTime()
            total_time = self.player.getTotalTime()
        except RuntimeError:
            self.log('exit early because player is no longer running', 2)
            return False, False
        progress_step_size = calculate_progress_steps(total_time - play_time)
        next_up_page.set_item(episode)
        next_up_page.set_progress_step_size(progress_step_size)
        still_watching_page.set_item(episode)
        still_watching_page.set_progress_step_size(progress_step_size)
        played_in_a_row_number = get_setting_int('playedInARow')
        self.log('played in a row settings %s' % played_in_a_row_number, 2)
        self.log('played in a row %s' % self.state.played_in_a_row, 2)
        showing_next_up_page = False
        showing_still_watching_page = False
        if int(self.state.played_in_a_row) <= int(played_in_a_row_number):
            self.log(
                'showing next up page as played in a row is %s' %
                self.state.played_in_a_row, 2)
            next_up_page.show()
            set_property('service.upnext.dialog', 'true')
            showing_next_up_page = True
        else:
            self.log(
                'showing still watching page as played in a row %s' %
                self.state.played_in_a_row, 2)
            still_watching_page.show()
            set_property('service.upnext.dialog', 'true')
            showing_still_watching_page = True
        while (self.player.isPlaying() and (total_time - play_time > 1)
               and not next_up_page.is_cancel()
               and not next_up_page.is_watch_now()
               and not still_watching_page.is_still_watching()
               and not still_watching_page.is_cancel()):
            try:
                play_time = self.player.getTime()
                total_time = self.player.getTotalTime()
            except RuntimeError:
                if showing_next_up_page:
                    next_up_page.close()
                    showing_next_up_page = False
                if showing_still_watching_page:
                    still_watching_page.close()
                    showing_still_watching_page = False
                break

            remaining = total_time - play_time
            runtime = episode.get('runtime')
            if not self.state.pause:
                if showing_next_up_page:
                    next_up_page.update_progress_control(remaining=remaining,
                                                         runtime=runtime)
                elif showing_still_watching_page:
                    still_watching_page.update_progress_control(
                        remaining=remaining, runtime=runtime)
            sleep(100)
        return showing_next_up_page, showing_still_watching_page

    def extract_play_info(self, next_up_page, showing_next_up_page,
                          showing_still_watching_page, still_watching_page):
        if showing_next_up_page:
            next_up_page.close()
            should_play_default = not next_up_page.is_cancel()
            should_play_non_default = next_up_page.is_watch_now()
        elif showing_still_watching_page:
            still_watching_page.close()
            should_play_default = still_watching_page.is_still_watching()
            should_play_non_default = still_watching_page.is_still_watching()
        else:
            # FIXME: This is a workaround until we handle this better (see comments in #142)
            return False, False

        if next_up_page.is_watch_now(
        ) or still_watching_page.is_still_watching():
            self.state.played_in_a_row = 1
        else:
            self.state.played_in_a_row += 1
        clear_property('service.upnext.dialog')
        return should_play_default, should_play_non_default
class PlaybackManager:
    _shared_state = {}

    def __init__(self):
        self.__dict__ = self._shared_state
        self.api = Api()
        self.play_item = PlayItem()
        self.state = State()
        self.player = Player()

    def log(self, msg, level=2):
        ulog(msg, name=self.__class__.__name__, level=level)

    def launch_up_next(self):
        playlist_item = get_setting_bool('enablePlaylist')
        episode = self.play_item.get_next()
        self.log('Playlist setting: %s' % playlist_item)
        if episode and not playlist_item:
            self.log('Playlist integration disabled', 2)
            return
        if not episode:
            playlist_item = False
            episode = self.play_item.get_episode()
            if episode is None:
                # No episode get out of here
                self.log(
                    'Error: no episode could be found to play next...exiting',
                    1)
                return
        self.log('episode details %s' % episode, 2)
        self.launch_popup(episode, playlist_item)
        self.api.reset_addon_data()

    def launch_popup(self, episode, playlist_item):
        episode_id = episode.get('episodeid')
        no_play_count = episode.get('playcount') is None or episode.get(
            'playcount') == 0
        include_play_count = True if self.state.include_watched else no_play_count
        if not include_play_count or self.state.current_episode_id == episode_id:
            return

        # We have a next up episode choose mode
        if get_setting_int('simpleMode') == 0:
            next_up_page = UpNext('script-upnext-upnext-simple.xml',
                                  addon_path(), 'default', '1080i')
            still_watching_page = StillWatching(
                'script-upnext-stillwatching-simple.xml', addon_path(),
                'default', '1080i')
        else:
            next_up_page = UpNext('script-upnext-upnext.xml', addon_path(),
                                  'default', '1080i')
            still_watching_page = StillWatching(
                'script-upnext-stillwatching.xml', addon_path(), 'default',
                '1080i')

        showing_next_up_page, showing_still_watching_page = self.show_popup_and_wait(
            episode, next_up_page, still_watching_page)
        should_play_default, should_play_non_default = self.extract_play_info(
            next_up_page, showing_next_up_page, showing_still_watching_page,
            still_watching_page)
        if not self.state.track:
            self.log('exit launch_popup early due to disabled tracking', 2)
            return
        play_item_option_1 = (should_play_default
                              and self.state.play_mode == 0)
        play_item_option_2 = (should_play_non_default
                              and self.state.play_mode == 1)
        if not play_item_option_1 and not play_item_option_2:
            return

        self.log('playing media episode', 2)
        # Signal to trakt previous episode watched
        event(message='NEXTUPWATCHEDSIGNAL',
              data=dict(episodeid=self.state.current_episode_id),
              encoding='base64')
        if playlist_item:
            try:
                # Play playlist media
                self.player.seekTime(self.player.getTotalTime())
            except RuntimeError:
                pass
        elif self.api.has_addon_data():
            # Play add-on media
            self.api.play_addon_item()
        else:
            # Play local media
            self.api.play_kodi_item(episode)

    def show_popup_and_wait(self, episode, next_up_page, still_watching_page):
        try:
            play_time = self.player.getTime()
            total_time = self.player.getTotalTime()
        except RuntimeError:
            self.log('exit early because player is no longer running', 2)
            return False, False
        progress_step_size = calculate_progress_steps(total_time - play_time)
        next_up_page.set_item(episode)
        next_up_page.set_progress_step_size(progress_step_size)
        still_watching_page.set_item(episode)
        still_watching_page.set_progress_step_size(progress_step_size)
        played_in_a_row_number = get_setting_int('playedInARow')
        self.log('played in a row settings %s' % played_in_a_row_number, 2)
        self.log('played in a row %s' % self.state.played_in_a_row, 2)
        showing_next_up_page = False
        showing_still_watching_page = False
        if int(self.state.played_in_a_row) <= int(played_in_a_row_number):
            self.log(
                'showing next up page as played in a row is %s' %
                self.state.played_in_a_row, 2)
            next_up_page.show()
            set_property('service.upnext.dialog', 'true')
            showing_next_up_page = True
        else:
            self.log(
                'showing still watching page as played in a row %s' %
                self.state.played_in_a_row, 2)
            still_watching_page.show()
            set_property('service.upnext.dialog', 'true')
            showing_still_watching_page = True
        while (self.player.isPlaying() and (total_time - play_time > 1)
               and not next_up_page.is_cancel()
               and not next_up_page.is_watch_now()
               and not still_watching_page.is_still_watching()
               and not still_watching_page.is_cancel()):
            try:
                play_time = self.player.getTime()
                total_time = self.player.getTotalTime()
            except RuntimeError:
                if showing_next_up_page:
                    next_up_page.close()
                    showing_next_up_page = False
                if showing_still_watching_page:
                    still_watching_page.close()
                    showing_still_watching_page = False
                break

            remaining = total_time - play_time
            runtime = episode.get('runtime')
            if not self.state.pause:
                if showing_next_up_page:
                    next_up_page.update_progress_control(remaining=remaining,
                                                         runtime=runtime)
                elif showing_still_watching_page:
                    still_watching_page.update_progress_control(
                        remaining=remaining, runtime=runtime)
            sleep(100)
        return showing_next_up_page, showing_still_watching_page

    def extract_play_info(self, next_up_page, showing_next_up_page,
                          showing_still_watching_page, still_watching_page):
        if showing_next_up_page:
            next_up_page.close()
            should_play_default = not next_up_page.is_cancel()
            should_play_non_default = next_up_page.is_watch_now()
        elif showing_still_watching_page:
            still_watching_page.close()
            should_play_default = still_watching_page.is_still_watching()
            should_play_non_default = still_watching_page.is_still_watching()
        else:
            # FIXME: This is a workaround until we handle this better (see comments in #142)
            return False, False

        if next_up_page.is_watch_now(
        ) or still_watching_page.is_still_watching():
            self.state.played_in_a_row = 1
        else:
            self.state.played_in_a_row += 1
        clear_property('service.upnext.dialog')
        return should_play_default, should_play_non_default