#!/usr/bin/env python3
"""
    RFC.py - A python module that downloads Request For Comments from the
    Internet Engineering Task Force into a Sqlite database for offline reading.

    Includes full text search, RFC number search and bookmarking capabilities
    and weekly updates inline with the IETF policy of weekly additions.

        Copyright (C) 2018-2020, <NAME>
"""
import sys
from time import sleep

import click
from peewee import DoesNotExist, OperationalError, fn

from rfcpy.helpers.display import (Color, clear_screen, logo,
                                   print_by_bookmark, print_by_keyword,
                                   print_by_number, print_get_latest, prompt)
from rfcpy.helpers.utils import (ask_user_to_update, check_last_update,
                                 read_config, sanitize_inputs)
from rfcpy.models import Data, DataIndex


def main():
    try:
        clear_screen()
        logo()
        read_config()
        check_last_update()
        home_page()

    except OSError:
        raise

    except KeyboardInterrupt:
        print("User exited using CTRL-C")

    except EOFError:
        print("User exited using CTRL-D")


def home_page():
    """Interactive home page which user can use to select their type of search.

    :options:   1. Search by RFC number
                2. Search by keyword (using Sqlite FTS5)
                3. Search bookmarks
                4. Latest 10 RFC's
                5. Get a random RFC
                [q] or [Enter] to quit application
    """

    clear_screen()
    logo()
    print(
        """
    [1] -- Search by Number
    [2] -- Search by Keyword
    [3] -- Search through Bookmark
    [4] -- Latest 10 RFC's
    [5] -- Get a Random RFC
    
    [0] -- User Options
    [q] or [Enter] - Quit!
    """
    )
    choice = input(prompt)
    if choice == "1":
        clear_screen()
        print_by_number()
        search_by_number()
    elif choice == "2":
        clear_screen()
        search_by_keyword()
    elif choice == "3":
        clear_screen()
        search_bookmarks()
    elif choice == "4":
        clear_screen()
        latest()
    elif choice == "5":
        clear_screen()
        random_rfc()
    elif choice == "0":
        clear_screen()
        settings_page()
    elif choice == "q" or choice == "":
        sys.exit()
    else:
        print("[!!] Please Select Options [1,2 or 3] [!!]")
        print("...exiting!")


def search_by_number():
    """User is to enter a valid RFC for retrieval from database."""

    try:
        print("[*] Enter RFC by number [eg. 8305]  [*]")
        print("[*] OR Press [Enter] for Home Page  [*]")
        number = input(f"{prompt}")
        if number == "":
            home_page()
        if not number.isdigit():
            print("[!!] Please enter rfc using numbers only i.e. 8305 [!!]")
            print("Exiting..")
            sys.exit(1)
        result = Data.get_by_id(number).text
        pager(result)
        bookmarker(number)

    except DoesNotExist:
        print(
            f"{Color.WARNING}[!!] Query not found! "
            f"Please check the rfc number and try again [!!]{Color.END}"
        )
    except OverflowError:
        print("Integer entered is too large.")


def search_by_keyword():
    """User can enter keywords to search for RFC's - only parses the title.

    Prints all matches with RFC number - user can then enter which RFC number
    to view, if any, or return to Home Page.
    """

    print_by_keyword()
    print("[*] Enter Keyword/s [http/2 hpack]")
    phrase = input(f"{prompt}")
    phrase = sanitize_inputs(phrase)
    query = (
        Data.select()
        .join(DataIndex, on=(Data.number == DataIndex.rowid))
        .where(DataIndex.match(phrase))
        .order_by(DataIndex.bm25())
    )
    try:
        for results in query:
            print(
                f"{Color.OKBLUE}Matches:{Color.NOTICE} RFC {results.title[:5]}"
                f"{Color.HEADER}- {results.title[5:]}{Color.END}"
            )
        print()
        search_by_number()
    except OperationalError:
        print("[!!] Database lookup error! [!!]")


def search_bookmarks():
    """Print list of bookmarked RFC's"""

    print_by_bookmark()
    print("[*] All Bookmarked RFC's[*]")
    print()
    query = Data.select().where(Data.bookmark == 1)
    for result in query:
        print(
            f"\t{Color.OKBLUE}RFC {result.number} - {Color.NOTICE}"
            f"{result.title[5:]}{Color.END}"
        )
    search_by_number()


def settings_page():
    """Print list of user adjustable settings."""
    print("[*] User Options\n")
    print(f"{Color.NOTICE}[1] Delete bookmarks{Color.END}\n")
    print(f"{Color.NOTICE}[2] Manual Update RFC Database{Color.END}\n")
    print("[Enter] Return to Home Page\n")
    choice = input(prompt)
    if choice == "1":
        clear_screen()
        update_bookmarks()
    elif choice == "2":
        clear_screen()
        ask_user_to_update()
        sleep(2)
        home_page()
    else:
        home_page()


def update_bookmarks():
    """Updates the Bookmark row in database for selected RFC."""
    print("[!] Select bookmark to delete [!]")
    print()
    query = Data.select().where(Data.bookmark == 1)
    for result in query:
        print(
            f"\t{Color.OKBLUE}RFC {result.number} - {Color.NOTICE}"
            f"{result.title[5:]}{Color.END}"
        )
    print()
    print("[*] Enter Bookmark to delete by number [eg. 8305]  [*]")
    print("[*] OR Press [Enter] for Home Page                 [*]")
    choice = input(prompt)

    if choice.isdigit():
        update = Data(number=choice, bookmark=0)
        update.save()
        update_bookmarks()
        print()
    elif choice == "" or choice == "q":
        home_page()
    else:
        print("\n[!] Please enter a valid number! [!]")
        print()
        update_bookmarks()


def bookmarker(number):
    """Give user the option to bookmark the last read RFC, defaults to No."""

    bookmark = input("Do you wish to bookmark this? [y/N] >> ")
    if bookmark == "y" or bookmark == "Y":
        print("YES", number)
        update = Data(number=number, bookmark=1)
        update.save()
    home_page()


def latest():
    """Get the most recent RFC's returning ten by default but the user can
    specify a set number to see.

    :arg number (default=10) user can set how many to retrieve."""
    print_get_latest()
    query = Data.select().order_by(Data.title.desc()).limit(10)
    # this is a slow lookup - needs optimisation.
    for result in query:
        print(
            f"\t{Color.OKBLUE}RFC {result.number} - {Color.NOTICE}"
            f"{result.title[5:]}{Color.END}"
        )
    search_by_number()


def random_rfc():
    """Randomly selects a RFC."""
    random = Data.select().order_by(fn.Random()).limit(1)
    for record in random:
        pager(record.text)
    bookmarker(random)


def pager(data):
    """Utilise the safe work of Click.echo_via_pager to render RFC's using
    system pager.
    """

    return click.echo_via_pager(data)


if __name__ == "__main__":
    main()

#!/usr/bin/env python3
"""
    RFC.py - A python module that downloads Request For Comments from the
    Internet Engineering Task Force into a Sqlite database for offline reading.

    Includes full text search, RFC number search and bookmarking capabilities
    and weekly updates inline with the IETF policy of weekly additions.

        Copyright (C) 2018-2020, <NAME>
"""
import sys
from time import sleep

import click
from peewee import DoesNotExist, OperationalError, fn

from rfcpy.helpers.display import (Color, clear_screen, logo,
                                   print_by_bookmark, print_by_keyword,
                                   print_by_number, print_get_latest, prompt)
from rfcpy.helpers.utils import (ask_user_to_update, check_last_update,
                                 read_config, sanitize_inputs)
from rfcpy.models import Data, DataIndex


def main():
    try:
        clear_screen()
        logo()
        read_config()
        check_last_update()
        home_page()

    except OSError:
        raise

    except KeyboardInterrupt:
        print("User exited using CTRL-C")

    except EOFError:
        print("User exited using CTRL-D")


def home_page():
    """Interactive home page which user can use to select their type of search.

    :options:   1. Search by RFC number
                2. Search by keyword (using Sqlite FTS5)
                3. Search bookmarks
                4. Latest 10 RFC's
                5. Get a random RFC
                [q] or [Enter] to quit application
    """

    clear_screen()
    logo()
    print(
        """
    [1] -- Search by Number
    [2] -- Search by Keyword
    [3] -- Search through Bookmark
    [4] -- Latest 10 RFC's
    [5] -- Get a Random RFC
    
    [0] -- User Options
    [q] or [Enter] - Quit!
    """
    )
    choice = input(prompt)
    if choice == "1":
        clear_screen()
        print_by_number()
        search_by_number()
    elif choice == "2":
        clear_screen()
        search_by_keyword()
    elif choice == "3":
        clear_screen()
        search_bookmarks()
    elif choice == "4":
        clear_screen()
        latest()
    elif choice == "5":
        clear_screen()
        random_rfc()
    elif choice == "0":
        clear_screen()
        settings_page()
    elif choice == "q" or choice == "":
        sys.exit()
    else:
        print("[!!] Please Select Options [1,2 or 3] [!!]")
        print("...exiting!")


def search_by_number():
    """User is to enter a valid RFC for retrieval from database."""

    try:
        print("[*] Enter RFC by number [eg. 8305]  [*]")
        print("[*] OR Press [Enter] for Home Page  [*]")
        number = input(f"{prompt}")
        if number == "":
            home_page()
        if not number.isdigit():
            print("[!!] Please enter rfc using numbers only i.e. 8305 [!!]")
            print("Exiting..")
            sys.exit(1)
        result = Data.get_by_id(number).text
        pager(result)
        bookmarker(number)

    except DoesNotExist:
        print(
            f"{Color.WARNING}[!!] Query not found! "
            f"Please check the rfc number and try again [!!]{Color.END}"
        )
    except OverflowError:
        print("Integer entered is too large.")


def search_by_keyword():
    """User can enter keywords to search for RFC's - only parses the title.

    Prints all matches with RFC number - user can then enter which RFC number
    to view, if any, or return to Home Page.
    """

    print_by_keyword()
    print("[*] Enter Keyword/s [http/2 hpack]")
    phrase = input(f"{prompt}")
    phrase = sanitize_inputs(phrase)
    query = (
        Data.select()
        .join(DataIndex, on=(Data.number == DataIndex.rowid))
        .where(DataIndex.match(phrase))
        .order_by(DataIndex.bm25())
    )
    try:
        for results in query:
            print(
                f"{Color.OKBLUE}Matches:{Color.NOTICE} RFC {results.title[:5]}"
                f"{Color.HEADER}- {results.title[5:]}{Color.END}"
            )
        print()
        search_by_number()
    except OperationalError:
        print("[!!] Database lookup error! [!!]")


def search_bookmarks():
    """Print list of bookmarked RFC's"""

    print_by_bookmark()
    print("[*] All Bookmarked RFC's[*]")
    print()
    query = Data.select().where(Data.bookmark == 1)
    for result in query:
        print(
            f"\t{Color.OKBLUE}RFC {result.number} - {Color.NOTICE}"
            f"{result.title[5:]}{Color.END}"
        )
    search_by_number()


def settings_page():
    """Print list of user adjustable settings."""
    print("[*] User Options\n")
    print(f"{Color.NOTICE}[1] Delete bookmarks{Color.END}\n")
    print(f"{Color.NOTICE}[2] Manual Update RFC Database{Color.END}\n")
    print("[Enter] Return to Home Page\n")
    choice = input(prompt)
    if choice == "1":
        clear_screen()
        update_bookmarks()
    elif choice == "2":
        clear_screen()
        ask_user_to_update()
        sleep(2)
        home_page()
    else:
        home_page()


def update_bookmarks():
    """Updates the Bookmark row in database for selected RFC."""
    print("[!] Select bookmark to delete [!]")
    print()
    query = Data.select().where(Data.bookmark == 1)
    for result in query:
        print(
            f"\t{Color.OKBLUE}RFC {result.number} - {Color.NOTICE}"
            f"{result.title[5:]}{Color.END}"
        )
    print()
    print("[*] Enter Bookmark to delete by number [eg. 8305]  [*]")
    print("[*] OR Press [Enter] for Home Page                 [*]")
    choice = input(prompt)

    if choice.isdigit():
        update = Data(number=choice, bookmark=0)
        update.save()
        update_bookmarks()
        print()
    elif choice == "" or choice == "q":
        home_page()
    else:
        print("\n[!] Please enter a valid number! [!]")
        print()
        update_bookmarks()


def bookmarker(number):
    """Give user the option to bookmark the last read RFC, defaults to No."""

    bookmark = input("Do you wish to bookmark this? [y/N] >> ")
    if bookmark == "y" or bookmark == "Y":
        print("YES", number)
        update = Data(number=number, bookmark=1)
        update.save()
    home_page()


def latest():
    """Get the most recent RFC's returning ten by default but the user can
    specify a set number to see.

    :arg number (default=10) user can set how many to retrieve."""
    print_get_latest()
    query = Data.select().order_by(Data.title.desc()).limit(10)
    # this is a slow lookup - needs optimisation.
    for result in query:
        print(
            f"\t{Color.OKBLUE}RFC {result.number} - {Color.NOTICE}"
            f"{result.title[5:]}{Color.END}"
        )
    search_by_number()


def random_rfc():
    """Randomly selects a RFC."""
    random = Data.select().order_by(fn.Random()).limit(1)
    for record in random:
        pager(record.text)
    bookmarker(random)


def pager(data):
    """Utilise the safe work of Click.echo_via_pager to render RFC's using
    system pager.
    """

    return click.echo_via_pager(data)


if __name__ == "__main__":
    main()

#!/usr/bin/env python3 RFC.py - A python module that downloads Request For Comments from the     Internet Engineering Task Force into a Sqlite database for offline reading.      Includes full text search, RFC number search and bookmarking capabilities     and weekly updates inline with the IETF policy of weekly additions.          Copyright (C) 2018-2020, <NAME> Interactive home page which user can use to select their type of search.      :options:   1. Search by RFC number                 2. Search by keyword (using Sqlite FTS5)                 3. Search bookmarks                 4. Latest 10 RFC's                 5. Get a random RFC                 [q] or [Enter] to quit application [1] -- Search by Number     [2] -- Search by Keyword     [3] -- Search through Bookmark     [4] -- Latest 10 RFC's     [5] -- Get a Random RFC          [0] -- User Options     [q] or [Enter] - Quit! User is to enter a valid RFC for retrieval from database. User can enter keywords to search for RFC's - only parses the title.      Prints all matches with RFC number - user can then enter which RFC number     to view, if any, or return to Home Page. Print list of bookmarked RFC's Print list of user adjustable settings. Updates the Bookmark row in database for selected RFC. Give user the option to bookmark the last read RFC, defaults to No. Get the most recent RFC's returning ten by default but the user can     specify a set number to see.      :arg number (default=10) user can set how many to retrieve. # this is a slow lookup - needs optimisation. Randomly selects a RFC. Utilise the safe work of Click.echo_via_pager to render RFC's using     system pager.