class View(WFrame):

    ## 조회할 기사
    # @var Article
    article = None

    ## 생성자
    def __init__(self, master=None, article=None, **kw):
        self.article = article
        super().__init__(master, **kw)

    def initializeWidget(self):
        self.scrollFrame = VScrollWidget(self)
        self.scrollFrame.pack(fill=BOTH, expand=TRUE)

        self.lblArticle = Label(self.scrollFrame.frame)
        self.lblArticle['justify'] = LEFT
        self.lblArticle['text'] = '\n'.join(self.article.texts)
        self.lblArticle['font'] = 'Consolas'
        self.lblArticle['padx'] = 0
        self.lblArticle['pady'] = 0
        self.lblArticle.pack(padx=(40, 0), pady=(20, 0), anchor=NW)

        self.text = '기사 보기'
        self.width = 640
        self.height = 480
        self.startPosition = StartPosition.centerParent
class Fixer(WFrame):

    typos = None

    def __init__(self, master=None, **kw):
        self.typos = Fixer.load()
        super().__init__(master, **kw)

    def initializeWidget(self):
        self.scrollFrame = VScrollWidget(self)
        self.scrollFrame.pack(fill=BOTH, expand=TRUE)

        for typo in self.typos:
            label = Label(self.scrollFrame.frame)
            label['justify'] = LEFT
            label['font'] = 'Consolas'
            label['padx'] = 0
            label['pady'] = 0
            label['text'] = typo.toString(Fixer.suggest(typo))
            label.pack(padx=(40, 0), pady=(20, 0), anchor=NW)

        self.text = '오타 알리미'
        self.width = 640
        self.height = 480
        self.startPosition = StartPosition.centerParent

    ## 오타에 대한 조언을하는 메서드
    #
    # 매우 중요!
    # @return string
    @staticmethod
    def suggest(typo):
        if ' ' in typo.context[typo.expected - 2:][:4]:
            return '차분한 마음으로 타자해보세요.'
        elif typo.ch in typo.context[typo.expected - 2:][:4]:
            return '타속은 너무 신경쓰지 말고,\n연습하는 느낌으로 타자해보세요.'
        return '좀 더 연습하세요.'

    @staticmethod
    def load():
        typos = None
        try:
            with open('data/typos.pkl', 'rb') as data:
                typos = pickle.load(data)
        except:
            pass
        return TypoList() if typos == None else typos

    @staticmethod
    def save(typoList):
        typoBak = Fixer.load()
        with open('data/typos.pkl', 'wb') as typos:
            pickle.dump(typoBak + typoList, typos)
    def initializeWidget(self):
        self.txtKeyword = Entry(self)
        self.txtKeyword['width'] = 987654
        self.txtKeyword.grid(row=0, column=0)

        self.btnSearch = Button(self)
        self.btnSearch['text'] = '검색'
        self.btnSearch['command'] = self.search
        self.btnSearch.grid(row=0, column=1)

        self.frmArticleList = VScrollWidget(self)
        self.frmArticleList.grid(row=1, column=0, columnspan=2, sticky=N)
        self.frmArticleList.bind_all('<Button-1>', self.select)

        self.btnSearchNext = Button(self)
        self.btnSearchNext['text'] = '더 보기'
        self.btnSearchNext['command'] = self.searchNext
        self.btnSearchNext.grid(row=2, column=0, columnspan=2)

        self.text = 'NYTimes 기사 검색기'
        self.width = 400
        self.height = 300
        self.startPosition = StartPosition.centerParent
        self.columnconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)
    def initializeWidget(self):
        self.scrollFrame = VScrollWidget(self)
        self.scrollFrame.pack(fill=BOTH, expand=TRUE)

        self.lblArticle = Label(self.scrollFrame.frame)
        self.lblArticle['justify'] = LEFT
        self.lblArticle['text'] = '\n'.join(self.article.texts)
        self.lblArticle['font'] = 'Consolas'
        self.lblArticle['padx'] = 0
        self.lblArticle['pady'] = 0
        self.lblArticle.pack(padx=(40, 0), pady=(20, 0), anchor=NW)

        self.text = '기사 보기'
        self.width = 640
        self.height = 480
        self.startPosition = StartPosition.centerParent
    def initializeWidget(self):
        self.scrollFrame = VScrollWidget(self)
        self.scrollFrame.pack(fill=BOTH, expand=TRUE)

        for typo in self.typos:
            label = Label(self.scrollFrame.frame)
            label['justify'] = LEFT
            label['font'] = 'Consolas'
            label['padx'] = 0
            label['pady'] = 0
            label['text'] = typo.toString(Fixer.suggest(typo))
            label.pack(padx=(40, 0), pady=(20, 0), anchor=NW)

        self.text = '오타 알리미'
        self.width = 640
        self.height = 480
        self.startPosition = StartPosition.centerParent
class Search(WFrame):

    ## 검색 결과 선택한 Article
    # @see select()
    # @var Article
    result = None

    def initializeWidget(self):
        self.txtKeyword = Entry(self)
        self.txtKeyword['width'] = 987654
        self.txtKeyword.grid(row=0, column=0)

        self.btnSearch = Button(self)
        self.btnSearch['text'] = '검색'
        self.btnSearch['command'] = self.search
        self.btnSearch.grid(row=0, column=1)

        self.frmArticleList = VScrollWidget(self)
        self.frmArticleList.grid(row=1, column=0, columnspan=2, sticky=N)
        self.frmArticleList.bind_all('<Button-1>', self.select)

        self.btnSearchNext = Button(self)
        self.btnSearchNext['text'] = '더 보기'
        self.btnSearchNext['command'] = self.searchNext
        self.btnSearchNext.grid(row=2, column=0, columnspan=2)

        self.text = 'NYTimes 기사 검색기'
        self.width = 400
        self.height = 300
        self.startPosition = StartPosition.centerParent
        self.columnconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)

    ## 기사 검색에 필요한 초기화 작업을 한다.
    def search(self):
        for widget in self.frmArticleList.frame.winfo_children():
            widget.destroy()
        self.page = 0
        self.searchNext()

    ## txtKeyword의 값으로 기사를 검색하고 화면에 결과를 출력한다.
    def searchNext(self):
        self.page += 1
        for article in Search.getArticles(self.txtKeyword.get(), self.page):
            ArticleWidget(self.frmArticleList.frame, article).pack()

    ## 선택한 ArticleWidget의 article을 load()하고 result에 저장 후 창을 닫는다.
    def select(self, e):
        isArticleWidget = isinstance(e.widget, ArticleWidget)
        if isArticleWidget or isinstance(e.widget.master, ArticleWidget):
            aw = e.widget if isArticleWidget else e.widget.master
            try:
                aw.article.load()
                self.result = aw.article
                self.close()
            except Exception as e:
                print(e)
                MessageBox.showerror(self.text, '기사를 불러오지 못했습니다.\n잠시 후 다시 시도하세요.')

    ## NYTimes의 API를 이용해 keyword에 해당하는 기사의 목록을 10개 단위로 가져온다.
    #
    # http://developer.nytimes.com/docs/read/article_search_api_v2
    # @param keyword 검색할 키워드
    # @param page 페이지
    # @return list<Article>
    @staticmethod
    def getArticles(keyword, page=1):
        url = 'http://api.nytimes.com/svc/search/v2/articlesearch.json?api-key=%s&fl=%s&page=%d' % (
            urllib.parse.quote(__config__.APIKey),
            urllib.parse.quote('web_url,headline,word_count'),
            (page - 1) * 10)
        if len(keyword) > 0:
            url += '&q=%s' % urllib.parse.quote(keyword)
        response = urllib.request.urlopen(url)
        content = response.read().decode('UTF-8')

        jobject = json.loads(content, 'UTF-8')
        articles = []
        for i in jobject['response']['docs']:
            url = i['web_url']
            # i['headline']['main']은 KeyError가 발생할 수 있음
            title = i['headline'].get('main')
            words = i['word_count']
            articles.append(Article(url, title, words))
        return articles