"""
project = Election scraper
author = <NAME>
"""

from time import time
import requests
from bs4 import BeautifulSoup as BS
import csv
import sys

# training website
INPUT = "https://volby.cz/pls/ps2017nss/ps3?xjazyk=CZ"


def get_districts(web):
    """
    Přijímá webovku a vrátí extrahovaný seznam odkazů na stránky volebních
    okresů + základní webovku.
    EG.: Ze stránky Volby.cz vrací [okres_1.cz, okres_2.cz, ... okres_N.cz].
    :param web:
    :return adr_okresu:
    :return base_adr:
    """

    base_adr = web[0:web.rfind("/")]

    soup = suck_n_chop(web)

    tab_lines = [tr.find_all("a") for tr in soup.find_all("tr")]

    adr_okresu = [base_adr + "/" + group[2]["href"] for group in tab_lines
                  if len(group) != 0 if group[0].text[0:2] == "CZ"]

    return adr_okresu, base_adr


def get_municipalities(web_list, base_adr):
    """
    Přijímá seznam okresních webů + základní webovku a vrací seznam webů obcí.
    EG.: Z webu brno-venkov.cz vrací [Opatovice.cz, Ostopovice.cz, ...].
    :param web_list:
    :param base_adr:
    :return adr_obci:
    """

    assert web_list != [], "Problém: seznam adres je prázdný."

    adr_obci = []

    for web in web_list:
        soup = suck_n_chop(web)

        tab_lines = [tr.find_all("a") for tr in soup.find_all("tr")]

        adr_obci = [base_adr + "/" + element["href"] for group in tab_lines
                    if len(group) != 0 for element in group
                    if element.text.isnumeric()]

    return adr_obci


def extract_data(web_list):
    """
    Přijímá cílové webovky (obce), cucá data a vrací je v seznamu.
    EG.: return [[code, location ...], [62500, Brno ...], ...]
    :param web_list:
    :return db:
    """

    assert web_list != [], "Problém: seznam adres je prázdný."

    db = [(complete_first_line(suck_n_chop(web_list[0])))]

    for web in web_list:
        soup = suck_n_chop(web)

        # získá kód obce
        code = []
        start = web.find("obec=") + 5
        i = start
        while web[i].isnumeric():
            code.append(web[i])
            i += 1
        code = "".join(code)

        # vytvoří řádek v CSVčku
        db.append(make_package(soup, code))

    return db


def complete_first_line(soup):
    """
    Přijímá soap webu, ze které získá jména všech polit. stran a vrátí
    popisky osy X v CSV tabulce.
    :param soup:
    :return first_line:
    """

    first_line = ["code", "location", "registered", "envelopes", "valid"]

    tabs = soup.find_all("div", {"class": "t2_470"})

    par_lines = [tr.find_all("td") for tab in tabs for tr in tab.find_all("tr")
                 if len(tr) == 11]

    for party in range(len(par_lines)):
        first_line.append(par_lines[party][1].text)

    return first_line


def make_package(soup, code):
    """
    Získá z poskytnuté polévky informace a vrátí je v balíku - seřazené jako
    řádek v CSV. Zvenku také získá kód označující obec.
    :param soup:
    :param code:
    :return package:
    """

    # code
    package = [code]

    # location
    for title in soup.find_all("h3"):
        if title.text[1:6] == "Obec:":
            package.append(title.text[7:].strip())

    # registered

    tab = soup.find("table")

    lines = [tr for tr in tab.find_all("tr")]

    inventory = [td for td in lines[2]]

    package.append("".join(inventory[7].text.split("\xa0")))

    # envelopes
    package.append("".join(inventory[9].text.split("\xa0")))

    # valid
    package.append("".join(inventory[15].text.split("\xa0")))

    # parties
    tabs = soup.find_all("table")

    par_lines = [tr.find_all("td") for tab in tabs[1:]
                 for tr in tab.find_all("tr") if len(tr) == 11]

    for party in range(len(par_lines)):
        package.append("".join(par_lines[party][2].text.split("\xa0")))

    return package


def suck_n_chop(web):
    """
    Vyšle požadavek, zkontroluje příjem a vrátí soap.
    :param web:
    :return BS(resp.text, "html.parser"):
    """

    resp = requests.get(web)
    assert resp.status_code == 200, "Problém se spojením: {}".format(resp.status_code)
    return BS(resp.text, "html.parser")


def save_csv(db, file_name):
    """
    Přijíme data o volbách a uloží data do csv souboru s přijatým názvem.
    :param db:
    :param file_name:
    """

    with open(file_name + ".csv", "w", newline="") as file:
        writer = csv.writer(file)
        writer.writerows(db)


def main(CSV_NAME):
    """
    Jedna funkce vládne všem, jedna jim všem káže...
    -
    200 obcí za 20 sec.
    Všech cca 6300 obcí si žádá cca 13 minut!!!
    """

    # fixtures
    # web = "https://volby.cz/pls/ps2017nss"
    # okresy = ["https://volby.cz/pls/ps2017nss/ps32?xjazyk=CZ&xkraj=11&xnumnuts=6203"]
    # obce = ["https://volby.cz/pls/ps2017nss/ps311?xjazyk=CZ&xkraj=11&xobec=582786&xvyber=6202"]
    # db = [["name", "age", "sex"], ["Ondrej", "23", "M"], ["Lucie", "21", "F"]]

    time_1 = time()

    okresy, web = get_districts(INPUT)
    print("Nalezeno okresů:", len(okresy))

    obce = get_municipalities(okresy, web)
    print("Nalezeno obcí:", len(obce))
    print("Zpracovávám. Čekejte prosím...")

    db = extract_data(obce)

    save_csv(db, CSV_NAME)
    print("Úspěšně dokončeno a uloženo.")

    time_2 = time()
    time_total = int(time_2 - time_1)
    print("TOTAL TIME:", time_total, "secs")


if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("\nUSAGE: Web_scraper.py OutputFileName\n")
    else:
        main(sys.argv[1:2])

"""
project = Election scraper
author = <NAME>
"""

from time import time
import requests
from bs4 import BeautifulSoup as BS
import csv
import sys

# training website
INPUT = "https://volby.cz/pls/ps2017nss/ps3?xjazyk=CZ"


def get_districts(web):
    """
    Přijímá webovku a vrátí extrahovaný seznam odkazů na stránky volebních
    okresů + základní webovku.
    EG.: Ze stránky Volby.cz vrací [okres_1.cz, okres_2.cz, ... okres_N.cz].
    :param web:
    :return adr_okresu:
    :return base_adr:
    """

    base_adr = web[0:web.rfind("/")]

    soup = suck_n_chop(web)

    tab_lines = [tr.find_all("a") for tr in soup.find_all("tr")]

    adr_okresu = [base_adr + "/" + group[2]["href"] for group in tab_lines
                  if len(group) != 0 if group[0].text[0:2] == "CZ"]

    return adr_okresu, base_adr


def get_municipalities(web_list, base_adr):
    """
    Přijímá seznam okresních webů + základní webovku a vrací seznam webů obcí.
    EG.: Z webu brno-venkov.cz vrací [Opatovice.cz, Ostopovice.cz, ...].
    :param web_list:
    :param base_adr:
    :return adr_obci:
    """

    assert web_list != [], "Problém: seznam adres je prázdný."

    adr_obci = []

    for web in web_list:
        soup = suck_n_chop(web)

        tab_lines = [tr.find_all("a") for tr in soup.find_all("tr")]

        adr_obci = [base_adr + "/" + element["href"] for group in tab_lines
                    if len(group) != 0 for element in group
                    if element.text.isnumeric()]

    return adr_obci


def extract_data(web_list):
    """
    Přijímá cílové webovky (obce), cucá data a vrací je v seznamu.
    EG.: return [[code, location ...], [62500, Brno ...], ...]
    :param web_list:
    :return db:
    """

    assert web_list != [], "Problém: seznam adres je prázdný."

    db = [(complete_first_line(suck_n_chop(web_list[0])))]

    for web in web_list:
        soup = suck_n_chop(web)

        # získá kód obce
        code = []
        start = web.find("obec=") + 5
        i = start
        while web[i].isnumeric():
            code.append(web[i])
            i += 1
        code = "".join(code)

        # vytvoří řádek v CSVčku
        db.append(make_package(soup, code))

    return db


def complete_first_line(soup):
    """
    Přijímá soap webu, ze které získá jména všech polit. stran a vrátí
    popisky osy X v CSV tabulce.
    :param soup:
    :return first_line:
    """

    first_line = ["code", "location", "registered", "envelopes", "valid"]

    tabs = soup.find_all("div", {"class": "t2_470"})

    par_lines = [tr.find_all("td") for tab in tabs for tr in tab.find_all("tr")
                 if len(tr) == 11]

    for party in range(len(par_lines)):
        first_line.append(par_lines[party][1].text)

    return first_line


def make_package(soup, code):
    """
    Získá z poskytnuté polévky informace a vrátí je v balíku - seřazené jako
    řádek v CSV. Zvenku také získá kód označující obec.
    :param soup:
    :param code:
    :return package:
    """

    # code
    package = [code]

    # location
    for title in soup.find_all("h3"):
        if title.text[1:6] == "Obec:":
            package.append(title.text[7:].strip())

    # registered

    tab = soup.find("table")

    lines = [tr for tr in tab.find_all("tr")]

    inventory = [td for td in lines[2]]

    package.append("".join(inventory[7].text.split("\xa0")))

    # envelopes
    package.append("".join(inventory[9].text.split("\xa0")))

    # valid
    package.append("".join(inventory[15].text.split("\xa0")))

    # parties
    tabs = soup.find_all("table")

    par_lines = [tr.find_all("td") for tab in tabs[1:]
                 for tr in tab.find_all("tr") if len(tr) == 11]

    for party in range(len(par_lines)):
        package.append("".join(par_lines[party][2].text.split("\xa0")))

    return package


def suck_n_chop(web):
    """
    Vyšle požadavek, zkontroluje příjem a vrátí soap.
    :param web:
    :return BS(resp.text, "html.parser"):
    """

    resp = requests.get(web)
    assert resp.status_code == 200, "Problém se spojením: {}".format(resp.status_code)
    return BS(resp.text, "html.parser")


def save_csv(db, file_name):
    """
    Přijíme data o volbách a uloží data do csv souboru s přijatým názvem.
    :param db:
    :param file_name:
    """

    with open(file_name + ".csv", "w", newline="") as file:
        writer = csv.writer(file)
        writer.writerows(db)


def main(CSV_NAME):
    """
    Jedna funkce vládne všem, jedna jim všem káže...
    -
    200 obcí za 20 sec.
    Všech cca 6300 obcí si žádá cca 13 minut!!!
    """

    # fixtures
    # web = "https://volby.cz/pls/ps2017nss"
    # okresy = ["https://volby.cz/pls/ps2017nss/ps32?xjazyk=CZ&xkraj=11&xnumnuts=6203"]
    # obce = ["https://volby.cz/pls/ps2017nss/ps311?xjazyk=CZ&xkraj=11&xobec=582786&xvyber=6202"]
    # db = [["name", "age", "sex"], ["Ondrej", "23", "M"], ["Lucie", "21", "F"]]

    time_1 = time()

    okresy, web = get_districts(INPUT)
    print("Nalezeno okresů:", len(okresy))

    obce = get_municipalities(okresy, web)
    print("Nalezeno obcí:", len(obce))
    print("Zpracovávám. Čekejte prosím...")

    db = extract_data(obce)

    save_csv(db, CSV_NAME)
    print("Úspěšně dokončeno a uloženo.")

    time_2 = time()
    time_total = int(time_2 - time_1)
    print("TOTAL TIME:", time_total, "secs")


if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("\nUSAGE: Web_scraper.py OutputFileName\n")
    else:
        main(sys.argv[1:2])

project = Election scraper
 author = <NAME> # training website Přijímá webovku a vrátí extrahovaný seznam odkazů na stránky volebních
     okresů + základní webovku.
     EG.: Ze stránky Volby.cz vrací [okres_1.cz, okres_2.cz, ... okres_N.cz].
     :param web:
     :return adr_okresu:
     :return base_adr: Přijímá seznam okresních webů + základní webovku a vrací seznam webů obcí.
     EG.: Z webu brno-venkov.cz vrací [Opatovice.cz, Ostopovice.cz, ...].
     :param web_list:
     :param base_adr:
     :return adr_obci: Přijímá cílové webovky (obce), cucá data a vrací je v seznamu.
     EG.: return [[code, location ...], [62500, Brno ...], ...]
     :param web_list:
     :return db: # získá kód obce # vytvoří řádek v CSVčku Přijímá soap webu, ze které získá jména všech polit. stran a vrátí
     popisky osy X v CSV tabulce.
     :param soup:
     :return first_line: Získá z poskytnuté polévky informace a vrátí je v balíku - seřazené jako
     řádek v CSV. Zvenku také získá kód označující obec.
     :param soup:
     :param code:
     :return package: # code # location # registered # envelopes # valid # parties Vyšle požadavek, zkontroluje příjem a vrátí soap.
     :param web:
     :return BS(resp.text, "html.parser"): Přijíme data o volbách a uloží data do csv souboru s přijatým názvem.
     :param db:
     :param file_name: Jedna funkce vládne všem, jedna jim všem káže...
     -
     200 obcí za 20 sec.
     Všech cca 6300 obcí si žádá cca 13 minut!!! # fixtures # web = "https://volby.cz/pls/ps2017nss" # okresy = ["https://volby.cz/pls/ps2017nss/ps32?xjazyk=CZ&xkraj=11&xnumnuts=6203"] # obce = ["https://volby.cz/pls/ps2017nss/ps311?xjazyk=CZ&xkraj=11&xobec=582786&xvyber=6202"] # db = [["name", "age", "sex"], ["Ondrej", "23", "M"], ["Lucie", "21", "F"]]