"""This file contains the unit tests of the wiki file"""
import wikipedia
from src.wiki import WikiSearcher

def test_wiki_geolookup(monkeypatch):

    token = ("OK", [48.8975156, 2.3833993])
    sut = WikiSearcher(token)

    class MockResponseGeosearch(object):
        # Creates Mock object

        def geosearch():
            georesponse = [
                "Quai de la Gironde",
                "Parc du Pont de Flandre",
                "Square du Quai-de-la-Gironde",
                "Avenue Corentin-Cariou",
                "Porte de la Villette (métro de Paris)",
            ]
            return georesponse

        def summary():

            sumresponse = (
                "Le quai de la Gironde est un quai situé"
                " le long du canal Saint-Denis, "
                "à Paris, dans le 19e arrondissement."
                "== Situation et accès =="
                "Il fait face au quai de la Charente, "
                "commence au quai de l'Oise"
                " et se termine avenue Corentin-Cariou."
            )
            return sumresponse

        def results(self):

            result_wiki_sentence = (
                "Le quai de la Gironde est un quai situé"
                " le long du canal Saint-Denis, "
                "à Paris, dans le 19e arrondissement."
                "== Situation et accès =="
                "Il fait face au quai de la Charente, "
                "commence au quai de l'Oise"
                " et se termine avenue Corentin-Cariou."
            )
            return result_wiki_sentence

    def mock_get(*url, **args):
        return MockResponseGeosearch().results()

    monkeypatch.setattr(wikipedia, "geosearch", mock_get)
    monkeypatch.setattr(wikipedia, "summary", mock_get)

    assert (
        sut.geolookup() == "Le quai de la Gironde est un quai situé"
        " le long du canal Saint-Denis, "
        "à Paris, dans le 19e arrondissement."
        "== Situation et accès =="
        "Il fait face au quai de la Charente, "
        "commence au quai de l'Oise"
        " et se termine avenue Corentin-Cariou."
    )

class Page:
    def __init__(self):
        self.url = "https://fr.wikipedia.org/wiki/Quai_de_la_Gironde"
        self.title = "title"

def test_wiki_get_url(monkeypatch):

    token = ("OK", [48.8975156, 2.3833993])
    sut = WikiSearcher(token)

    class MockResponseUrl(object):
        def geosearch(self):

            georesponse = [
                "Quai de la Gironde",
                "Parc du Pont de Flandre",
                "Square du Quai-de-la-Gironde",
                "Avenue Corentin-Cariou",
                "Porte de la Villette (métro de Paris)",
            ]
            return georesponse

        def page(self):
            return Page()

        def results(self):

            result_wiki_url = "https://fr.wikipedia.org/wiki/",
            "Quai_de_la_Gironde"

            return result_wiki_url

    def mock_get(*url, **kwargs):
        return MockResponseUrl().geosearch()

    def mock_wikipedia(*url, **kwargs):
        return MockResponseUrl().page()

    monkeypatch.setattr(wikipedia, "geosearch", mock_get)
    monkeypatch.setattr(wikipedia, "page", mock_wikipedia)

    assert sut.get_url() == "https://fr.wikipedia.org/wiki/Quai_de_la_Gironde"


def nextLargerNodes(self, head: Optional[ListNode]) -> List[int]:
    stack = []
    temp_list = []
    while head:
        temp_list.append(head.val)
        head = head.next
    ans = [0] * len(temp_list)
    for i, val in enumerate(temp_list):
        while stack and val > temp_list[stack[-1]]:
            ans[stack.pop()] = val
        stack.append(i)
    return ans


import os
import json
import datetime
from typing import List
from flask import Flask, render_template, request
from sqlalchemy import and_
from flask_sqlalchemy import SQLAlchemy

def create_app(test_config=None):
    project_dir = os.path.dirname(os.path.abspath(__file__))
    flask_app = Flask(__name__)
    if test_config is None:
        database_file = "sqlite:///{}".format(os.path.join(project_dir, "feature.db"))
        flask_app.config["SQLALCHEMY_DATABASE_URI"] = database_file
        flask_app.templates_auto_reload = True
        flask_app.debug = True
    else:
        flask_app.config.update(test_config)
        flask_app.testing = True
        database_file = "sqlite:///{}".format(os.path.join(project_dir, "feature_test.db"))
        flask_app.config["SQLALCHEMY_DATABASE_URI"] = database_file

    @flask_app.route("/", methods=["GET"])
    def index():
        return render_template("index.html")

    @flask_app.route("/features", methods=["GET"])
    def features_list():
        """Show all the requests, ordered by default."""
        features = Feature.query.all()
        list_dict = list(map(lambda x: x.as_dict(), features))
        return json.dumps(list_dict, default=json_serial)

    @flask_app.route("/features/add", methods=["POST"])
    def add():
        """Add new feature request with data taken from the AJAX request."""
        feature = None
        try:
            request_clone = request.json
            if "target_date" in request_clone:
                request_clone["target_date"] = datetime.datetime.strptime(request.json["target_date"], "%Y-%m-%d")
            feature = Feature(**request_clone)
            features_filtered = \
                Feature.query.filter(and_(Feature.client == request_clone["client"],
                                          Feature.client_priority >= int(request_clone["client_priority"]))).all()
            if features_filtered.__len__() > 0:
                priorities: List[int] = [f.client_priority for f in features_filtered]
                if int(request_clone["client_priority"]) in priorities:
                    for f in features_filtered:
                        f.client_priority += 1
            db.session.add(feature)
            db.session.commit()
        except Exception as e:
            print("Error: ", e)
        finally:
            if feature is not None:
                return json.dumps(feature.as_dict(), default=json_serial)
            return "Error adding new feature request"

    @flask_app.route("/features/delete", methods=["POST"])
    def delete():
        """Delete a feature request with given ID as args from the AJAX request."""
        feature = Feature.query.filter_by(id=request.args.get("id")).first()
        db.session.delete(feature)
        db.session.commit()
        return "Request successfully deleted"

    return flask_app

def init_db():
    flask_db = SQLAlchemy(app)

    return flask_db

app = create_app()
db = init_db()

def json_serial(obj):
    """Handle datetime difference between Python and JavaScript."""
    if isinstance(obj, (datetime.date, datetime.datetime)):
        return obj.isoformat()
    raise TypeError("Type %s not serializable" % type(obj))

class Feature(db.Model):
    id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True)
    title = db.Column(db.String(64), nullable=False)
    description = db.Column(db.String(255), nullable=False)
    client = db.Column(db.String(64), nullable=False)
    client_priority = db.Column(db.Integer, nullable=False)
    target_date = db.Column(db.Date)
    product_area = db.Column(db.String(64), nullable=False)

    def as_dict(self):
        return {c.name: getattr(self, c.name) for c in self.__table__.columns}

if __name__ == "__main__":
    app.run(host='0.0.0.0')


import csv
import matplotlib.pyplot as plt
import numpy as np
import os

# Increase the maximum field size to handle large files
csv.field_size_limit(10000000)

def calc_length(s):
    """Calculate the number of characters excluding delimiters and encapsulators."""

    # Preconditions
    assert isinstance(s, list)

    return sum([len(x) for x in s])

def calc_doc_lengths(filepath, delimiter, encapsulator):
    """Calculate the length of the documents."""

    # Preconditions
    assert os.path.exists(filepath), f"File doesn't exist: {filepath}"
    assert isinstance(delimiter, str)
    assert isinstance(encapsulator, str)

    # List of the lengths of each document
    doc_lengths = []

    with open(filepath, 'r', encoding='utf8') as fp:
        reader = csv.reader(fp, delimiter=delimiter, quotechar=encapsulator)

        num_rows_read = 0

        for row in reader:
            doc_lengths.append(calc_length(row))
            num_rows_read += 1

    print(f"Read {num_rows_read} rows from {filepath}")

    return doc_lengths

def spacing_ratio(n):
    """Calculate n-1 even ratios."""

    # Preconditions
    assert n > 1

    return [x/n for x in list(range(1, n))]

def calc_break_points(cum_doc_lengths, num_files):
    """Calculate breaks (row indicies) in the input file."""

    # Preconditions
    assert isinstance(doc_lengths, list)
    assert num_files > 1

    # Total number of characters
    total = cum_doc_lengths[-1]

    return [np.argmin(abs(cum_doc_lengths - r*total)) for r in spacing_ratio(num_files)]

class BatchedCsvWriter:
    def __init__(self, folder, prefix, delimiter, encapsulator, header):

        # Preconditions
        assert os.path.exists(folder)
        assert isinstance(prefix, str)
        assert isinstance(delimiter, str)
        assert encapsulator is None or isinstance(encapsulator, str)
        assert isinstance(header, list)

        self.folder = folder
        self.prefix = prefix
        self.delimiter = delimiter
        self.encapsulator = encapsulator
        self.header = header

        # File pointer
        self.fp = None

        # CSV writer
        self.writer = None

        # Current index of the file
        self.current_index = -1

    def start_new_file(self):
        """Start a new output file."""

        self.current_index += 1

        # Create the filepath
        filepath = os.path.join(
            self.folder, f"{self.prefix}-{self.current_index}.csv")
        print(f"Writing to file: {filepath}")

        # Open the file for writing
        self.fp = open(filepath, 'w', encoding='utf8', newline='')
        self.writer = csv.writer(self.fp)

        # Add the header to the file
        self.add_row(self.header)

    def add_row(self, row):
        """Add a row of data to the output file."""

        # Preconditions
        assert isinstance(row, list)

        # Start a new file if this is the first row
        if self.fp is None:
            self.start_new_file()

        self.writer.writerow(row)

    def close(self):
        """Close the file."""

        if self.fp is not None:
            self.fp.close()

def split(filepath, delimiter, encapsulator, output_folder, prefix, cuts):
    """Split a CSV file into smaller files."""

    # Preconditions
    assert os.path.exists(filepath)
    assert isinstance(delimiter, str)
    assert encapsulator is None or isinstance(encapsulator, str)
    assert os.path.exists(output_folder)
    assert isinstance(prefix, str)
    assert isinstance(cuts, list) and len(cuts) > 0

    with open(filepath, 'r', encoding='utf8') as fp:
        reader = csv.reader(fp, delimiter=delimiter, quotechar=encapsulator)

        # Read the header
        header = next(reader)

        # Initialise the CSV writer
        writer = BatchedCsvWriter(
            output_folder, prefix, delimiter, encapsulator, header)

        num_rows_read = 0

        for row in reader:

            num_rows_read += 1

            # Should a new file be started?
            if num_rows_read in cuts:
                writer.start_new_file()

            writer.add_row(row)

        print(f"Read {num_rows_read} data rows from {filepath}")
        writer.close()

def plot_doc_lengths(doc_lengths):
    """Plot the length of each document as a function of document index."""

    # Preconditions
    assert isinstance(doc_lengths, list)
    assert len(doc_lengths) > 0

    plt.plot(doc_lengths)
    plt.xlabel("Row index")
    plt.ylabel("Number of characters")

    plt.savefig("doc_lengths.png")
    plt.show()

def plot_break_points(cum_doc_lengths, cuts):
    """Plot the break points for the files"""

    # Preconditions
    assert isinstance(doc_lengths, list)
    assert len(doc_lengths) > 0
    assert isinstance(cuts, list)
    assert len(cuts) > 0

    plt.plot(cum_doc_lengths, '-g')

    for cut in cuts:
        plt.plot([0, len(cum_doc_lengths)], [
                 cum_doc_lengths[cut], cum_doc_lengths[cut]], '--r')

    plt.xlabel("Row index")
    plt.ylabel("Cumulative total number of characters")

    plt.savefig("break_points.png")
    plt.show()

if __name__ == '__main__':

    # Location of the input CSV file to split
    filepath = r"./data/input.csv"

    # CSV file parameters
    delimiter = ","
    encapsulator = "|"

    # Number of files to split the input file into
    num_files = 4

    # Location of the output (split) files
    output_folder = r"./data/"
    prefix = "split"

    # Calculate the length of each document (row) in the CSV file
    print(f"Calculating the lengths of each row in {filepath} ...")
    doc_lengths = calc_doc_lengths(filepath, delimiter, encapsulator)
    plot_doc_lengths(doc_lengths)

    # Cumulative sum of the document lengths
    # Using int64 to avoid overflow issues
    cum_total = np.cumsum(np.int64(doc_lengths))

    # Calculate the 'break' indices
    cuts = calc_break_points(cum_total, num_files)
    plot_break_points(cum_total, cuts)

    # Split the CSV file
    split(filepath, delimiter, encapsulator, output_folder, prefix, cuts)


board = [
    '-', '-', '-',
    '-', '-', '-',
    '-', '-', '-',
]

game_on = True

winner = None

current_player = "Presh"

def board_view():
    print(board[0] + '|' + board[1] + '|' + board[2])
    print(board[3] + '|' + board[4] + '|' + board[5])
    print(board[6] + '|' + board[7] + '|' + board[8])

def player_turn():
    global current_player
    if current_player == "Presh":
        current_player = "Gideon"
    elif current_player == "Gideon":
        current_player = "Presh"

def game_control():
    print()
    print(current_player + "'s turn")

    valid = False
    while not valid:
        position = input('choose a number between 1-9: ')

        while position not in ['1', '2', '3', '4', '5', '6', '7', '8', '9']:
            position = input('Not a valid item, Try again: ')

        position = int(position) - 1
        if board[position] == "-":
            valid = True
        else:
            print('Try a different position.')

    board[position] = current_player
    board_view()

def check_if_game_end():
    check_winner()
    check_tie()

def check_winner():
    global winner
    row_winner = check_row()
    column_winner = check_column()
    diagonal_winner = check_diagonal()

    if row_winner:
        winner = row_winner
    elif column_winner:
        winner = column_winner
    elif diagonal_winner:
        winner = diagonal_winner
    else:
        winner = None

def check_row():
    global game_on
    row_1 = board[0] == board[1] == board[2] != "-"
    row_2 = board[3] == board[4] == board[5] != "-"
    row_3 = board[6] == board[7] == board[8] != "-"

    if row_1 or row_2 or row_3:
        game_on = False

    if row_1:
        return board[0]
    if row_2:
        return board[3]
    if row_3:
        return board[6]

def check_column():
    global game_on

    column_1 = board[0] == board[3] == board[6] != "-"
    column_2 = board[1] == board[4] == board[7] != "-"
    column_3 = board[2] == board[5] == board[8] != "-"

    if column_1 or column_2 or column_3:
        game_on = False

    if column_1:
        return board[0]
    elif column_2:
        return board[1]
    elif column_3:
        return board[2]

def check_diagonal():
    global game_on
    diagonals_1 = board[0] == board[4] == board[8] != "-"
    diagonals_2 = board[2] == board[4] == board[6] != "-"

    if diagonals_1 or diagonals_2:
        game_on = False

    if diagonals_1:
        return board[0]
    elif diagonals_2:
        return board[6]

def check_tie():
    global game_on
    if "-" not in board:
        game_on = False

def play_game():
    global winner
    board_view()
    while game_on:
        game_control()

        check_if_game_end()

        player_turn()

    if winner == "Presh" or winner == "Gideon":
        print(winner + " won!!")
    elif winner == None:
        print("Tie!")

play_game()


from io import StringIO
from io import open
from operator import contains
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
import time
import os

# process pdf
def read_pdf(pdf):
    # resource manager
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    laparams = LAParams()
    # device
    device = TextConverter(rsrcmgr, retstr, laparams=laparams)
    process_pdf(rsrcmgr, device, pdf)
    device.close()
    content = retstr.getvalue()
    retstr.close()
    # get lines
    lines = str(content).split("\n")
    return lines

# get key parts
def key_parts(path):
    list_of_content = []
    list_of_keys = []
    try:
        with open(path, "rb") as my_pdf:
            list_of_content = read_pdf(my_pdf)
            # print(len(list_of_content))

            for i in range(50, len(list_of_content) - 200):
                if len(list_of_content[i]) >= 15:
                    list_of_keys.append(list_of_content[i])
    except:
        pass
    return list_of_keys

# form Q
def generateQ(parts):
    str = ""
    for part in parts:
        # print(part)
        str += part
    return str

def read_all(in_directory, out_directory, key_directory):
    for filename in os.listdir(in_directory):
        f = os.path.join(in_directory, filename)
        name = filename.split('.')[0]
        try:
            if os.path.isfile(f):
                ret = generateQ(key_parts(f))
                txt_name = os.path.join(out_directory, f'{name}.txt')
                print(f'OUT: {txt_name}')
                with open(txt_name, "w") as txt:
                    txt.write(ret)
                    txt.close()
        except:
            try:
                os.remove(key_directory + name + '.pdf.txt')
            except FileNotFoundError:
                pass

if __name__ == '__main__':
    # read_all("/Users/donglianghan/Desktop/NLP_for_NASA/pdfs","/Users/donglianghan/Desktop/NLP_for_NASA/raw_data/q"
    read_all("./pdf_pool", "./seq2seq/rawdata/q", "./seq2seq/rawdata/a/")