1# -*- coding: utf-8 -*-
2from __future__ import unicode_literals
3
4import time
5
6from . import docs
7from .content import SubredditContent
8from .page import Page, PageController, logged_in
9from .objects import Navigator, Command
10from .exceptions import TemporaryFileError
11
12
13class SubredditController(PageController):
14    character_map = {}
15
16
17class SubredditPage(Page):
18    BANNER = docs.BANNER_SUBREDDIT
19    FOOTER = docs.FOOTER_SUBREDDIT
20
21    name = 'subreddit'
22
23    def __init__(self, reddit, term, config, oauth, name):
24        """
25        Params:
26            name (string): Name of subreddit to open
27        """
28        super(SubredditPage, self).__init__(reddit, term, config, oauth)
29
30        self.controller = SubredditController(self, keymap=config.keymap)
31        self.content = SubredditContent.from_name(reddit, name, term.loader)
32        self.nav = Navigator(self.content.get)
33        self.toggled_subreddit = None
34
35    def handle_selected_page(self):
36        """
37        Open all selected pages in subwindows except other subreddit pages.
38        """
39        if not self.selected_page:
40            pass
41        elif self.selected_page.name in ('subscription', 'submission', 'inbox'):
42            # Launch page in a subwindow
43            self.selected_page = self.selected_page.loop()
44        elif self.selected_page.name == 'subreddit':
45            # Replace the current page
46            self.active = False
47        else:
48            raise RuntimeError(self.selected_page.name)
49
50    def refresh_content(self, order=None, name=None):
51        """
52        Re-download all submissions and reset the page index
53        """
54        order = order or self.content.order
55
56        # Preserve the query if staying on the current page
57        if name is None:
58            query = self.content.query
59        else:
60            query = None
61
62        name = name or self.content.name
63
64        # Hack to allow an order specified in the name by prompt_subreddit() to
65        # override the current default
66        if order == 'ignore':
67            order = None
68
69        with self.term.loader('Refreshing page'):
70            self.content = SubredditContent.from_name(
71                self.reddit, name, self.term.loader, order=order, query=query)
72        if not self.term.loader.exception:
73            self.nav = Navigator(self.content.get)
74
75    @SubredditController.register(Command('SORT_1'))
76    def sort_content_hot(self):
77        if self.content.query:
78            self.refresh_content(order='relevance')
79        else:
80            self.refresh_content(order='hot')
81
82    @SubredditController.register(Command('SORT_2'))
83    def sort_content_top(self):
84        order = self._prompt_period('top')
85        if order is None:
86            self.term.show_notification('Invalid option')
87        else:
88            self.refresh_content(order=order)
89
90    @SubredditController.register(Command('SORT_3'))
91    def sort_content_rising(self):
92        if self.content.query:
93            order = self._prompt_period('comments')
94            if order is None:
95                self.term.show_notification('Invalid option')
96            else:
97                self.refresh_content(order=order)
98        else:
99            self.refresh_content(order='rising')
100
101    @SubredditController.register(Command('SORT_4'))
102    def sort_content_new(self):
103        self.refresh_content(order='new')
104
105    @SubredditController.register(Command('SORT_5'))
106    def sort_content_controversial(self):
107        if self.content.query:
108            self.term.flash()
109        else:
110            order = self._prompt_period('controversial')
111            if order is None:
112                self.term.show_notification('Invalid option')
113            else:
114                self.refresh_content(order=order)
115
116    @SubredditController.register(Command('SORT_6'))
117    def sort_content_gilded(self):
118        if self.content.query:
119            self.term.flash()
120        else:
121            self.refresh_content(order='gilded')
122
123    @SubredditController.register(Command('SUBREDDIT_SEARCH'))
124    def search_subreddit(self, name=None):
125        """
126        Open a prompt to search the given subreddit
127        """
128        name = name or self.content.name
129
130        query = self.term.prompt_input('Search {0}: '.format(name))
131        if not query:
132            return
133
134        with self.term.loader('Searching'):
135            self.content = SubredditContent.from_name(
136                self.reddit, name, self.term.loader, query=query)
137        if not self.term.loader.exception:
138            self.nav = Navigator(self.content.get)
139
140    @SubredditController.register(Command('SUBREDDIT_FRONTPAGE'))
141    def show_frontpage(self):
142        """
143        If on a subreddit, remember it and head back to the front page.
144        If this was pressed on the front page, go back to the last subreddit.
145        """
146
147        if self.content.name != '/r/front':
148            target = '/r/front'
149            self.toggled_subreddit = self.content.name
150        else:
151            target = self.toggled_subreddit
152
153        # target still may be empty string if this command hasn't yet been used
154        if target is not None:
155            self.refresh_content(order='ignore', name=target)
156
157    @SubredditController.register(Command('SUBREDDIT_OPEN'))
158    def open_submission(self, url=None):
159        """
160        Select the current submission to view posts.
161        """
162        if url is None:
163            data = self.get_selected_item()
164            url = data['permalink']
165            if data.get('url_type') == 'selfpost':
166                self.config.history.add(data['url_full'])
167
168        self.selected_page = self.open_submission_page(url)
169
170    @SubredditController.register(Command('SUBREDDIT_OPEN_IN_BROWSER'))
171    def open_link(self):
172        """
173        Open a link with the webbrowser
174        """
175
176        data = self.get_selected_item()
177        if data['url_type'] == 'selfpost':
178            self.open_submission()
179        elif data['url_type'] == 'x-post subreddit':
180            self.refresh_content(order='ignore', name=data['xpost_subreddit'])
181        elif data['url_type'] == 'x-post submission':
182            self.open_submission(url=data['url_full'])
183            self.config.history.add(data['url_full'])
184        else:
185            self.term.open_link(data['url_full'])
186            self.config.history.add(data['url_full'])
187
188    @SubredditController.register(Command('SUBREDDIT_POST'))
189    @logged_in
190    def post_submission(self):
191        """
192        Post a new submission to the given subreddit.
193        """
194        # Check that the subreddit can be submitted to
195        name = self.content.name
196        if '+' in name or name in ('/r/all', '/r/front', '/r/me', '/u/saved'):
197            self.term.show_notification("Can't post to {0}".format(name))
198            return
199
200        submission_info = docs.SUBMISSION_FILE.format(name=name)
201        with self.term.open_editor(submission_info) as text:
202            if not text:
203                self.term.show_notification('Canceled')
204                return
205            elif '\n' not in text:
206                self.term.show_notification('Missing body')
207                return
208
209            title, content = text.split('\n', 1)
210            with self.term.loader('Posting', delay=0):
211                submission = self.reddit.submit(name, title, text=content,
212                                                raise_captcha_exception=True)
213                # Give reddit time to process the submission
214                time.sleep(2.0)
215            if self.term.loader.exception:
216                raise TemporaryFileError()
217
218        if not self.term.loader.exception:
219            # Open the newly created submission
220            self.selected_page = self.open_submission_page(submission=submission)
221
222    @SubredditController.register(Command('SUBREDDIT_HIDE'))
223    @logged_in
224    def hide(self):
225        data = self.get_selected_item()
226        if not hasattr(data["object"], 'hide'):
227            self.term.flash()
228        elif data['hidden']:
229            with self.term.loader('Unhiding'):
230                data['object'].unhide()
231                data['hidden'] = False
232        else:
233            with self.term.loader('Hiding'):
234                data['object'].hide()
235                data['hidden'] = True
236
237    def _draw_item(self, win, data, inverted):
238
239        n_rows, n_cols = win.getmaxyx()
240        n_cols -= 1  # Leave space for the cursor in the first column
241
242        # Handle the case where the window is not large enough to fit the data.
243        valid_rows = range(0, n_rows)
244        offset = 0 if not inverted else -(data['n_rows'] - n_rows)
245
246        n_title = len(data['split_title'])
247        if data['url_full'] in self.config.history:
248            attr = self.term.attr('SubmissionTitleSeen')
249        else:
250            attr = self.term.attr('SubmissionTitle')
251        for row, text in enumerate(data['split_title'], start=offset):
252            if row in valid_rows:
253                self.term.add_line(win, text, row, 1, attr)
254
255        row = n_title + offset
256        if data['url_full'] in self.config.history:
257            attr = self.term.attr('LinkSeen')
258        else:
259            attr = self.term.attr('Link')
260        if row in valid_rows:
261            self.term.add_line(win, '{url}'.format(**data), row, 1, attr)
262
263        row = n_title + offset + 1
264        if row in valid_rows:
265
266            attr = self.term.attr('Score')
267            self.term.add_line(win, '{score}'.format(**data), row, 1, attr)
268            self.term.add_space(win)
269
270            arrow, attr = self.term.get_arrow(data['likes'])
271            self.term.add_line(win, arrow, attr=attr)
272            self.term.add_space(win)
273
274            attr = self.term.attr('Created')
275            self.term.add_line(win, '{created}{edited}'.format(**data), attr=attr)
276
277            if data['comments'] is not None:
278                attr = self.term.attr('Separator')
279                self.term.add_space(win)
280                self.term.add_line(win, '-', attr=attr)
281
282                attr = self.term.attr('CommentCount')
283                self.term.add_space(win)
284                self.term.add_line(win, '{comments}'.format(**data), attr=attr)
285
286            if data['saved']:
287                attr = self.term.attr('Saved')
288                self.term.add_space(win)
289                self.term.add_line(win, '[saved]', attr=attr)
290
291            if data['hidden']:
292                attr = self.term.attr('Hidden')
293                self.term.add_space(win)
294                self.term.add_line(win, '[hidden]', attr=attr)
295
296            if data['stickied']:
297                attr = self.term.attr('Stickied')
298                self.term.add_space(win)
299                self.term.add_line(win, '[stickied]', attr=attr)
300
301            if data['gold']:
302                attr = self.term.attr('Gold')
303                self.term.add_space(win)
304                count = 'x{}'.format(data['gold']) if data['gold'] > 1 else ''
305                text = self.term.gilded + count
306                self.term.add_line(win, text, attr=attr)
307
308            if data['nsfw']:
309                attr = self.term.attr('NSFW')
310                self.term.add_space(win)
311                self.term.add_line(win, 'NSFW', attr=attr)
312
313        row = n_title + offset + 2
314        if row in valid_rows:
315            attr = self.term.attr('SubmissionAuthor')
316            self.term.add_line(win, '{author}'.format(**data), row, 1, attr)
317            self.term.add_space(win)
318
319            attr = self.term.attr('SubmissionSubreddit')
320            self.term.add_line(win, '/r/{subreddit}'.format(**data), attr=attr)
321
322            if data['flair']:
323                attr = self.term.attr('SubmissionFlair')
324                self.term.add_space(win)
325                self.term.add_line(win, '{flair}'.format(**data), attr=attr)
326
327        attr = self.term.attr('CursorBlock')
328        for y in range(n_rows):
329            self.term.addch(win, y, 0, str(' '), attr)
330