from selenium import webdriver
import os, shutil
import time as t
from PIL import Image, ImageChops
import tkinter as tk
from threading import Thread
from tkinter import filedialog
from ctypes import windll


def is_picture(counter):
    im = Image.open('temp/scrapping/image' + str(counter) + '.png')
    rgb_im = im.convert('RGB')
    r, g, b = rgb_im.getpixel((2000, 1300))
    if r == 255 and g == 255 and b == 255:
        return False
    else:
        return True


def is_same(counter):
    if counter > 0:
        prev_counter = counter - 1
        new_file = os.path.getsize('temp/scrapping/image%s.png' % str(counter))
        old_file = os.path.getsize('temp/scrapping/image%s.png' % str(prev_counter))
        os.remove('temp/scrapping/image%s.png' % str(prev_counter))
        if new_file == old_file:
            return True
        else:
            return False


def trim(image):
    bg = Image.new(image.mode, image.size, image.getpixel((0, 0)))
    diff = ImageChops.difference(image, bg)
    diff = ImageChops.add(diff, diff, 2.0, -100)
    bbox = diff.getbbox()
    if bbox:
        return image.crop(bbox)


def remove(value, delete_chars):
    for c in delete_chars:
        value = value.replace(c, '')
    return value


def initialize_folders():
    if not os.path.exists('temp'):
        os.makedirs('temp')
    else:
        shutil.rmtree('temp')
    if not os.path.exists('temp/scrapping'):
        os.makedirs('temp/scrapping')


def file_save(name, status):
    path = status
    f = filedialog.asksaveasfile(mode='wb', defaultextension=".png", title="Saving picture", initialfile=name, filetypes=(("PNG high resolution image", "*.png"), ("all files", "*.*")))
    if f is None:
        lbl.config(text='Downloading was cancelled')
        btn.config(state='normal')
        return
    if os.path.abspath(path) != f.name.replace('/', '\\'):
        im = Image.open(path)
        im.save(f)
        os.remove(path)
        f.close()
        lbl.config(text='Success! File saved as : ' + str(status) + '!')
    else:
        lbl.config(text='Failed! Please next time don\'t replace file in script directory!')


def do_scrapping(url):
    old_url = url
    url = ''

    for char in old_url:
        if char == '?':
            break
        url += char

    lbl.config(text='2/3: Scrapping: starting webdriver... [it takes several seconds]')
    options = webdriver.ChromeOptions()
    options.add_argument('--headless')
    options.add_argument('--disable-gpu')
    driver = webdriver.Chrome(executable_path=r"chromedriver.exe", chrome_options=options)
    driver.set_window_size(4000, 4000)
    driver.get(url)
    xPath3 = r".//html/body/div[3]/div[3]/div/div/div/div[3]/div"  # img xPath
    xPath2 = r".//html/body/div[3]/div[3]/div/div/div[2]/div[1]/div[2]/div[1]/div"  # zoom xPath
    xPath1 = r".//html/body/div[3]/div[3]/div/div/div[3]/div/content/span"  # open img xPath
    image_appeared = False  # flag for starting click on image
    image_zoom_taked = False
    last_file = ''  # last succeed file
    lbl.config(text='2/3: Scrapping: waiting for response')
    driver.implicitly_wait(1)
    lbl.config(text='2/3: Scrapping: getting information about artist and picture')

    try:
        authorPic = driver.find_element_by_xpath(r'/html[1]/body[1]/div[3]/div[3]/div[1]/div[1]/div[6]/section[2]/div[1]/ul[1]/li[2]/a[1]').text  # author of the picture xPath
    except Exception:
        authorPic = ''

    try:
        name_pic = driver.find_element_by_xpath(r'/html[1]/body[1]/div[3]/div[3]/div[1]/div[1]/div[6]/section[2]/div[1]/ul[1]/li[1]').text[7::]  # name of the picture xPath
        if authorPic != '':
            name_pic = ' - ' + name_pic
    except Exception:
        name_pic = driver.title[0:-23]

    name_file = authorPic + name_pic
    name_file = remove(name_file, '\/:*?"<>|')
    lbl.config(text='2/3: Scrapping: starting ' + name_file + ' [+3 sec]')
    t.sleep(3)
    for i in range(0, 45):  # 45 attempts
        t.sleep(1)
        if image_appeared:
            lbl.config(text='2/3: Scrapping: %sth attempt, image appeared, zooming...' % str(i+1) + ' [+6 sec]')
            t.sleep(3)
            if exImg.get() == 1:
                elem2 = driver.find_element_by_xpath(xPath1)
            else:
                elem2 = driver.find_element_by_xpath(xPath2)
            elem3 = driver.find_element_by_xpath(xPath3)
            driver.execute_script("arguments[0].click();", elem2)
            driver.execute_script("arguments[0].click();", elem3)
            t.sleep(3)
            image_appeared = False
            image_zoom_taked = True
        else:
            lbl.config(text='2/3: Scrapping: %sth attempt, waiting for the image...' % str(i+1))
        lbl.config(text='2/3: Scrapping: %sth attempt, taking snapshot' % str(i+1))
        driver.save_screenshot('temp/scrapping/image%s.png' % str(i))
        lbl.config(text='2/3: Scrapping: %sth attempt, checking progress...' % str(i+1))

        if is_picture(i) and not image_zoom_taked:
            image_appeared = True
        if is_same(i):
            last_file = 'temp/scrapping/image%s.png' % str(i)
            break
    lbl.config(text='2/3: Scrapping: Success!')
    driver.quit()
    return last_file, name_file


def do_finally_changes(last_file, name_file):
    if last_file != '':
        shutil.copyfile(last_file, 'temp/image_result.png')
        shutil.rmtree('temp/scrapping')
        imOp = Image.open('temp/image_result.png')
        if exImg.get() == 1:
            im = imOp.crop((0, 50, 4000, 4000))  # 20!8
        else:
            im = imOp
        im = trim(im)
        im.save(name_file + '.png')
        shutil.rmtree('temp')
        return name_file
    return 'An error occurred with processing image'


def start_process():
    btn.config(state='disabled')
    btnPaste.config(state='disabled')
    ent.config(state='disabled')
    chk.config(state='disabled')
    lbl.config(text='Working...')
    lbl.config(text='1/3: Initializing folders')
    initialize_folders()
    lbl.config(text='2/3: Scrapping picture (may take a few minutes)')
    file, name = do_scrapping(ent.get())
    lbl.config(text='3/3: Cropping image')
    status = do_finally_changes(file, name)
    lbl.config(text='Saving the file: ' + str(status) + '...')
    file_save(status + '.png', status + '.png')
    btnPaste.config(state='normal')
    ent.config(state='normal')
    btn.config(state='normal')
    chk.config(state='normal')


def start():
    lbl.config(text="Starting..")
    th = Thread(target=start_process)
    th.start()


def on_key_release(event):
    ctrl = (event.state & 0x4) != 0
    if event.keycode == 88 and ctrl and event.keysym.lower() != "x":
        event.widget.event_generate("<<Cut>>")

    if event.keycode == 86 and ctrl and event.keysym.lower() != "v":
        event.widget.event_generate("<<Paste>>")

    if event.keycode == 67 and ctrl and event.keysym.lower() != "c":
        event.widget.event_generate("<<Copy>>")

    if event.keycode == 65 and ctrl and event.keysym.lower() != "a":
        event.widget.event_generate("<<SelectAll>>")


def paste():
    entryText.set(root.clipboard_get())


root = tk.Tk()
root.title('Google Art Downloader 0.1.2 beta')
windll.shcore.SetProcessDpiAwareness(1)
root.resizable(0, 0)

entryText = tk.StringVar()
ent = tk.Entry(root, width=77, textvariable=entryText)
entryText.set(r"https://artsandculture.google.com/asset/the-starry-night/bgEuwDxel93-Pg")
lbl = tk.Label(root, width=80)
btn = tk.Button(root, text="Download", command=start)
btnPaste = tk.Button(root, text="Paste url", command=paste)
exImg = tk.IntVar()
chk = tk.Checkbutton(root, text="Check this, if your image cropped wrongly (only for elongated vertical image)", variable=exImg)

lbl.grid(row=1, column=1, columnspan=3, pady=1)
ent.grid(row=2, column=1, padx=6, pady=1)
btnPaste.grid(row=2, column=2, padx=3, pady=2)
btn.grid(row=2, column=3, padx=3, pady=2)
chk.grid(row=3, column=1, columnspan=1, pady=1)

lbl.configure(text='Insert here link to picture from Google Arts & Culture:')
ent.bind("<Key>", on_key_release, "+")
root.mainloop()