# %% [code]
# %% [markdown]
# # Prepare data and environement

# %% [code] {"execution":{"iopub.status.busy":"2021-12-20T11:18:32.226832Z","iopub.execute_input":"2021-12-20T11:18:32.227218Z","iopub.status.idle":"2021-12-20T11:19:10.914635Z","shell.execute_reply.started":"2021-12-20T11:18:32.227187Z","shell.execute_reply":"2021-12-20T11:19:10.913263Z"}}
import os
import zipfile

test_folder="./input/test1"
train_folder= "./input/train"
# Extract data
if not os.path.isdir(test_folder):
    with zipfile.ZipFile("../input/dogs-vs-cats/test1.zip","r") as zip_ref:
        zip_ref.extractall("./input/")

if not os.path.isdir(train_folder):
    with zipfile.ZipFile("../input/dogs-vs-cats/train.zip","r") as zip_ref:
        zip_ref.extractall("./input/")
        

output = os.popen('pip install keras-visualizer').read()
output += os.popen('pip install graphviz').read()

print(output)
from graphviz import Source
from keras_visualizer import visualizer 
# Put cats and dogs in repository
import glob, os, shutil

for item_class in["cat","dog"]:
        files = glob.glob(f'{train_folder}/{item_class}.*.jpg')
        class_folder=os.path.join(train_folder,item_class)
        os.makedirs(class_folder, exist_ok=True) 
        for file in files:
            shutil.move(file, class_folder)
            


# %% [code] {"execution":{"iopub.status.busy":"2021-12-20T11:19:18.727824Z","iopub.execute_input":"2021-12-20T11:19:18.728161Z","iopub.status.idle":"2021-12-20T11:19:22.851989Z","shell.execute_reply.started":"2021-12-20T11:19:18.728123Z","shell.execute_reply":"2021-12-20T11:19:22.850518Z"}}

# Utililty function
def list_files(startpath):
    from PIL import Image
    import os
    for root, dirs, files in os.walk(startpath):
        level = root.replace(startpath, '').count(os.sep)
        indent = ' ' * 4 * (level)
        print('{}{}/'.format(indent, os.path.basename(root)))
        subindent = ' ' * 4 * (level + 1)
        for itf, f in enumerate(files):
            if itf <6:
                if f.split(".")[-1] == "jpg":
                    image = Image.open(os.path.join(root,f))
                    f = f"{f.ljust(30,' ')} size: {image.size}"
                print('{}{}'.format(subindent, f))
            else:
                print(subindent,"6 files shown.. on",len(files),"\t", len(files)-6, "files left")
                break

                
def save_model_as_file(model,filename,format="png"):

    dotfile = f"{filename}.dot"
    visualizer(model, filename=dotfile, format=None, view=False)
    print(f"Model exported as,", dotfile)

    s = Source.from_file(dotfile)
    s.format=format
    s.render(filename)
    print(f"Model exported as {format} saved as {filename}.{format}")
    

# Plot an array of things
# [{"title":"filename"}]
# [{"title":"2darray"}]
# [{"title":"pilimg"}]

def plot_figures(images_dicts, ncols=5):
    import matplotlib.pyplot as plt
    import numpy as np
    import PIL

    from PIL import Image
    # settings
    import math
    nrows = math.ceil(len(images_dicts) / ncols)
    figsize = [nrows*6, ncols * 1.5]  # figure size, inches
    # prep (x,y) for extra plotting on selected sub-plots
    xs = np.linspace(0, 2 * np.pi, 60)  # from 0 to 2pi
    ys = np.abs(np.sin(xs))  # absolute of sine

    # create figure (fig), and array of axes (ax)
    fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=figsize)

    if len(images_dicts) >= ncols:
        ax=ax.flatten()
    # plot simple raster image on each sub-plot
    for axi, img_dict in zip(ax, images_dicts):
        title, img = list(img_dict.items())[0]
        
        print("Plotting",title)
        if type(img) is str:
            img = Image.open(img)
        if type(PIL.PngImagePlugin.PngImageFile) is PIL.PngImagePlugin.PngImageFile:
            img = np.array(img)
        # i runs from 0 to (nrows*ncols-1)
        # axi is equivalent with ax[rowid][colid]
        axi.imshow(img)
        axi.set_title(title)

    # one can access the axes by ax[row_id][col_id]
    # do additional plotting on ax[row_id][col_id] of your choice
    # ax[0][2].plot(xs, 3 * ys, color='red', linewidth=3)
    # ax[4][3].plot(ys ** 2, xs, color='green', linewidth=3)

    plt.tight_layout()
    plt.show()

files=glob.glob(f'{train_folder}/cat/*.jpg')+glob.glob(f'{train_folder}/dog/*.jpg')
import random
import os.path
  
random.shuffle(files)
files=files[:30]
some_figs=[
    {os.path.basename(file):file} for file in files
]
plot_figures(some_figs)

# %% [markdown]
# # One block code from tutorial [github](https://gist.github.com/fchollet/0830affa1f7f19fd47b06d4cf89ed44d)

# %% [code]
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras import backend as K

# dimensions of our images.
img_width, img_height = 150, 150

train_data_dir = train_folder
validation_data_dir = train_folder
nb_train_samples = 2000
nb_validation_samples = 800
epochs = 50
batch_size = 16

if K.image_data_format() == 'channels_first':
    input_shape = (3, img_width, img_height)
else:
    input_shape = (img_width, img_height, 3)

model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))

model.compile(loss='binary_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

save_model_as_file(model,"my_mod",format="png")

# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator(
    rescale=1. / 255,
    shear_range=0.2,
    zoom_range=0.2,

    validation_split=0.5,
    horizontal_flip=True)

# this is the augmentation configuration we will use for testing:
# only rescaling
test_datagen = ImageDataGenerator(rescale=1. / 255,
                                  validation_split=0.5
                                  )

train_generator = train_datagen.flow_from_directory(
    train_data_dir,
    target_size=(img_width, img_height),
    batch_size=batch_size,
        class_mode='binary',
        subset="training",
)

validation_generator = test_datagen.flow_from_directory(
    validation_data_dir,
    target_size=(img_width, img_height),
    batch_size=batch_size,
    class_mode='binary',
    subset="validation",
)
model.fit(
    train_generator,
    steps_per_epoch=nb_train_samples // batch_size,
    epochs=epochs,
    validation_data=validation_generator,
    validation_steps=nb_validation_samples // batch_size)

model.save_weights('first_try.h5')


# %% [code]
