import click
import os
import re
from googletrans import Translator
from base import BotManager
from settings import SPRINGER_LINK, SCI_HUB_LINK, ARTICLE_LINK
from api import get_proxy_ips

translator = Translator()

class Downloader(BotManager):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.topic = kwargs.get("topic")
        self.start = kwargs.get("start")
        self.end = kwargs.get("end")
        self.page_number = kwargs.get("page")
        self.page_range = kwargs.get("page_range")
        self.query = kwargs.get("search_key")
        self.discipline = kwargs.get("discipline")
        self.proxies = kwargs.get("proxies")

    def open_springer(self):
        if self.browser is None:
            self.create_browser()
        self.open_new_page()
        # self.go_to_link(SPRINGER_LINK)

    def select_topic(self):
        self.wait_element_loading('[id="Discipline"]')
        self.click_element(f"text={self.topic}")
        self.sleep(3)
        self.wait_element_loading('[id="date-facet"]')

    def filter_by_date_article(self):
        self.click_element("text=Date Published")
        self.sleep(1)
        self.wait_element_loading('[id="start-year"]')
        self.reinsert_value('[id="start-year"]', 2019)
        self.sleep(1)
        self.reinsert_value('[id="end-year"]', 2022)
        self.sleep(1)
        self.click_element('[id="date-facet-submit"]')
        self.wait_element_loading('[id="content-type-facet"]')

    def get_search_results(self):
        ## article link https://link.springer.com/search?date-facet-mode=between&facet-start-year=2019&facet-content-type=%22Article%22&facet-discipline=%22Materials+Science%22&facet-end-year=2022
        # self.wait_element_loading('[id="results-list"]')
        link_results = []
        title_results = []
        for page_number in self.page_range:
            search_link = ARTICLE_LINK.format(
                page=page_number,
                start=self.start,
                end=self.end,
                query=self.query,
                discipline='+'.join(self.discipline.split(' '))
            )

            self.open_new_page()
            self.go_to_link(search_link)
            try:
                self.wait_element_loading('[id="results-list"]')
                content = """() => {
                    let links = []
                    let titles = []
                    const lists = document.querySelector('[id="results-list"]').querySelectorAll('li')
                    for (let i=0; i<lists.length; i ++) {
                        list = lists[i]
                        anchor = list.querySelector('a').href
                        title = list.querySelector('a').innerText
                        links.push(anchor)
                        titles.push(title)
                    }
                    return [links, titles]
                }
                """
                page_results = self.page.evaluate(content)
                link_results = link_results + page_results[0]
                title_results = title_results + page_results[1]
                self.page.close()
            except Exception as e:
                self.page.close()
        return [link_results, title_results]

    def download_pdfs(self, results):
        success_number = 0
        anchor_list = results[0]
        title_list = results[1]

        for i in range(len(anchor_list)):
            anchor = anchor_list[i]
            title = title_list[i]
            try:
                self.open_new_page()
                print("anchor: " + anchor)
                self.go_to_link(anchor)
                self.wait_element_loading("text=Cite this article")
                self.click_element("text=Cite this article")
                self.wait_element_loading('[class="c-bibliographic-information__value"]')

                content = """
                    ()=> {
                        return document.querySelector('[class*="c-bibliographic-information__list-item--doi"]').querySelector('[class="c-bibliographic-information__value"]').innerText
                    }
                """
                doi = self.page.evaluate(content)
                print(doi)
                self.go_to_link(SCI_HUB_LINK)
                self.wait_element_loading('[type="textbox"]', 30000)
                self.insert_value('[type="textbox"]', doi)
                self.sleep(1)
                self.hit_enter()
                self.sleep(10)

                with self.page.expect_download() as download_info:
                    content = """
                        ()=>{
                            document.querySelector('#buttons').querySelector('button').click()
                        }
                    """
                    self.page.evaluate(content)
                download = download_info.value
                title = re.sub('[^A-Za-z0-9]+',' ', title)
                translated = translator.translate(title, dest='ko')
                filename = translated.text + '.pdf'
                download.save_as(filename)
                os.replace(os.path.join(os.getcwd(), filename),self.discipline + "/" + self.query + "/" + filename)
                self.page.close()
                success_number = success_number + 1
            except Exception as e:
                print("error", e)
                self.page.close()
        print(f"Total {len(anchor_list)}, success: {success_number}")

    def run(self):
        self.open_springer()
        results = self.get_search_results()
        if len(results[0]):
            total = len(results[0])
            print(f"Total search results: {total}, Downloading...")
            self.download_pdfs(results)
            print("Finished downloading.")
        else:
            print("No search results. Just change query or discipline.")

@click.command()
@click.option(
    "--start",
    default=2021,
    help="Start Year.",
    prompt="Input start year number, default is 2021.",
)
@click.option(
    "--end", default=2022, help="End Year.", prompt="Input end year, default is 2022."
)
@click.option(
    "--start_page",
    default=1,
    help="Start page to download",
    prompt="Input start page number, default is 1.",
)
@click.option(
    "--end_page",
    default=10,
    help="End page to download",
    prompt="Input end page number, default is 10.",
)
@click.option(
    "--discipline",
    default="Engineering",
    prompt="Input discipline, default is Environment",
    help="https://link.springer.com/search?date-facet-mode=between&query=recycling&facet-end-year=%7Bend_year%7D&facet-language=%22En%22&facet-start-year=%7Bstart_year%7D",
)
@click.option(
    "--query", default="agriculture machine", help="Query to download", prompt="Insert query"
)
def main(start, end, start_page, end_page, query, discipline):
    try:
        os.makedirs(discipline + '/' + query)
    except:
        pass

    bot = Downloader(
        start=start,
        end=end,
        use_chrome=False,
        page_range=range(start_page, end_page),
        search_key=query,
        discipline=discipline,
    )
    bot.run()

if __name__ == "__main__":
    main()


import pygame, sys

class Duck(pygame.sprite.Sprite):
    def __init__(self, pos_x, pos_y, picture_path):
        super().__init__()
        self.image = pygame.image.load(picture_path)
        self.rect = self.image.get_rect()
        self.colisao = pygame.mixer.Sound("Colisões e Gameover\Assets\Hit_02.wav")
        self.rect.center = [pos_x, pos_y]

    def update(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_w] and self.rect.top > 0 + 20:
            self.rect.y -= 3
        if keys[pygame.K_s] and self.rect.bottom <= screen_y - 20:
            self.rect.y += 3
        if keys[pygame.K_a] and self.rect.left >= 0 + 20:
            self.rect.x -= 3
        if keys[pygame.K_d] and self.rect.right <= screen_x - 20:
            self.rect.x += 3
        print(self.rect.y, self.rect.x)

    def colisao1(self):
        self.colisao.play()

class Boulder(pygame.sprite.Sprite):
    def __init__(self, picture_path):
        super().__init__()
        self.image = pygame.image.load(picture_path)
        self.rect = self.image.get_rect()
        self.rect.center = [400, 200]

class GameOver(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load("Colisões e Gameover\Assets\gameover_tam_2.png")
        self.rect = self.image.get_rect()
        self.rect.center = [360, 100]

# Genaral setup
pygame.init()
clock = pygame.time.Clock()

# Game screnn
screen_x = 720
screen_y = 400
screen = pygame.display.set_mode((screen_x,screen_y))
pygame.mouse.set_visible(False)
background = pygame.image.load(r"Colisões e Gameover\Assets\background.png")

# Duck
duck = Duck(40, 50,"Colisões e Gameover\Assets\Idle_002-1.png")
duck_group = pygame.sprite.Group()
duck_group.add(duck)

# Builder
boulder = Boulder(r"Colisões e Gameover\Assets\boulder.png")
boulder_group = pygame.sprite.Group()
boulder_group.add(boulder)

# GameOver
gameover_img = GameOver()
gameover_group = pygame.sprite.Group()
gameover_group.add(gameover_img)

# GameStatus
game_over = True
running = True

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            raise SystemExit

    if duck.rect.colliderect(boulder.rect) and running == True:
        duck.colisao1()
        running = False

    screen.fill((205, 227, 238))
    screen.blit(background,(0,0))

    duck_group.draw(screen)
    if running == True:
        duck_group.update()

    boulder_group.draw(screen)
    boulder_group.update()

    if running == False:
        gameover_group.draw(screen)
        gameover_group.update()

    pygame.draw.rect(screen, "black", (0,0,20,400), 20)
    pygame.draw.rect(screen, "black", (700,0,20,400), 20)
    pygame.draw.rect(screen, "black", (0,380,720,20), 20)
    pygame.draw.rect(screen, "black", (0,0,720,20), 20)

    pygame.display.flip()
    clock.tick(60)


import functools
import string
from dataclasses import dataclass
from typing import Dict, List, Mapping
from speculos.observer import TextEvent
from . import bagl_font

from construct import Struct, Int8ul, Int16ul

nbgl_area_t = Struct(
    "x0" / Int16ul,
    "y0" / Int16ul,
    "width" / Int16ul,
    "height" / Int16ul,
    "color" / Int8ul,
    "bpp" / Int8ul,
)

MIN_WORD_CONFIDENCE_LVL = 0  # percent
NEW_LINE_THRESHOLD = 10  # pixels

BitMap = bytes
BitVector = str  # a string of '1' and '0'
Width = int  # width
CharWidth = Width
Char = str  # a single character string (chars are 1-char strings in Python)

@dataclass
class BitMapChar:
    char: bagl_font.FontCharacter
    bitmap: bytes

__FONT_MAP: Dict[int, Mapping[str, BitMapChar]] = {}

DISPLAY_CHARS = string.ascii_letters + string.digits + string.punctuation

def cache_font(f):
    __font_char_cache = {}

    @functools.wraps(f)
    def wrapper(byte_string: bytes):
        if byte_string not in __font_char_cache:
            __font_char_cache[byte_string] = f(byte_string)
        return __font_char_cache[byte_string]
    return wrapper

def split(bits: BitVector, n: Width) -> List[BitVector]:
    """
    Split a bit array (string of '1' and '0')
    into an arbitrary list of n-sized bit arrays.

    Useful if you want to display a character from a bitmap
    """
    output = []
    bit_list = bits[:]
    while bit_list:
        bit_list_to_append = bit_list[:n]
        # do padding
        # bit_list_to_append += '0' * (n - len(bit_list_to_append))
        output.append(bit_list_to_append)
        bit_list = bit_list[n:]
    return output

def split_bytes(bytes_elems: BitMap, n: CharWidth):
    """Useful to display a bitmap character"""
    bits = "".join("{0:08b}".format(x)[::-1] for x in bytes_elems)
    return split(bits, n)

def get_font(font_id: int) -> bagl_font.Font:
    font = bagl_font.get(font_id)
    if not font:
        raise ValueError(f"Could not get font with font_id={font_id}")
    return font

def get_char(font: bagl_font.Font, char: str) -> BitMapChar:
    if len(char) != 1 or char not in DISPLAY_CHARS:
        raise ValueError(f"could not print {char}")
    return get_font_map(font)[char]

def display_char(font: bagl_font.Font, char: str) -> None:
    bm_char = get_char(font, char)
    print("\n".join(split_bytes(bm_char.bitmap, font.bpp * bm_char.char.char_width)))

def get_font_map(font: bagl_font.Font):
    if font.font_id not in __FONT_MAP:
        __FONT_MAP[font.font_id] = _get_font_map(font)
    return __FONT_MAP[font.font_id]

def _get_font_map(font: bagl_font.Font) -> Mapping[Char, BitMapChar]:
    font_map = {}
    for ord_char, font_char in zip(
        range(font.first_char, font.last_char), font.characters
    ):
        font_map[chr(ord_char)] = BitMapChar(
            font_char,
            bytes(
                font.bitmap[
                    font_char.bitmap_offset:(
                        font_char.bitmap_offset
                        + font_char.bitmap_byte_count
                    )
                ]
            ),
        )
    return font_map

class OCR:

    # Maximum space for a letter to be considered part of the same word
    MAX_BLANK_SPACE_NANO = 12
    MAX_BLANK_SPACE_STAX = 24

    def __init__(self, model: str):
        self.events: List[TextEvent] = []
        # Store the model of the device
        self.model = model
        # Maximum space for a letter to be considered part of the same word
        if model == "stax":
            self.max_blank_space = OCR.MAX_BLANK_SPACE_STAX
        else:
            self.max_blank_space = OCR.MAX_BLANK_SPACE_NANO

    @staticmethod
    def find_char_from_bitmap(bitmap: BitMap) -> str:
        """
        Find a character from a bitmap
        >>> font = get_font(4)
        >>> char = get_char(font, 'c')
        >>> find_char_from_bitmap(char.bitmap)
        'c'
        """
        all_values = []
        for font in bagl_font.FONTS:
            font_map = get_font_map(font)
            for character_value, bitmap_struct in font_map.items():
                if bitmap_struct.bitmap.startswith(bitmap):
                    # sometimes (but not always) the bitmap being passed is shortened
                    # by one '\x00' byte, not matching the exact bitmap
                    # provided in the font. Hence the 'residual' computation
                    residual_bytes: bytes = bitmap_struct.bitmap[len(bitmap):]
                    if all(b == 0 for b in residual_bytes):
                        all_values.append(character_value)
            if all_values:
                char = max([x for x in all_values])
                if char == "\x80":
                    char = " "
                return char
        return ""

    def find_bitmap(self, x: int, y: int, w: int, h: int, bitmap: bytes) -> None:
        char = self.find_char_from_bitmap(bitmap)
        if char:
            if self.events and y <= self.events[-1].y:
                self.events[-1].text += char
            else:
                # create a new TextEvent if there are no events yet
                # or if there is a new line
                self.events.append(TextEvent(char, x, y, w, h))

    def store_char_in_last_event(self, x: int, y: int, w: int, h: int, char: str) -> None:
        """
        Add current character to last event
        """
        self.events[-1].text += char
        # Update w for all chars in self.events[-1]
        x2 = x + w - 1
        self.events[-1].w = x2 - self.events[-1].x + 1
        # Update y & h, if needed, for all chars in self.events[-1]
        y1 = y
        if y1 > self.events[-1].y:
            # Keep the lowest Y in Y1
            y1 = self.events[-1].y
        y2 = y + h - 1
        if y2 < (self.events[-1].y + self.events[-1].h):
            # Keep the highest Y in Y2
            y2 = self.events[-1].y + self.events[-1].h - 1
        self.events[-1].y = y1
        self.events[-1].h = y2 - y1 + 1

    def add_character(self, x: int, y: int, w: int, h: int, char: str) -> None:
        """
        Add the provided character to previous event or create a new one
        """
        # Compute difference with X coord from previous event
        # if x_diff > self.max_blank_space the char is not on same sentence
        if self.events:
            x_diff = x - (self.events[-1].x + self.events[-1].w)
            if x_diff < 0:
                x_diff = -x_diff
            # Try to find if that char can be added to previous event
            if y < (self.events[-1].y + self.events[-1].h) \
               and x_diff < self.max_blank_space:
                # Add this character to previous event
                self.store_char_in_last_event(x, y, w, h, char)
                return

        # create a new TextEvent if there are no events yet or if there is a new line
        self.events.append(TextEvent(char, x, y, w, h))

    def analyze_bitmap(self, data: bytes) -> None:
        """
        data contain information about the latest displayed bitmap.
        Since unified SDK, speculos added the displayed character to data.
        For older SKD versions, legacy behaviour is used: parsing internal
        fonts to find a matching bitmap.
        """
        if self.model == "stax":
            # Can be called via SephTag.NBGL_DRAW_IMAGE or SephTag.NBGL_DRAW_IMAGE_RLE
            # In both cases, data contains:
            # - area (sizeof(nbgl_area_t))
            # - compressed bitmap (buffer_len)
            # - 2 bytes of different meaning depending on SephTag
            # - 4 bytes with unicode code point of displayed character
            area = nbgl_area_t.parse(data[0:nbgl_area_t.sizeof()])
            x, y, w, h = area.x0, area.y0, area.width, area.height
            character = int.from_bytes(data[-4:], byteorder="little", signed=False)
            bitmap = data[nbgl_area_t.sizeof():-(2+4)]
        else:
            if data[0] != 0:
                return

            x = int.from_bytes(data[1:3], byteorder="big", signed=True)
            y = int.from_bytes(data[3:5], byteorder="big", signed=True)
            w = int.from_bytes(data[5:7], byteorder="big", signed=True)
            h = int.from_bytes(data[7:9], byteorder="big", signed=True)
            bpp = int.from_bytes(data[9:10], byteorder="big")
            character = int.from_bytes(data[10:14], byteorder="big", signed=False)
            color_size = 4 * (1 << bpp)
            bitmap = data[14+color_size:]

            # h may no reflect the real height: use number of lines displayed
            h = (len(bitmap) * 8) // w
            if (len(bitmap) * 8) % w:
                h += 1

        # Space is now encoded as an empty character (no 'space' wasted :)
        if len(bitmap) == 0:
            character = 32

        # If data contains a character, don't bother doing OCR, just store it!
        if character != 0:
            char = chr(character)
            self.add_character(x, y, w, h, char)
        else:
            self.find_bitmap(x, y, w, h, bitmap)

    def get_events(self) -> List[TextEvent]:
        events = self.events.copy()
        self.events = []
        return events


#! /usr/bin/env python3

import sys

class InputError(Exception):
    pass

USAGE = (f"usage: {sys.argv[0]} <number1> <number2>\n"
         f"Example:\n\tpython operations.py 10 3")

def prog(*args):
    if len(args) is 1:
        raise InputError("not enough arguments")
    elif len(args) > 2:
        raise InputError("too many arguments")

    try:
        nb1, nb2 = int(args[0]), int(args[1])
    except ValueError:
        raise InputError("only numbers")

    def getDiv(nb1, nb2):
        try:
            return nb1 / nb2
        except ZeroDivisionError:
            return "ERROR (div by zero)"

    def getMod(nb1, nb2):
        try:
            return nb1 % nb2
        except ZeroDivisionError:
            return "ERROR (modulo by zero)"

    print(f"Sum:\t\t{nb1 + nb2}\n"
          f"Difference:\t{abs(nb1 - nb2)}\n"
          f"Product:\t{nb1 * nb2}\n"
          f"Sum:\t\t{getDiv(nb1, nb2)}\n"
          f"Sum:\t\t{getMod(nb1, nb2)}\n")

if __name__ == "__main__":
    if len(sys.argv) is 1:
        print(USAGE)
        sys.exit(1)
    try:
        prog(*sys.argv[1:])
    except Exception as e:
        print(f"InputError: {e}", type(e))
        print()
        print(USAGE)
        sys.exit(1)


import PyPDF2
import json
import elasticsearch
from elasticsearch import Elasticsearch

def get_all_books():
    es = None
    # es = Elasticsearch([{'host': 'localhost', 'port': 9200}])
    es = Elasticsearch(
   [{
      'host': str("localhost"),
      'port': 9200,
      'scheme': "http"
   }],
   basic_auth = (str("elastic"), str("9jc8ja9lpPK3P28ihfQ0"))
)
    if es.ping():
        print('Yupiee  Connected ')
    else:
        print('Awww it could not connect!')
    total = []
    res = es.search(index="file", body = {
    'size' : 100,
    'query': {
        'match_all' : {}
    }
    })
    for hit in res['hits']['hits']:
        total.append(hit['_source'])
    return total

print(json.dumps(get_all_books()))


import matplotlib.pyplot as plt
from persim import plot_diagrams

def scatterplot(
    x_coords,
    y_coords,
    color,
    z_coords=None,
    dim=2,
    engine="matplotlib",
    save=False,
    name="images/test.png",
):
    if engine == "matplotlib":
        if dim == 2:
            fig = plt.figure()
            ax = fig.add_subplot()
            ax.scatter(x_coords, y_coords, c=color)
        if dim == 3:
            fig = plt.figure()
            ax = fig.add_subplot(projection="3d")
            ax.scatter(x_coords, y_coords, z_coords, c=color)
    if save:
        fig.savefig(name)
    return fig

def plot_line(x_range, y_range, label=None, title=None, save=False, filename=None):
    fig = plt.figure()
    ax = fig.add_subplot()
    ax.plot(x_range, y_range, label=label)
    fig.suptitle(title)
    if save:
        fig.savefig(filename)

def plot_lines(
    x_ranges,
    y_ranges,
    stds=None,
    labels=None,
    titles=None,
    fig_title=None,
    xlabels=None,
    share_x_range=True,
    save=True,
    filename="",
    **kwargs
):
    fig, axs = plt.subplots(**kwargs)
    axs = axs.flatten()
    n_axes = len(y_ranges)
    if share_x_range:
        x_ranges = [x_ranges] * n_axes
    for i, x_range in enumerate(x_ranges):
        for j, y_range in enumerate(y_ranges[i]):
            axs[i].plot(x_range, y_range, label=labels[i][j])
            axs[i].fill_between(
                x_range, y_range - stds[i][j], y_range + stds[i][j], alpha=0.1
            )
        axs[i].set_xlabel(xlabels[i])
        axs[i].set_title(titles[i])
        axs[i].legend(loc="best")
    fig.suptitle(fig_title)
    if save:
        fig.savefig(filename)

def lineplot(
    x_range,
    y_ranges,
    stds=None,
    title=None,
    labels=None,
    xlabel=None,
    ylabel=None,
    save=True,
    filename=True,
):
    plt.cla()
    for i, y_range in enumerate(y_ranges):
        plt.plot(x_range, y_range, "D-", label=labels[i])
        plt.fill_between(x_range, y_range - stds[i], y_range + stds[i], alpha=0.1)
    plt.xlabel(xlabel)
    plt.ylabel(ylabel)
    plt.title(title)
    plt.legend(loc="best")
    if save:
        plt.savefig(filename)

def plot_dgm(dgm, **kwargs):
    return plot_diagrams(dgm, show=True, **kwargs)

def main():
    pass

if __name__ == "__main__":
    main()


from bs4 import BeautifulSoup, SoupStrainer
import requests

#url = "https://dr-stone.org/"

def grab_webtoon_chapter_links(url):
    page = requests.get(url)
    data = page.text
    soup = BeautifulSoup(data)
    list_of_links = []

    for link in soup.find_all('a'):
        if "https://dr-stone.org/manga/dr-stone-chapter-" in link.get('href'):
            list_of_links.append(link.get('href'))
            #print(link.get('href'))
    return list_of_links


class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        nums_len = len(nums)
        ret = []
        for i in range(nums_len - 3):
            if i and nums[i - 1] == nums[i]:
                continue
            sol = self.threeSum(nums, i + 1, target, nums[i])
            ret += sol
        return ret
    def threeSum(self, nums, st, target, x0):
        nums_len = len(nums)
        ret = []
        for i in range(st, nums_len):
            if i > st and nums[i - 1] == nums[i]:
                continue
            l, r = i + 1, nums_len - 1
            while True:
                while i + 1 < l and nums[l - 1] == nums[l] and l < r:
                    l += 1
                while r < nums_len - 1 and nums[r] == nums[r + 1] and l < r:
                    r -= 1
                if l >= r:
                    break
                cur_sum = x0 + nums[i] + nums[l] + nums[r]
                if cur_sum < target:
                    l += 1
                elif cur_sum == target:
                    ret.append([x0, nums[i], nums[l], nums[r]])
                    l += 1
                else:
                    r -= 1
        return ret


class Solution:
    """
    Implement pow(x, n), which calculates x raised to the power n (i.e., xn).

    Constraints:
    - -100.0 < x < 100.0
    - -2^31 <= n <= 2^31-1
    - n is an integer.
    - Either x is not zero or n > 0.
    - -10^4 <= xn <= 10^4
    """

    def myPow(self, x: float, n: int) -> float:
        """
        Square and multiply algorithm.
        Note that this implementation makes use of the "either x is not zero
        or n > 0" constraint.
        O(log(n)) / O(1)    time / space complexity
        """
        if n < 0:
            exponent_is_negative = True
            # if exponent is negative, use absolute value
            n = -n
        else:
            exponent_is_negative = False

        result = 1
        # square and multply
        current_square = x
        bit_mask = 1
        while bit_mask <= n:
            # if n has bit set at current bitmask bit, then multiply result with current square
            if bit_mask & n:
                result *= current_square
            # move on to next bit
            bit_mask <<= 1
            # square the current square value
            current_square *= current_square

        # if exponent is negative, return inverse of result
        if exponent_is_negative:
            return 1 / result
        return result


import sys
sys.path.append('../')
from tkinter import filedialog as fd
from PIL import Image, ImageTk
from backend.interface import *
from backend.analyzer import remove_comments
import os
import tkinter as tk
import time

class SourceAnalyzer:
    '''
    A class used as the main structure for the Tkinter based GUI.

    Methods:
    ----------

        File Selection:
        ----------------
            open_file1:
                    Responsible for student file addition
            clear_file1:
                    Responsible for clearing student files
            open_file2:
                    Responsible for boilerplate file addition
            clear_file2:
                    Responsible for clearing boilerplate files

        Backend Interface:
        ----------------
            export_files:
                    Sends student/boilerplate files to and nitializes filetofingerprint objects from the backend,
                    ensures more than one student file is sent, and that boilerplate files can't be identical to student files.
            get_output:
                    Responsible for printing at-a-glance results between two files, and issues warnings if incorrect analyzer is used.
            gather_reg_fingerprints:
                    With two provided filetofingerprint objects (based on tracking indexes in a class variable), and other user input data
                    (k, window size, ignore count), an in-depth comparison of the two files with eachother is done on the backend via
                    compare_files and get_fps functions. The documents are output to the GUI's side-by-side textboxes, and that output
                    is invisibly tagged with the locations of every found fingerprint (done searching for provided substrings). The tags
                    follow the format 'match#' with # being a number from 0 to (max fingerprints). This function also establishes the
                    number of fingerprints in a given comparison, as well as initializes the current fingerprint to 1.
            gather_most_fingerprints:
                    Very similar to gather_reg_fingerprints, only using backend functions pertaining specifically to most_important_fingerprints.
                    These matches are tagged using 'most#', and differs slightly in how the returned list/tuple structure is parsed.

        File Navigation:
        ----------------
            next_file1:
                    Responsible for increasing the value self.curr_index1, which keeps track of which file is currently being compared on the left.
            next_file2:
                    Responsible for increasing the value self.curr_index2, which keeps track of which file is being compared to on the right.
            prev_file1:
                    Responsible for decreasing self.curr_index1
            prev_file2:
                    Responsible for decreasing self.curr_index2

        Fingerprint Display:
        ----------------
            show_fp:
                    Called when 'View All' is toggled in order to update which fingerprints are being shown. Decides which version of show_fp to
                    run based on what type of fingerprint is being displayed.
            show_reg_fp:
                    Depending on whether 'View All' is selected, either highlights every tagged fingerprint, or highlights the first fingerprint and
                    initializes a class variable to track the current fingerprint. Note that the textbox is changed to 'normal' at the beginning and 'disabled' at the
                    end of the function, to ensure users can't edit information inside the textboxes.
            show_most_fp:
                    Very similar to show_reg_fp, only instead of highlighting the 'match#' tags, it highlights the 'most#' tags.

        Fingerprint Navigation:
        ----------------
            next_fp:
                    Responsible for incrementing to and highlighting the next fingerprint. Due to issues with overlapping fingerprints, the current tag must be
                    raised in rank to ensure it shows up in full, hence this function must lower the previous tag, raise this new one, and highlight it yellow. This
                    function contains the code for both the most_important and regular fingerprints, the only difference being the name of the tags.
            last_fp:
                    Very similar to next_fp, only responsible for going to the previous fingerprint.

        Other Functions:
        ----------------
            clear_output:
                    Runs when the Clear Output button is pressed, but also immediately once the Compare button is pressed. Resets all class variables and
                    clears text output on screen.
            mult_yview:
                    Allows the scroll bars on the side-by-side text boxes to move in sync (when clicked and dragged)
            report:
                    Responsible for generating the output report full of at-a-glance results.
            open_help:
                    Responsible for the help menu in the toolbar.

        Main Class:
        ----------------
            __init__:
                    Initializes class and runs create_widgets, which builds the GUI itself.
            create_widgets:
                    Responsible for creating and laying all the actual GUI elements: Frames, Buttons, Text-Boxes, etc. Also creates class variables.

    '''

#File Selection

    def open_file1(self):
        '''
        File selection for student files.
        '''
        if self.language_var.get() == "Python":
            files = fd.askopenfilenames(initialdir=os.getcwd(), title="Open File", filetypes=(("Python Files", "*.py"),("Text Files", "*.txt"),("Java Files", "*.java")))
        elif self.language_var.get() == "Java":
            files = fd.askopenfilenames(initialdir=os.getcwd(), title="Open File", filetypes=(("Java Files", "*.java"),("Python Files", "*.py"),("Text Files", "*.txt")))
        else:
            files = fd.askopenfilenames(initialdir=os.getcwd(), title="Open File", filetypes=(("Text Files", "*.txt"),("Python Files", "*.py"),("Java Files", "*.java")))
        # print(files)
        self.files1 = files
        for file in files:
            self.file_name1.insert(tk.END, file)

    def clear_file1(self):
        '''
        Clears student files.
        '''
        self.file1 = []
        self.file_name1.delete(0, tk.END)

    def open_file2(self):
        '''
        File selection for boilerplate files.
        '''
        if self.language_var.get() == "Python":
            files = fd.askopenfilenames(initialdir=os.getcwd(), title="Open File", filetypes=(("Python Files", "*.py"),("Text Files", "*.txt"),("Java Files", "*.java")))
        elif self.language_var.get() == "Java":
            files = fd.askopenfilenames(initialdir=os.getcwd(), title="Open File", filetypes=(("Java Files", "*.java"),("Python Files", "*.py"),("Text Files", "*.txt")))
        else:
            files = fd.askopenfilenames(initialdir=os.getcwd(), title="Open File", filetypes=(("Text Files", "*.txt"),("Python Files", "*.py"),("Java Files", "*.java")))
        # print(files)
        self.files2 = files
        for file in files:
            self.file_name2.insert(tk.END, file)

    def clear_file2(self):
        '''
        Clears boilerplate files.
        '''
        self.file2 = []
        self.file_name2.delete(0, tk.END)

#Backend Interface

    def export_files(self):
        '''
        Interfaces with backend based on user inputs (student files, parameters, etc.)

        Gathers list of files, and from that gathers a list of filetofingerprint objects, based on user parameters.
        Also ensures user input is valid (to an extent).

        '''

        #Clear current output before new comparison
        self.clear_output()

        file1 = self.file_name1.get(0, tk.END) #student
        file2 = self.file_name2.get(0, tk.END) #boilerplate

        #k and w from user inputs
        k = int(self.k_input.get())
        w = int(self.windowSizeInput.get())

        #Default displayed file indexes are 0 and 1 (first and second files of list)
        index1 = 0
        index2 = 1

        if (not (len(file1)<=1)): #Runs if there are at least 2 student files

            diff = True
            for x in file1:
                for y in file2:
                    if x == y:
                        diff = False
            if diff: #Runs if all student files are different from boilerplate files

                #File Output
                self.file1out = open(file1[index1], 'r').read()
                self.file2out = open(file1[index2], 'r').read()

                #Ignore count from user input
                ignorecount = int(self.ignore_input.get())

                #Python
                if self.language_var.get() == "Python":
                    file2fp_objs = compare_multiple_files_py(file1, k, w, file2, ignorecount)
                #Java
                elif self.language_var.get() == "Java":
                    file2fp_objs = compare_multiple_files_java(file1, k, w, file2, ignorecount)
                #Text
                else:
                    file2fp_objs = compare_multiple_files_txt(file1, k, w, file2, ignorecount)

                #Set class variables
                self.f2fp = file2fp_objs
                self.curr_index1 = index1
                self.curr_index2 = index2

                #Print at-a-glance output
                self.get_output()

            else:
                print("there exists a same file between boilerplate and student files")
                self.out_result.configure(state='normal')
                self.out_result.delete('1.0', tk.END)
                self.out_result.insert(tk.END, "There exists a same file between boilerplate and student files!")
                self.out_result.configure(state='disabled')

        else:
            self.out_result.configure(state='normal')
            self.out_result.delete('1.0', tk.END)
            self.out_result.insert(tk.END, "Please include more student files to compare!")
            self.out_result.configure(state='disabled')

    def get_output(self):
        '''
        Responsible for printing at-a-glance results between two files, and issues warnings if incorrect analyzer is used.
        '''

        self.out_result.configure(state='normal')

        self.out_result.delete('1.0', tk.END)

        #Python analyzer warning
        if self.language_var.get() == "Python":
            if self.f2fp[self.curr_index1].filename[(len(self.f2fp[self.curr_index1].filename) - 3):] != '.py' or self.f2fp[self.curr_index2].filename[(len(self.f2fp[self.curr_index2].filename) - 3):] != '.py':
                self.out_result.insert(tk.END, "WARNING: Used improper analyzer for file type. Results will be inaccurate!\n")

        #Java analyzer warning
        if self.language_var.get() == "Java":
            if self.f2fp[self.curr_index1].filename[(len(self.f2fp[self.curr_index1].filename) - 5):] != '.java' or self.f2fp[self.curr_index2].filename[(len(self.f2fp[self.curr_index2].filename) - 5):] != '.java':
                self.out_result.insert(tk.END, "WARNING: Used improper analyzer for file type. Results will be inaccurate!\n")

        #If files have enough fingerprints in common (determined on backend using ignore count), display output for them
        if self.f2fp[self.curr_index2] in self.f2fp[self.curr_index1].similarto:
            percentage = "{:.2%}".format(get_similarity(self.f2fp[self.curr_index1], self.f2fp[self.curr_index2]))
            f2fpstring = str("Files Compared: " + self.f2fp[self.curr_index1].filename + " and " + self.f2fp[self.curr_index2].filename + "\nPercentage Similarity: " + str(percentage) + "\nCommon Fingerprints: " + str(len(self.f2fp[self.curr_index1].similarto[self.f2fp[self.curr_index2]])))

        #Otherwise, state the similarity is negligible
        else:
            f2fpstring = str("Files Compared: " + self.f2fp[self.curr_index1].filename + " and " + self.f2fp[self.curr_index2].filename + "\nSimilarity between files deemed negligible via ignore count.")

        #Output to text box
        self.out_result.insert(tk.END, f2fpstring)

        self.out_result.configure(state='disabled')

        #Depending on what fingerprints are requested, run specified function
        if self.fp_type.get() == 0:
            self.gather_reg_fingerprints()
        else:
            self.gather_most_fingerprints()

    def gather_reg_fingerprints(self):
        '''
        Responsible for gathering regular fingerprints from backend, used for side-by-side comparison.
        '''

        self.out_text1.configure(state='normal')
        self.out_text2.configure(state='normal')

        #k and w from user input
        k = int(self.k_input.get())
        w = int(self.windowSizeInput.get())

        #Two files being compared side-by-side
        file1 = self.f2fp[self.curr_index1].filename
        file2 = self.f2fp[self.curr_index2].filename

        #Output of those files
        file1out = open(file1, 'r').read()
        file2out = open(file2, 'r').read()

        #If the analyzer is set to Java, remove comments from files
        if self.language_var.get() == "Java":
            file1out = remove_comments(file1out)
            file2out = remove_comments(file2out)

        if self.f2fp[self.curr_index2] in self.f2fp[self.curr_index1].similarto:

            #Python
            if self.language_var.get() == "Python":
                res, num_common_fps = compare_files_py(file1, file2, k, w, self.file_name2.get(0, tk.END))
                fp = get_fps_py(file1, file2, k, self.file_name2.get(0, tk.END))

            #Java
            elif self.language_var.get() == "Java":
                res, num_common_fps = compare_files_java(file1, file2, k, w, self.file_name2.get(0, tk.END))
                fp = get_fps_java(file1, file2, k, self.file_name2.get(0, tk.END))

            #Text
            else:
                res, num_common_fps = compare_files_txt(file1, file2, k, w, self.file_name2.get(0, tk.END))
                fp = get_fps_txt(file1, file2, k, self.file_name2.get(0, tk.END))

        else:
            fp = []

        #fp = self.f2fp[self.curr_index1].similarto[self.f2fp[self.curr_index2]]

        #Initialize tags
        for i in range(len(fp)):
            self.out_text1.tag_config("match" + str(i), background='white')
            self.out_text2.tag_config("match" + str(i), background='white')

        #Clear text boxes, and add file outputs
        self.out_text1.delete('1.0', tk.END)
        self.out_text2.delete('1.0', tk.END)
        self.out_text1.insert(tk.END, file1out)
        self.out_text2.insert(tk.END, file2out)

        #Used to progress the search through the file, so multiple instances of the same substring aren't caught.
        index_track1 = '1.0'
        fp_track = 0
        remove_fps = []

        #For each fingerprint
        for fingerprint in fp:

            index_track2 = '1.0'
            increment_fp = True

            new_tag1 = ''
            new_tag2 = ''

            #Parse through all substrings in File 1 for a given fingerprint, tagging them for this fingerprint
            for i in range(len(fingerprint[0])):
                new_tag1 = self.out_text1.search(fingerprint[0][i].substring, index_track1, tk.END, exact=False)

                if new_tag1 != '':
                    '''print("1 - " + str(fp_track + 1) + ": " + fingerprint[0][i].substring)'''
                    self.out_text1.tag_add("match" + str(fp_track), new_tag1, str(new_tag1) + "+" + str(len(fingerprint[0][i].substring)) + "c")
                else:
                    increment_fp = False
                    '''print("1 - " + str(fp_track + 1) + ": " + fingerprint[0][i].substring)'''
                    '''print("COULD NOT FIND")'''

            #Parse through all substrings in File 2 for a given fingerprint, tagging them for this fingerprint
            for i in range(len(fingerprint[1])):
                new_tag2 = self.out_text2.search(fingerprint[1][i].substring, '1.0', tk.END, exact=False)

                if new_tag2 != '':
                    '''print("2 - " + str(fp_track + 1) + ": " + fingerprint[1][i].substring)'''
                    self.out_text2.tag_add("match" + str(fp_track), new_tag2, str(new_tag2) + "+" + str(len(fingerprint[1][i].substring)) + "c")
                    index_track2 = new_tag2
                else:
                    increment_fp = False
                    '''print("2 - " + str(fp_track + 1) + ": " + fingerprint[1][i].substring)'''
                    '''print("COULD NOT FIND")'''

            if increment_fp:
                fp_track += 1
            else:
                self.out_text1.tag_delete("match" + str(fp_track))
                self.out_text2.tag_delete("match" + str(fp_track))
                remove_fps.append(fingerprint)

        self.out_text1.configure(state='disabled')
        self.out_text2.configure(state='disabled')

        for rfp in remove_fps:
            fp.remove(rfp)

        self.fp = fp

        self.max_fp = len(self.fp)
        self.current_fp['text'] = "Current: " + str(self.cur_fp) + "/" + str(self.max_fp)

        #Show fingerprints
        self.show_reg_fp()

    def gather_most_fingerprints(self):
        '''
        Responsible for gathering most important fingerprints from backend, used for side-by-side comparison.
        '''

        self.out_text1.configure(state='normal')
        self.out_text2.configure(state='normal')

        #k and w from user input
        k = int(self.k_input.get())
        w = int(self.windowSizeInput.get())

        #Two files being compared side-by-side
        file1 = self.f2fp[self.curr_index1].filename
        file2 = self.f2fp[self.curr_index2].filename

        #Output of those files
        file1out = open(file1, 'r').read()
        file2out = open(file2, 'r').read()

        #If the analyzer is set to Java, remove comments from files
        if self.language_var.get() == "Java":
            file1out = remove_comments(file1out)
            file2out = remove_comments(file2out)

        #Python
        if self.language_var.get() == "Python":
            get_most_important_matches_javpy(self.f2fp[self.curr_index1], self.f2fp[self.curr_index2], k, int(self.fp_count_in.get()), int(self.offset_in.get()))

        #Java
        elif self.language_var.get() == "Java":
            get_most_important_matches_javpy(self.f2fp[self.curr_index1], self.f2fp[self.curr_index2], k, int(self.fp_count_in.get()), int(self.offset_in.get()))

        #Text
        else:
            get_most_important_matches_txt(self.f2fp[self.curr_index1], self.f2fp[self.curr_index2], k, 3, 6)

        #If there exist most important matches, use them
        if self.f2fp[self.curr_index2] in self.f2fp[self.curr_index1].mostimportantmatches:
            fp = self.f2fp[self.curr_index1].mostimportantmatches[self.f2fp[self.curr_index2]]
        else:
            fp = []

        #Initialize tags
        for i in range(len(fp)):
            self.out_text1.tag_config("match" + str(i), background='white')
            self.out_text2.tag_config("match" + str(i), background='white')

        #Clear text boxes, and add file outputs
        self.out_text1.delete('1.0', tk.END)
        self.out_text2.delete('1.0', tk.END)
        self.out_text1.insert(tk.END, file1out)
        self.out_text2.insert(tk.END, file2out)

        #Used to progress the search through the file, so multiple instances of the same substring aren't caught.
        index_track1 = '1.0'
        fp_track = 0
        remove_fps = []

        #For each fingerprint
        for fingerprint in fp:

            index_track2 = '1.0'
            increment_fp = True

            new_tag1 = ''
            new_tag2 = ''

            #Parse through all substrings in File 1 for a given fingerprint, tagging them for this fingerprint
            for i in range(len(fingerprint[0])):
                new_tag1 = self.out_text1.search(fingerprint[0], '1.0', tk.END)
                '''print("1 - " + str(fp_track + 1) + ": " + fingerprint[0])'''
                if new_tag1 != '':
                    self.out_text1.tag_add("most" + str(fp_track), new_tag1, str(new_tag1) + "+" + str(len(fingerprint[0])) + "c")
                else:
                    increment_fp = False
                    '''print("COULD NOT FIND")'''

            #Parse through all substrings in File 2 for a given fingerprint, tagging them for this fingerprint
            for i in range(len(fingerprint[1])):
                new_tag2 = self.out_text2.search(fingerprint[1][i], '1.0', tk.END)
                '''print("2 - " + str(fp_track + 1) + ": " + fingerprint[1][i])'''
                if new_tag2 != '':
                    self.out_text2.tag_add("most" + str(fp_track), new_tag2, str(new_tag2) + "+" + str(len(fingerprint[1][i])) + "c")
                    index_track2 = new_tag2
                else:
                    increment_fp = False
                    '''print("COULD NOT FIND")'''

            #If fingerprints found, progress the search
            if len(self.out_text1.tag_ranges("most" + str(fp_track))) > 0:
                index_track1 = new_tag1

            if increment_fp:
                fp_track += 1
            else:
                self.out_text1.tag_delete("most" + str(fp_track))
                self.out_text2.tag_delete("most" + str(fp_track))
                remove_fps.append(fingerprint)

        self.out_text1.configure(state='disabled')
        self.out_text2.configure(state='disabled')

        for rfp in remove_fps:
            fp.remove(rfp)

        self.most_fp = fp

        self.max_fp = len(self.most_fp)
        self.current_fp['text'] = "Current: " + str(self.cur_fp) + "/" + str(self.max_fp)

        #Show fingerprints
        self.show_most_fp()

#File Navigation

    def next_file1(self):
        '''
        Responsible for changing to the next file currently being analyzed on the left of the side-by-side
        '''
        self.out_result.configure(state='normal')
        #print("REACHED next_file1. curr_index1=" + str(self.curr_index1) + ". curr_index2=" + str(self.curr_index2))

        #Makes sure file isn't identical to the other side, and that index loops around when necessary
        if (self.curr_index1+1) == self.curr_index2:
            self.curr_index1 = self.curr_index1 + 2
        else:
            self.curr_index1 = self.curr_index1 + 1

        if self.curr_index1 >= len(self.f2fp):
            if self.curr_index2 != 0:
                self.curr_index1 = 0
            else:
                self.curr_index1 = 1

        self.out_result.configure(state='disabled')
        self.get_output()

    def next_file2(self):
        '''
        Responsible for changing to the next file currently being analyzed on the right of the side-by-side
        '''
        self.out_result.configure(state='normal')
        #print("REACHED next_file2. curr_index1=" + str(self.curr_index1) + ". curr_index2=" + str(self.curr_index2))

        #Makes sure file isn't identical to the other side, and that index loops around when necessary
        if (self.curr_index2+1) == self.curr_index1:
            self.curr_index2 = self.curr_index2 + 2
        else:
            self.curr_index2 = self.curr_index2 + 1

        if self.curr_index2 >= len(self.f2fp):
            if self.curr_index1 != 0:
                self.curr_index2 = 0
            else:
                self.curr_index2 = 1

        self.out_result.configure(state='disabled')
        self.get_output()

    def prev_file1(self):
        '''
        Responsible for changing to the previous file currently being analyzed on the left of the side-by-side
        '''
        self.out_result.configure(state='normal')
        #print("REACHED prev_file1. curr_index1=" + str(self.curr_index1) + ". curr_index2=" + str(self.curr_index2))

        #Makes sure file isn't identical to the other side, and that index loops around when necessary
        if (self.curr_index1-1) == self.curr_index2:
            self.curr_index1 = self.curr_index1 - 2
        else:
            self.curr_index1 = self.curr_index1 - 1

        if self.curr_index1 < 0:
            if self.curr_index2 != len(self.f2fp) - 1:
                self.curr_index1 = len(self.f2fp) - 1
            else:
                self.curr_index1 = len(self.f2fp) - 2

        self.out_result.configure(state='disabled')
        self.get_output()

    def prev_file2(self):
        '''
        Responsible for changing to the previous file currently being analyzed on the right of the side-by-side
        '''
        self.out_result.configure(state='normal')
        #print("REACHED prev_file2. curr_index1=" + str(self.curr_index1) + ". curr_index2=" + str(self.curr_index2))

        #Makes sure file isn't identical to the other side, and that index loops around when necessary
        if (self.curr_index2-1) == self.curr_index1:
            self.curr_index2 = self.curr_index2 - 2
        else:
            self.curr_index2 = self.curr_index2 - 1

        if self.curr_index2 < 0:
            if self.curr_index1 != len(self.f2fp) - 1:
                self.curr_index2 = len(self.f2fp) - 1
            else:
                self.curr_index2 = len(self.f2fp) - 2

        self.out_result.configure(state='disabled')
        self.get_output()

#Fingerprint Display

    def show_fp(self):
        '''
        Responsible for calling the correct show function depending on fingerprint mode.
        '''
        if self.fp_type.get() == 0:
            self.show_reg_fp()
        else:
            self.show_most_fp()

    def show_reg_fp(self):
        '''
        Responsible for showing regular fingerprints on screen, whether highlighting all of them, or just the first one.
        '''

        self.out_text1.configure(state='normal')
        self.out_text2.configure(state='normal')

        #View all
        if self.view_var.get() == 1:
            if self.max_fp > 0:
                self.cur_fp = 1
            else:
                self.cur_fp = 0
            for i in range(len(self.fp)):
                self.out_text1.tag_config("match" + str(i), background='yellow')
                self.out_text2.tag_config("match" + str(i), background='yellow')

        #Highlight first one and initialize class variables
        else:
            if self.max_fp > 0:
                self.cur_fp = 1

                #Set all others to white background
                for i in range(len(self.fp)):
                    self.out_text1.tag_config("match" + str(i), background='white')
                    self.out_text2.tag_config("match" + str(i), background='white')

                #Raise priority of and highlight first fingerprint
                self.out_text1.tag_config("match0", background='yellow')
                self.out_text2.tag_config("match0", background='yellow')

                self.out_text1.tag_raise("match0")
                self.out_text2.tag_raise("match0")

                #Automatically scroll to it
                if len(self.out_text1.tag_ranges("match0")) > 0:
                    self.out_text1.see(self.out_text1.tag_ranges("match0")[0])
                if len(self.out_text2.tag_ranges("match0")) > 0:
                    self.out_text2.see(self.out_text2.tag_ranges("match0")[0])

            else:
                self.cur_fp = 0
            self.current_fp['text'] = "Current: " + str(self.cur_fp) + "/" + str(len(self.fp))

        self.out_text1.configure(state='disabled')
        self.out_text2.configure(state='disabled')

    def show_most_fp(self):
        '''
        Responsible for showing most important fingerprints on screen, whether highlighting all of them, or just the first one.
        '''

        self.out_text1.configure(state='normal')
        self.out_text2.configure(state='normal')

        #View all
        if self.view_var.get() == 1:
            if len(self.most_fp) > 0:
                self.cur_fp = 1
            else:
                self.cur_fp = 0
            for i in range(len(self.most_fp)):
                self.out_text1.tag_config("most" + str(i), background='green')
                self.out_text2.tag_config("most" + str(i), background='green')

        #Highlight first one and initialize class variables
        else:
            if len(self.most_fp) > 0:
                self.cur_fp = 1

                #Set others to white background
                for i in range(len(self.most_fp)):
                    self.out_text1.tag_config("most" + str(i), background='white')
                    self.out_text2.tag_config("most" + str(i), background='white')

                #Raise priority of and highlight first fingerprint
                self.out_text1.tag_config("most0", background='green')
                self.out_text2.tag_config("most0", background='green')

                self.out_text1.tag_raise("most0")
                self.out_text2.tag_raise("most0")

                #Automatically scroll to it
                self.out_text1.see(self.out_text1.tag_ranges("most0")[0])
                self.out_text2.see(self.out_text2.tag_ranges("most0")[0])

            else:
                self.cur_fp = 0
            self.current_fp['text'] = "Current: " + str(self.cur_fp) + "/" + str(len(self.most_fp))

        self.out_text1.configure(state='disabled')
        self.out_text2.configure(state='disabled')

#Fingerprint Navigation

    def next_fp(self):
        '''
        Responsible for incrementing to the next fingerprint.
        '''

        #Checks whether working with most important or regular fingerprints
        if self.fp_type.get() == 0:

            #Checks to ensure view all isn't active
            if self.view_var.get() == 0:

                #Checks to ensure there are fingerprints remaining
                if self.cur_fp < self.max_fp:

                    #Set others to white background
                    for i in range(self.max_fp):
                        self.out_text1.tag_config("match" + str(i), background='white')
                        self.out_text2.tag_config("match" + str(i), background='white')

                    #Lower priority of prior fingerprint
                    self.out_text1.tag_lower("match" + str(self.cur_fp - 1))
                    self.out_text2.tag_lower("match" + str(self.cur_fp - 1))

                    #Raise priority of and highlight new fingerprint
                    self.out_text1.tag_config("match" + str(self.cur_fp), background='yellow')
                    self.out_text2.tag_config("match" + str(self.cur_fp), background='yellow')

                    self.out_text1.tag_raise("match" + str(self.cur_fp))
                    self.out_text2.tag_raise("match" + str(self.cur_fp))

                    #Autoscrolling
                    self.out_text1.see(self.out_text1.tag_ranges("match" + str(self.cur_fp))[1])
                    self.out_text2.see(self.out_text2.tag_ranges("match" + str(self.cur_fp))[1])

                    #Increment current fingerprint
                    self.cur_fp = self.cur_fp + 1
                    self.current_fp['text'] = "Current: " + str(self.cur_fp) + "/" + str(self.max_fp)
        else:

            #Checks to ensure view all isn't active
            if self.view_var.get() == 0:

                #Checks to ensure there are fingerprints remaining
                if self.cur_fp < self.max_fp:

                    #Set others to white background
                    for i in range(self.max_fp):
                        self.out_text1.tag_config("most" + str(i), background='white')
                        self.out_text2.tag_config("most" + str(i), background='white')

                    #Lower priority of prior fingerprint
                    self.out_text1.tag_lower("most" + str(self.cur_fp - 1))
                    self.out_text2.tag_lower("most" + str(self.cur_fp - 1))

                    #Raise priority of and highlight new fingerprint
                    self.out_text1.tag_config("most" + str(self.cur_fp), background='green')
                    self.out_text2.tag_config("most" + str(self.cur_fp), background='green')

                    self.out_text1.tag_raise("most" + str(self.cur_fp))
                    self.out_text2.tag_raise("most" + str(self.cur_fp))

                    #Autoscrolling
                    self.out_text1.see(self.out_text1.tag_ranges("most" + str(self.cur_fp))[1])
                    self.out_text2.see(self.out_text2.tag_ranges("most" + str(self.cur_fp))[1])

                    #Increment current fingerprint
                    self.cur_fp = self.cur_fp + 1
                    self.current_fp['text'] = "Current: " + str(self.cur_fp) + "/" + str(self.max_fp)

    def last_fp(self):
        '''
        Responsible for decrementing to the previous fingerprint.
        '''

        #Checks whether working with most important or regular fingerprints
        if self.fp_type.get() == 0:

            #Checks to ensure view all isn't active
            if self.view_var.get() == 0:

                #Checks to ensure there are fingerprints remaining
                if self.cur_fp > 1:

                    #Set others to white background
                    for i in range(self.max_fp):
                        self.out_text1.tag_config("match" + str(i), background='white')
                        self.out_text2.tag_config("match" + str(i), background='white')

                    #Lower priority of prior fingerprint
                    self.out_text1.tag_lower("match" + str(self.cur_fp - 1))
                    self.out_text2.tag_lower("match" + str(self.cur_fp - 1))

                    #Raise priority of and highlight new fingerprint
                    self.out_text1.tag_config("match" + str(self.cur_fp - 2), background='yellow')
                    self.out_text2.tag_config("match" + str(self.cur_fp - 2), background='yellow')

                    self.out_text1.tag_raise("match" + str(self.cur_fp - 2))
                    self.out_text2.tag_raise("match" + str(self.cur_fp - 2))

                    #Autoscrolling
                    self.out_text1.see(self.out_text1.tag_ranges("match" + str(self.cur_fp - 2))[0])
                    self.out_text2.see(self.out_text2.tag_ranges("match" + str(self.cur_fp - 2))[0])

                    #Decrement current fingerprint
                    self.cur_fp = self.cur_fp - 1
                    self.current_fp['text'] = "Current: " + str(self.cur_fp) + "/" + str(self.max_fp)
        else:

            #Checks to ensure view all isn't active
            if self.view_var.get() == 0:

                #Checks to ensure there are fingerprints remaining
                if self.cur_fp > 1:

                    #Set others to white background
                    for i in range(self.max_fp):
                        self.out_text1.tag_config("most" + str(i), background='white')
                        self.out_text2.tag_config("most" + str(i), background='white')

                    #Lower priority of prior fingerprint
                    self.out_text1.tag_lower("most" + str(self.cur_fp - 1))
                    self.out_text2.tag_lower("most" + str(self.cur_fp - 1))

                    #Raise priority of and highlight new fingerprint
                    self.out_text1.tag_config("most" + str(self.cur_fp - 2), background='green')
                    self.out_text2.tag_config("most" + str(self.cur_fp - 2), background='green')

                    self.out_text1.tag_raise("most" + str(self.cur_fp - 2))
                    self.out_text2.tag_raise("most" + str(self.cur_fp - 2))

                    #Autoscrolling
                    self.out_text1.see(self.out_text1.tag_ranges("most" + str(self.cur_fp - 2))[0])
                    self.out_text2.see(self.out_text2.tag_ranges("most" + str(self.cur_fp - 2))[0])

                    #Decrement current fingerprint
                    self.cur_fp = self.cur_fp - 1
                    self.current_fp['text'] = "Current: " + str(self.cur_fp) + "/" + str(self.max_fp)

#Misc

    def clear_output(self):
        '''
        Responsible for clearing the output boxes on the GUI, as well as resetting class variables to default/empty states.
        '''

        self.out_result.configure(state='normal')
        self.out_text1.configure(state='normal')
        self.out_text2.configure(state='normal')

        self.out_result.delete('1.0', tk.END)
        self.out_text1.delete('1.0', tk.END)
        self.out_text2.delete('1.0', tk.END)

        for i in range(len(self.fp)):
            self.out_text1.tag_delete('match' + str(i))
            self.out_text2.tag_delete('match' + str(i))

        for i in range(len(self.most_fp)):
            self.out_text1.tag_delete('most' + str(i))
            self.out_text2.tag_delete('most' + str(i))

        self.out_result.configure(state='disabled')
        self.out_text1.configure(state='disabled')
        self.out_text2.configure(state='disabled')

        self.fp = []
        self.f2fp = []
        self.most_fp = []
        self.curr_index1 = 0
        self.curr_index2 = 1
        self.cur_fp = 0
        self.max_fp = 0

    def mult_yview(self, *args):
        '''
        Allows both scroll bars in the side-by-side output to move at the same time.
        '''
        self.out_text1.yview(*args)
        self.out_text2.yview(*args)

    def report(self):
        '''
        Responsible for generating the output report full of at-a-glance results.
        '''

        self.out_result.configure(state='normal')

        total = len(self.f2fp)
        if total != 0:

            self.report_index1 = self.curr_index1 % total
            self.report_index2 = self.curr_index2 % total

            current_time = time.strftime("%Y-%m-%d_%H-%M-%S")

            localreport = fd.asksaveasfile(mode='w', initialdir=os.getcwd(), initialfile='SCAM-report_' + current_time + '.txt', title="Save SCAM report file", filetypes=(("text files", "*.txt"), ("all files", "*.*")))

            for x in self.f2fp:
                for y in self.f2fp:
                    if self.report_index1 == self.report_index2:
                        self.report_index2 = (self.report_index2 + 1) % total
                        continue
                    else:
                        if self.f2fp[self.report_index2] in self.f2fp[self.report_index1].similarto:
                            percentage = "{:.2%}".format(get_similarity(self.f2fp[self.report_index1], self.f2fp[self.report_index2]))
                            localreport.write(str("Files Compared: " + str(self.f2fp[self.report_index1].filename) + " and " + str(self.f2fp[self.report_index2].filename)))
                            localreport.write(str("\nPercentage Similarity: " + str(percentage)))
                            localreport.write(str("\nCommon Fingerprints: " + str(len(self.f2fp[self.report_index1].similarto[self.f2fp[self.report_index2]])) + "\n\n"))
                        self.report_index2 = (self.report_index2 + 1 ) % total

                self.report_index1 = (self.report_index1 + 1) % total

            localreport.close()

            """
            report.reportname.insert(tk.END, )
            def clear_file1(self):
                self.file1 = []
                self.file_name1.delete(0, tk.END)
            """
            #localreport.close()

            self.out_result.delete('1.0', tk.END)
            self.out_result.insert(tk.END, "Full Report Generated!\n")

            print(localreport)

        else:
            self.out_result.delete('1.0', tk.END)
            self.out_result.insert(tk.END, "Must Compare files before generating report!")

        self.out_result.configure(state='disabled')

    def openHelp(self):
        self.helpSect = tk.Toplevel()#height=800, width=600)
        self.helpSect.title("SCAM Help Manual")
        self.helpSect.geometry("800x600")

        self.hm_lbl = tk.Label(self.helpSect, text="Welcome to the SCAM help manual!", )
        self.hm_lbl.pack(pady = 15)

        self.hm_main = tk.Text(self.helpSect, height='30', width='80', wrap='word')
        self.hm_main.pack()
        self.hm_main.configure(state='normal')

        self.hm_scroll= tk.Scrollbar(self.helpSect, command=self.hm_main.yview)
        self.hm_main['yscrollcommand'] = self.hm_scroll.set

        self.hm_main.insert(tk.INSERT,
"""\n\tOur tool, the Source Code Analyzing Machine, is used to analyze similarity in source code for the purpose of plagiarism detection. It supports the lang- uages of Python and Java, but it can also analyze raw text which can be used for (although may not be as robust) other currently unsupported languages.

Here is some general information to start off...

    -Ignore Count determines fingerprint threshold for commonality.
    -K-grams (noise threshold) impacts sensitivity.
    -Window Size is the winnow size used by the algorithm."
    -Fingerprints size < k will be ignored.
    -Block Size is the number of fingerprints required be to be considered
        a most important match block
    -Offset is the allowable distance between them for most important matches
    -Number of fingerprints shown at the bottom does not reflect the results
        of the user's search. This number is calculated via a separate in-depth
        search specifically for the side-by-side comparison, and is also limited
        by what fingerprints are viewable. It can be larger or smaller than the
        reported number.

This program was originally built for python software, thus \"*.py\" files are the most likely to produce the best results.
\n\n\t\t\t***SCROLL DOWN FOR FUTHER INFO***\n\n
""")
        self.hm_file = open("source/manual.txt", 'r', encoding="utf-8").read()

        self.hm_main.insert(tk.INSERT, self.hm_file)
        self.hm_main.configure(state='disable')

        self.donebtn = tk.Button(self.helpSect, text="DONE", command=self.helpSect.destroy).pack()

        self.helpSect.mainloop()

#Main Class

    def __init__(self, master):
        self.master = master
        self.create_widgets()

    def create_widgets(self):

    #Class Variables

        #Store Filenames
        self.files1 = []
        self.files2 = []

        #Tracking Fingerprints
        self.cur_fp = 0
        self.max_fp = 0
        self.fp = []
        self.most_fp = []

        #Tracking Multiple Files
        self.curr_index1 = 0
        self.curr_index2 = 1
        self.f2fp = []

    #Frames/Layout

        self.menubar = tk.Menu(self.master)
        self.menubar.config(font=(None, 9))

        self.upper = tk.Frame(self.master)
        self.upper.pack(side = "top", fill='both', pady=5, padx=5)

        self.top_frame = tk.Frame(self.upper)
        self.top_frame.pack(expand=True, side = "left", fill='both', pady=5)

        self.button_panel = tk.Frame(self.upper)
        self.button_panel.pack(side="right", fill='x', padx=10, pady=5)

        self.output_frame = tk.Frame(self.master)
        self.output_frame.pack(expand=True, fill='both', pady=5, side='bottom')

        self.bottom_frame = tk.Frame(self.output_frame)
        self.bottom_frame.pack(expand=True, fill='both', pady=5)

        self.index_btns = tk.Frame(self.bottom_frame)
        self.index_btns.pack(expand=False, fill='x', pady=5, side='bottom')

        self.index_btns1 = tk.Frame(self.index_btns)
        self.index_btns1.pack(expand=True, fill='x', side='left')

        self.index_btns2 = tk.Frame(self.index_btns)
        self.index_btns2.pack(expand=True, fill='x', side='right')

        self.very_bottom = tk.Frame(self.output_frame, width=0, height=5)
        self.very_bottom.pack(expand=False, fill='none', pady=5, side="bottom")

    #Tools Menu

        self.toolsmenu = tk.Menu(self.menubar, tearoff=0)
        self.toolsmenu.add_command(label="Generate Report", command=self.report)
        #self.toolsmenu.add_command(label="Check Matches", command=self.donothing)
        #self.toolsmenu.add_command(label="Fingerprint Offest", command=self.donothing)
        self.menubar.add_cascade(label="Tools", menu=self.toolsmenu)

        self.helpmenu = tk.Menu(self.menubar, tearoff=0)
        self.helpmenu.add_command(label="Manual", command= self.openHelp)
        self.menubar.add_cascade(label="Help", menu=self.helpmenu)

        #self.toolsmenu = tk.Menu(self.menubar, tearoff=0)
        #self.toolsmenu.add_command(label="Check Matches", command=self.donothing)
        #self.toolsmenu.add_command(label="Fingerprint Offest", command=self.donothing)
        #self.menubar.add_cascade(label="Tools", menu=self.toolsmenu)

        #self.helpmenu = tk.Menu(self.menubar, tearoff=0)
        #self.helpmenu.add_command(label="Manual", command= self.openHelp)
        #self.menubar.add_cascade(label="Help", menu=self.helpmenu)

        self.master.config(menu=self.menubar)

    #Filename Display

        self.file1_frame = tk.Frame(self.top_frame)
        self.file1_frame.pack(side='top', expand=True, fill='both')

        self.file2_frame = tk.Frame(self.top_frame)
        self.file2_frame.pack(side='bottom', expand=True, fill='both')

        #ADDED for bp
        self.bpfile_frame = tk.Frame(self.top_frame)
        self.bpfile_frame.pack(side='bottom', expand=True, fill='both')

        #Filebox 1

        self.cur_file_label1 = tk.Label(self.file1_frame, text = "Student Files: ")
        self.cur_file_label1.pack(anchor='w')
        self.cur_file_label1.config(font=(None, 9))

        self.file_name1 = tk.Listbox(self.file1_frame, height=5, exportselection=False)

        self.file_scroll1 = tk.Scrollbar(self.file1_frame, command=self.file_name1.yview)
        self.file_name1['yscrollcommand'] = self.file_scroll1.set
        self.file_scroll1.pack(expand=False, fill="y", side='right')

        self.file_name1.pack(expand=True, pady=(0, 10), fill='both')

        #Filebox 2

        self.cur_file_label2 = tk.Label(self.file2_frame, text = "Boilerplate Files: ")
        self.cur_file_label2.pack(anchor='w')
        self.cur_file_label2.config(font=(None, 9))

        self.file_name2 = tk.Listbox(self.file2_frame, height=5, exportselection=False)

        self.file_scroll2 = tk.Scrollbar(self.file2_frame, command=self.file_name2.yview)
        self.file_name2['yscrollcommand'] = self.file_scroll2.set
        self.file_scroll2.pack(expand=False, fill="y", side='right')

        self.file_name2.pack(expand=True, fill='both')

    #Button Panel

        #Logo

        """
        logo = tk.PhotoImage(file="source/SCAM.png")
        smallerlogo = logo.subsample(6,6)
        imglabel = tk.Label(self.button_panel, image=smallerlogo)
        imglabel.image = smallerlogo
        imglabel.grid(row=0, column=0, columnspan=4, padx=100)
        """

        logo = Image.open("source/SCAM.png")
        smallerlogo = logo.resize((round(logo.size[0] * .1), round(logo.size[1] * .1)));
        render = ImageTk.PhotoImage(smallerlogo)
        img = tk.Label(self.button_panel, image=render)
        img.image = render
        img.grid(row=0, column=0, columnspan=4)

        #self.k_desc_label = tk.Label(self.button_panel, text = "K (noise threshold) impacts sensitivity. Fingerprints size < k will be ignored.\nWindow Size is the winnow size used by the algorithm.\nIgnore Count determines fingerprint threshold for commonality.\nPython files should be able to be compiled for the best results.")
        #self.k_desc_label.grid(row=1, column=0, columnspan=4)
        #self.k_desc_label.config(font=(None, 8))

        self.w_desc_label = tk.Label(self.button_panel, text = "Default values set for optimal machine output. \n View Help Manual for more information.")
        self.w_desc_label.grid(row=1, column=0, columnspan=4)
        self.w_desc_label.config(font=(None, 8))

        #self.ignore_label = tk.Label(self.button_panel, text = "Ignore Files: ")
        #self.ignore_label.grid(row=1, column=0)
        #self.ignore_label.config(font=(None, 9))

        #self.file_ignore = tk.Text(self.button_panel, height=1, width=30, state='disabled')
        #self.file_ignore.grid(row=1, column=1, columnspan=4)

        #Add Files

        self.button1 = tk.Button(self.button_panel, text="Add Student Files", command=self.open_file1, bg="gray75", width=20)
        self.button1.grid(row = 2, column = 0, padx = 1, pady = 2, columnspan=2)
        self.button1.config(font=(None, 9))

        self.button1a = tk.Button(self.button_panel, text="Clear Student File(s)", command=self.clear_file1, bg="gray80", width=20)
        self.button1a.grid(row = 2, column = 2, padx = 1, pady = 2, columnspan=2)
        self.button1a.config(font=(None, 9))

        self.button2 = tk.Button(self.button_panel, text="Add Boilerplate Files", command=self.open_file2, bg="gray75", width=20)
        self.button2.grid(row = 3, column = 0, padx =1, pady = 2, columnspan=2)
        self.button2.config(font=(None, 9))

        self.button2a = tk.Button(self.button_panel, text="Clear Boilerplate File(s)", command=self.clear_file2, bg="gray80", width=20)
        self.button2a.grid(row = 3, column = 2, padx = 1, pady = 2, columnspan=2)
        self.button2a.config(font=(None, 9))

        #Language Select/Ignore Count

        self.lang_label = tk.Label(self.button_panel, text = "Language: ")
        self.lang_label.grid(row = 5, column = 0, pady = 10)
        self.lang_label.config(font=(None, 9))

        self.language_var = tk.StringVar(self.button_panel)
        self.language_var.set("Python")
        self.languageMenu = tk.OptionMenu(self.button_panel, self.language_var, "Text", "Python", "Java")
        self.languageMenu.grid(row=5, column=1, pady=10, sticky='w', columnspan=1)
        self.languageMenu.config(font=(None, 9))

        self.ignore_count_label = tk.Label(self.button_panel, text = "Ignore Count: ")
        self.ignore_count_label.grid(row = 5, column = 2, pady = 10)
        self.ignore_count_label.config(font=(None, 9))

        self.ignore_input = tk.Spinbox(self.button_panel, from_=0, to=255, width=5)
        self.ignore_input.grid(row=5, column=3, pady=10)
        self.ignore_input.delete(0, tk.END)
        self.ignore_input.insert(0, '5')
        self.ignore_input.config(font=(None, 9))

        #Advanced

        self.k_label = tk.Label(self.button_panel, text = "K-grams: ")
        self.k_label.grid(row = 7, column = 0, padx = 1, pady = (10,0))
        self.k_label.config(font=(None, 9))

        self.k_input = tk.Spinbox(self.button_panel, from_=1, to=999, width=5)
        self.k_input.grid(row=7, column=1, padx=5, pady = (10,0))

        self.k_input.delete(0, tk.END)
        self.k_input.insert(0, '50')
        self.k_input.config(font=(None, 9))

        self.w_label = tk.Label(self.button_panel, text = "Window Size: ")
        self.w_label.grid(row = 7, column = 2, padx = 1, pady = (10,0))
        self.w_label.config(font=(None, 9))

        self.windowSizeInput = tk.Spinbox(self.button_panel, from_=1, to=999, width=5)
        self.windowSizeInput.grid(row=7, column=3, padx=5, pady = (10,0))
        self.windowSizeInput.config(font=(None, 9))

        self.windowSizeInput.delete(0, tk.END)
        self.windowSizeInput.insert(0, '20')

        self.fp_count_lbl = tk.Label(self.button_panel, text = "Block Size: ")
        self.fp_count_lbl.grid(row = 8, column = 0, padx = 5, pady = 5)
        self.fp_count_lbl.config(font=(None, 9))

        self.fp_count_in = tk.Spinbox(self.button_panel, from_=1, to=999, width=5)
        self.fp_count_in.grid(row=8, column=1, padx=5, pady = 5)
        self.fp_count_in.delete(0, tk.END)
        self.fp_count_in.insert(0, '3')
        self.fp_count_in.config(font=(None, 9))

        self.offset_lbl = tk.Label(self.button_panel, text = "Offset: ")
        self.offset_lbl.grid(row = 8, column = 2, padx = 1, pady = 5, columnspan=1)
        self.offset_lbl.config(font=(None, 9))

        self.offset_in = tk.Spinbox(self.button_panel, from_=1, to=999, width=5)
        self.offset_in.grid(row=8, column=3, padx=0, pady = 5, columnspan=2)
        self.offset_in.delete(0, tk.END)
        self.offset_in.insert(0, '6')
        self.offset_in.config(font=(None, 9))

        self.fp_type = tk.IntVar(self.button_panel)
        self.fp_type.set(0)
        self.fp_menu1 = tk.Radiobutton(self.button_panel, text="All Fingerprints", variable=self.fp_type, value=0)
        self.fp_menu1.grid(row=9, column=0, padx=5, pady=(10,5), columnspan=2)
        self.fp_menu1.config(font=(None, 9))
        self.fp_menu2 = tk.Radiobutton(self.button_panel, text="Important Blocks", variable=self.fp_type, value=1)
        self.fp_menu2.grid(row=9, column=2, padx=(0,10), pady=(10,5), columnspan=2)
        self.fp_menu2.config(font=(None, 9))

        #Compare

        self.run_label = tk.Button(self.button_panel, text="Compare", height = 1, width = 40, command=self.export_files, bg="gray75", bd=3)
        self.run_label.grid(row=11, column=0, pady=(5, 0), columnspan=4)
        self.run_label.config(font=(None, 9))

        self.clear_label = tk.Button(self.button_panel, text="Clear Output", height = 1, width = 40, command=self.clear_output, bg="gray80", bd=3)
        self.clear_label.grid(row=12, column=0, pady=2.5, columnspan=4)
        self.clear_label.config(font=(None, 9))

        #self.report_label = tk.Button(self.button_panel, text="Full Report", height=1, width=40, command=self.report_output, bg="gray80", bd=3)
        #self.report_label.grid(row=11, column=0, pady=2.5, columnspan=4)

    #Output Display

        self.output_frame = tk.Frame(self.bottom_frame)
        self.output_frame.pack(expand=False, fill='x', side='top', padx=10, pady=5)

        self.output_lbl = tk.Label(self.output_frame, text = "Output")
        self.output_lbl.pack()

        self.out_result = tk.Text(self.output_frame, width=1, height=3)
        self.out_result.pack(expand=True, fill="both", side='left', padx=0)
        self.res_scroll = tk.Scrollbar(self.output_frame, command=self.out_result.yview)
        self.out_result['yscrollcommand'] = self.res_scroll.set
        self.res_scroll.pack(expand=False, fill="y", side='left')
        self.out_result.configure(state='disabled')

        self.out_text1 = tk.Text(self.bottom_frame, width=1, height=1)
        self.out_text1.configure(state='disabled')

        self.txt_scroll1 = tk.Scrollbar(self.bottom_frame, command=self.mult_yview)
        self.out_text1['yscrollcommand'] = self.txt_scroll1.set

        self.out_text1.pack(expand=True, fill="both", padx=(10,0),pady=10, side='left')
        self.txt_scroll1.pack(side='left', padx=(0,10), fill='y', pady=10)

        self.out_text2 = tk.Text(self.bottom_frame, width=1, height=1, )
        self.out_text2.configure(state='disabled')

        self.txt_scroll2 = tk.Scrollbar(self.bottom_frame, command=self.mult_yview)
        self.out_text2['yscrollcommand'] = self.txt_scroll2.set

        self.out_text2.pack(expand=True, fill="both", padx=(10,0),pady=10, side='left')
        self.txt_scroll2.pack(side='left', padx=(0,10), fill='y', pady=10)

    #Next File Buttons

        self.next_filebtn1 = tk.Button(self.index_btns1, text="Compare Next File", command=self.next_file1, bg="gray75", width=15)
        self.next_filebtn1.pack(expand=True, side='right', padx=(5,25), fill='x')

        self.prev_filebtn1 = tk.Button(self.index_btns1, text="Compare Previous File", command=self.prev_file1, bg="gray80", width=15)
        self.prev_filebtn1.pack(expand=True, side='left', padx=(25,5), fill='x')

        self.next_filebtn2 = tk.Button(self.index_btns2, text="Compare Next File", command=self.next_file2, bg="gray75", width=15)
        self.next_filebtn2.pack(expand=True, side='right', padx=(5,25), fill='x')

        self.prev_filebtn2 = tk.Button(self.index_btns2, text="Compare Previous File", command=self.prev_file2, bg="gray80", width=15)
        self.prev_filebtn2.pack(expand=True, side='left', padx=(25,5), fill='x')

    #Very Bottom

        self.view_label = tk.Label(self.very_bottom, text="View All?")
        self.view_label.grid(row=0, column=3, padx=(10,0), pady=5)

        self.view_var = tk.IntVar()

        self.view_all = tk.Checkbutton(self.very_bottom, command=self.show_fp, variable=self.view_var)
        self.view_all.grid(row=0, column=4, padx=5, pady=5)

        self.last_fp = tk.Button(self.very_bottom, text="Last Fingerprint", command=self.last_fp)
        self.last_fp.grid(row=0, column=5, padx=5, pady=5)

        self.current_fp = tk.Label(self.very_bottom, text="Current: " + str(self.cur_fp) + "/" + str(self.max_fp))
        self.current_fp.grid(row=0, column=6, padx=5, pady=5)

        self.next_fp = tk.Button(self.very_bottom, text="Next Fingerprint", command=self.next_fp)
        self.next_fp.grid(row=0, column=7, padx=(5, 100), pady=5)

        #self.warning_lbl2 = tk.Label(self.very_bottom, text="")
        #self.warning_lbl2.grid(row=2, column=0, padx=(10,0), pady=5, columnspan=30)
        #self.warning_lbl2.config(font=(None, 8))

def main():
    root = tk.Tk()
    root.geometry("1080x740")
    root.title("Source Code Analyzing Machine")
    gui = SourceAnalyzer(root)
    root.mainloop()

if __name__ == "__main__":
    main()


#!/usr/bin/env python3.6

import argparse
import sys
import getopt
import os
import pathlib

import csci508_final as csci

def main(argv):
    # Get full command-line arguments
    full_cmd_arguments = sys.argv

    # Keep all but the first
    argument_list = full_cmd_arguments[1:]

    short_options = "h"
    long_options = ["help",
                    "train_ratio=",
                    "batch_size=",
                    "learn_rate=",
                    "epoch_qty=",
                    "transform_horz=",
                    "transform_vert=",
                    "transform_rot30=",
                    "transform_noise=",
                    "transform_blur=",
                    "architecture="]

    try:
        arguments, values = getopt.getopt(argument_list, short_options, long_options)
    except getopt.error as err:
        # Output error, and return with an error code
        print (str(err))
        sys.exit(2)

    for current_argument, current_value in arguments:
        if current_argument in ("-h", "--help"):
            print()
            print("Usage: main.py [argument]")
            print()
            print("Optional Arguments:")
            print("-h, --help \t\t\t Show this help message and exit")
            print("--train_ratio=[float] \t\t Training ratio for splitting data. Chosen value should be a float < 1.00.")
            print("\t\t\t\t Default value is 0.6.")
            print("--batch_size=[int] \t\t Batch size for training data. Chosen value should be an integer < 50.")
            print("\t\t\t\t Default value is 8.")
            print("--learn_rate=[float] \t\t Learning rate for training model. Chosen value should be a float.")
            print("\t\t\t\t Default value is 0.001.")
            print("--epoch_qty=[int] \t\t Epoch Quantity for training model. Chosen value should be an integer.")
            print("\t\t\t\t Default value is 8.")
            print("--transform_horz=[bool] \t Horizontal Augmentation for training data. Chosen value should be True or False.")
            print("\t\t\t\t Default value is False.")
            print("--transform_vert=[bool] \t Vertical Augmentation for training data. Chosen value should be True or False.")
            print("\t\t\t\t Default value is False.")
            print("--transform_rot30=[bool] \t 30 Degree Rotation Augmentation for training data. Chosen value should be True or False.")
            print("\t\t\t\t Default value is False.")
            print("--transform_noise=[bool] \t Noise Augmentation for training data. Chosen value should be True or False.")
            print("\t\t\t\t Default value is False.")
            print("--transform_blur=[bool] \t Blur Augmentation for training data. Chosen value should be True or False.")
            print("\t\t\t\t Default value is False.")
            print("--architecture=[string] \t Pre-Trained model type for leveraging transfer learning. Chosen value should be")
            print("\t\t\t\t 'resnet18', 'resnet34', 'resnet50', or 'resnet50-modnet'. Default value is 'resnet18'.")
            print()
            exit()
        elif current_argument in ("--train_ratio"):
            train_ratio = float(current_value)
        elif current_argument in ("--epoch_qty"):
            epoch_qty = int(current_value)
        elif current_argument in ("--batch_size"):
            batch_size = int(current_value)
        elif current_argument in ("--learn_rate"):
            learn_rate = float(current_value)
        elif current_argument in ("--transform_horz"):
            transform_horz = bool(current_value)
        elif current_argument in ("--transform_vert"):
            transform_horz = bool(current_value)
        elif current_argument in ("--transform_rot30"):
            transform_horz = bool(current_value)
        elif current_argument in ("--transform_noise"):
            transform_horz = bool(current_value)
        elif current_argument in ("--transform_blur"):
            transform_horz = bool(current_value)
        elif current_argument in ("--architecture"):
            model_type = current_value

    if 'train_ratio' not in locals():
        train_ratio = 0.6
    if 'epoch_qty' not in locals():
        epoch_qty = 5
    if 'batch_size' not in locals():
        batch_size = 8
    if 'learn_rate' not in locals():
        learn_rate = 1e-3
    if 'transform_horz' not in locals():
        transform_horz = False
    if 'transform_vert' not in locals():
        transform_vert = False
    if 'transform_rot' not in locals():
        transform_rot = False
    if 'transform_noise' not in locals():
        transform_noise = False
    if 'transform_blur' not in locals():
        transform_blur = False
    if 'model_type' not in locals():
        model_type = 'resnet18'

    val_ratio = (1.0 - train_ratio)/2
    test_ratio = 1.0 - train_ratio - val_ratio

    hyperparameters = dict(
        train_ratio = train_ratio,
        val_ratio = val_ratio,
        test_ratio = test_ratio,
        epoch_qty = epoch_qty,
        batch_size = batch_size,
        learn_rate = learn_rate,
        transform_horz = transform_horz,
        transform_vert = transform_vert,
        transform_rot = transform_rot,
        transform_noise = transform_noise,
        transform_blur = transform_blur,
        architecture = model_type
    )

    model_dict, model_file_name = csci.model_selection.model_selection(model_type)
    csci.train_test_model.main(hyperparameters, model_dict, model_file_name)

if __name__ == "__main__":
   main(sys.argv[:])


import pandas as pd
from bs4 import BeautifulSoup
import requests
from splinter import Browser

def scrape():
    executable_path = {'executable_path': '/usr/local/bin/chromedriver'}
    browser = Browser('chrome', **executable_path, headless=True)
    url = "https://mars.nasa.gov/news/"
    browser.visit(url)
    html = browser.html
    soup = BeautifulSoup(html, 'html.parser')
    results = soup.find('div', class_="list_text")

    news_title = results.find('div', class_='content_title').text
    news_p = results.find('div', class_='article_teaser_body').text

    url_2 = "https://www.jpl.nasa.gov/spaceimages/?search=&category=Mars"
    browser.visit(url_2)
    browser.click_link_by_partial_text('FULL IMAGE')
    browser.click_link_by_partial_text('more info')
    html_2 = browser.html
    soup_2 = BeautifulSoup(html_2, 'html.parser')
    article = soup.article
    results_2 = soup_2.find('figure', class_='lede')
    featured_image_url = f"https://www.jpl.nasa.gov/{results_2.a['href']}"

    url_3 = "https://space-facts.com/mars/"
    tables = pd.read_html(url_3)
    df = tables[0]
    df = df.rename(columns = {0:'Description', 1: 'Mars'})
    df = df.set_index('Description')
    html_table = df.to_html()

    url_4 = 'https://astrogeology.usgs.gov/search/results?q=hemisphere+enhanced&k1=target&v1=Mars'
    browser.visit(url_4)

    hemisphere_image_urls = []

    html_4 = browser.html
    soup_4 = BeautifulSoup(html_4, 'html.parser')

    sections = soup_4.find_all('div', class_='description')

    for section in sections:
        d1 = {}
        title = section.find('h3').text.strip()
        d1['title'] = title
        browser.click_link_by_partial_text(title)

        html_5 = browser.html
        soup_5 = BeautifulSoup(html_5, 'html.parser')

        grab = soup_5.find('img', class_='wide-image')
        img_url = f"https://astrogeology.usgs.gov/{grab['src']}"
        d1['img_url'] = img_url

        hemisphere_image_urls.append(d1)
        browser.back()

        data = {"news_title":news_title,
                "news_paragraph":news_p,
                "featured_image":featured_image_url,
                "facts_table":html_table,
                "hemispheres":hemisphere_image_urls}

    return data


import io
import motw_shutil

output =  io.StringIO()
output.write("first line")
output.write("second line")

with open ('/home/j/testio', 'r+') as fd, open('/home/j/testio2', 'w') as fd2:
    l = fd.readlines()

    for i in range(len(l)):
        l[i] = l[i].strip()
    print(l)
print("___")

to_write = ["a",'bb','ccc','dddd']
with open('/home/j/testio2', 'r+') as fd:
    fd.write('\n'.join(to_write))
    fd.seek(0)
    print(fd.read())

res = []
with open('/home/j/testio2', 'r+') as fd:
    for line in fd:
        res.append(line)

print(res)


import numpy as np
import unittest
from sklearn.naive_bayes import GaussianNB
from sklearn.datasets import load_iris

class NaiveBayes:
    def __init__(self):
        self.classes = None
        self.priors = None
        self.means = None
        self.stds = None

    def fit(self, X, y):
        self.classes = np.unique(y)
        n_classes = len(self.classes)

        # Calculate class priors
        self.priors = np.zeros(n_classes)
        for i, c in enumerate(self.classes):
            self.priors[i] = np.sum(y == c) / len(y)

        # Calculate class means and standard deviations
        n_features = X.shape[1]
        self.means = np.zeros((n_classes, n_features))
        self.stds = np.zeros((n_classes, n_features))
        for i, c in enumerate(self.classes):
            X_c = X[y == c]
            self.means[i, :] = X_c.mean(axis=0)
            self.stds[i, :] = X_c.std(axis=0)

    def predict(self, X):
        n_samples = X.shape[0]
        posteriors = np.zeros((n_samples, len(self.classes)))

        # Calculate class posteriors
        for i, c in enumerate(self.classes):
            prior = self.priors[i]
            likelihoods = self._pdf(X, i)
            posteriors[:, i] = prior * likelihoods

        # Return class with highest posterior probability
        return self.classes[np.argmax(posteriors, axis=1)]

    def _pdf(self, X, class_idx):
        # Calculate probability density function for a given class
        mean = self.means[class_idx]
        std = self.stds[class_idx]
        numerator = np.exp(- (X - mean) ** 2 / (2 * std ** 2))
        denominator = np.sqrt(2 * np.pi * std ** 2)
        return np.prod(numerator / denominator, axis=1)

class TestNaiveBayes(unittest.TestCase):
    def setUp(self):
        self.X, self.y = load_iris(return_X_y=True)
        self.nb = NaiveBayes()
        self.sk_nb = GaussianNB()

    def test_fit(self):
        self.nb.fit(self.X, self.y)
        self.assertIsNotNone(self.nb.classes)
        self.assertIsNotNone(self.nb.priors)
        self.assertIsNotNone(self.nb.means)
        self.assertIsNotNone(self.nb.stds)

    def test_predict(self):
        self.nb.fit(self.X, self.y)
        y_pred = self.nb.predict(self.X)
        accuracy = np.sum(y_pred == self.y) / len(y_pred)
        self.assertGreater(accuracy, 0.9)

    # compare to sklearn implementation
    def test_sklearn_comparison(self):
        self.sk_nb.fit(self.X, self.y)
        sk_y_pred = self.sk_nb.predict(self.X)
        sk_accuracy = np.sum(sk_y_pred == self.y) / len(sk_y_pred)

        self.nb.fit(self.X, self.y)
        y_pred = self.nb.predict(self.X)
        accuracy = np.sum(y_pred == self.y) / len(y_pred)

        np.testing.assert_almost_equal(accuracy, sk_accuracy)

if __name__ == '__main__':
    unittest.main()