# guiscrape.py

from tkinter import *
from tkinter import ttk, filedialog, messagebox
import base64
import json
import os
from bs4 import BeautifulSoup
import requests

config = {} # This will be our memory

# Scaning the given url:
def fetch_url():
    url = _url.get()
    config['images'] = []
    _images.set(())    # initialized as empty tuple
    try:
        page = requests.get(url)
    except requests.RequestException as rex:
        _statusbar(str(rex))
    else:
        soup = BeautifulSoup(page.content, 'html.parser')
        images = fetch_images(soup, url)
        if images:
            _images.set(tuple(img['name'] for img in images))
            _statusbar('Images found: {}'.format(len(images)))
        else:
            _statusbar('No images found')
        config['images'] = images

# Scaning all the img objects in the page:
def fetch_images(soup, base_url):
    images = []
    for img in soup.findAll('img'):
        src = img.get('src')
        img_url = (
            '{base_url}//{src}'.format(base_url=base_url, src=src))
        name = img_url.split('/')[-1]
        images.append(dict(name=name, url=img_url))
    return images

# function for saving the images:
def save():
    if not config.get('images'):
        _alert('No images to save')
        return
		
    if _save_method.get() == 'img':
        dirname = filedialog.askdirectory(mustexist=True)
        _save_images(dirname)
    else:
        filename = filedialog.asksaveasfilename(
            initialfile='images.json',
            filetypes=[('JSON','.json')])
        _save_json(filename)

# Saving the choosen images in selected path:
def _save_images(dirname):
    if dirname and config.get('images'):
        for img in config['images']:
            img_data = requests.get(img['url']).content
            filename = os.path.join(dirname, img['name'])
            with open(filename, 'wb') as f:
                f.write(img_data)
        _alert('Done')
	
# Saving choosen images like a .json file:	
def _save_json(filename):
    if filename and config.get('images'):
        data = {}
        for img in config['images']:
            img_data = requests.get(img['url']).content
            b64_img_data = base64.b64encode(img_data)
            str_img_data = b64_img_data.decode('utf-8')
            data[img['name']] = str_img_data
			
        with open(filename, 'w') as ijson:
            ijson.write(json.dumps(data))
        _alert('Done')
	
# Status Bar:	
def _statusbar(arg):
    _status_msg.set(arg)

# Alert function:
def _alert(msg):
    messagebox.showinfo(message=msg)		


# The gui:
if __name__ == '__main__':

# Defining the window:
    _root = Tk()
    _root.title('Scrape app')
# make _root window resizable:
    _root.columnconfigure(0, weight=1)
    _root.rowconfigure(0, weight=1)
# set default size of the window:
    _root.geometry("720x480")
# Define mainframe, where all the objects will be:
    _mainframe = ttk.Frame(_root, padding='5 5 5 5')
    _mainframe.grid(row=0, column=0, sticky=(E, W, N, S))
# make _mainframe resizable:
    _mainframe.columnconfigure(0, weight=1)
    _mainframe.rowconfigure(0, weight=1)
    _mainframe.rowconfigure(1, weight=1)
    _mainframe.rowconfigure(2, weight=1)

# Url frame, where you write the url for scrapping:
    _url_frame = ttk.LabelFrame(_mainframe, text='URL', padding='5 5 5 5')
    _url_frame.grid(row=0, column=0, sticky=(E, W))
# make _url_frame resizable:
    _url_frame.columnconfigure(0, weight=1)
    #_url_frame.columnconfigure(1, weight=1)
    _url_frame.rowconfigure(0, weight=1)


    _url = StringVar()
    _url.set('http://localhost:8000')
    _url_entry = ttk.Entry(
      _url_frame, width=40, textvariable=_url)
    _url_entry.grid(row=0, column=0, sticky=(E, W, S, N), padx=5)
    _fetch_btn = ttk.Button(
      _url_frame, text='Fetch info', command=fetch_url)
    _fetch_btn.grid(row=0, column=1, sticky=W, padx=5)

# Define the frame, where list of all images will be:   
    _img_frame = ttk.LabelFrame(
      _mainframe, text='Content', padding='9 0 0 0')
    _img_frame.grid(row=1, column=0, sticky=(N, S, E, W))
    _img_frame.columnconfigure(0, weight=1)
    _img_frame.rowconfigure(0, weight=1)
  
    _images = StringVar()
    _img_listbox = Listbox(
      _img_frame, listvariable=_images, height=6, width=25)
    _img_listbox.grid(row=0, column=0, sticky=(E, W, S, N), pady=5)
                                           # here ^ ^ ^ we make the listbox expandable.
    _scrollbar = ttk.Scrollbar(
      _img_frame, orient=VERTICAL, command=_img_listbox.yview)
    _scrollbar.grid(row=0, column=1, sticky=(S, N), pady=6)
    _img_listbox.configure(yscrollcommand=_scrollbar.set)

# Define frame for the radio buttons(buttons to select save format for the images):
    _radio_frame = ttk.Frame(_img_frame)
    _radio_frame.grid(row=0, column=2, sticky=(N, S, W, E))
# simple lable with text for the radio buttons:
    _choice_lbl = ttk.Label(
      _radio_frame, text='Choose how to save images')
    _choice_lbl.grid(row=0, column=0, padx=5, pady=5)
########
    _save_method = StringVar()
    _save_method.set('img')
    _img_only_radio = ttk.Radiobutton(
      _radio_frame, text='As Images', variable=_save_method, value='img')
    _img_only_radio.grid(
      row=1, column=0, padx=5, pady=2, sticky=W)
    _img_only_radio.configure(state='normal')
##########
    _json_radio = ttk.Radiobutton(
      _radio_frame, text='As JSON', variable=_save_method, value='json')
    _json_radio.grid(row=2, column=0, padx=5, pady=2, sticky=W)    
############
    _scrape_btn = ttk.Button(
      _mainframe, text='Scrape!', command=save)
    _scrape_btn.grid(row=2, column=0, sticky=E, pady=5)

# Define the frame for the StatusBar:
    _status_frame= ttk.Frame(
      _root, relief='sunken', padding='2 2 2 2')
    _status_frame.grid(row=1, column=0, sticky=(E, W, S))
#######
    _status_msg = StringVar()
    _status_msg.set('Type a URL to start scraping...')
    _status = ttk.Label(
     _status_frame, textvariable=_status_msg, anchor=W)
    _status.grid(row=0, column=0, sticky=(E, W))
##########

    _root.mainloop()
