import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

url = 'https://raw.githubusercontent.com/AdiPersonalWorks/Random/master/student_scores%20-%20student_scores.csv'
df = pd.read_csv(url)

fig = plt.figure(figsize=(8,6))
sns.scatterplot(data=df, x='Hours', y='Scores')
# plt.show()
plt.close()

# splitting the data into train and test values.
X = df[['Hours']].values
y = df['Scores'].values

# taking 30% fo the data for testing and rest for training.
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42, test_size=0.3)

# training a linearRegression model.
lr = LinearRegression()
lr.fit(X_train, y_train)

# predicting the scores for given hours in test dataset.
yhat_train = lr.coef_ * X_train + lr.intercept_

fig = plt.figure(figsize=(8,6))
plt.scatter(X_train, y_train)
plt.plot(X_train, yhat_train, '-r')
# plt.show()
plt.close()

# predicting values on test data
yhat_test = lr.predict(X_test)

fig = plt.figure(figsize=(8,6))
plt.scatter(X_test, y_test)
plt.plot(X_test, yhat_test, '-r')
# plt.show()
plt.close()

# evaluating the model based on test results.
r_score = r2_score(y_test, yhat_test)
MSE = mean_squared_error(y_test, yhat_test)
MAE = mean_absolute_error(y_test, yhat_test)

eval_df = pd.DataFrame({"Evalution Method": ['R2 score', 'Mean Sqaured Error', 'Mean Absolute Error'], "Values": [r_score, MSE, MAE]})
print(eval_df)
print(lr.predict([[9.25]]))


from collections import deque

def search(lines, pattern, history=5):
    previous_lines = deque(maxlen=history)
    for line in lines:
        if pattern in line:
            yield line, previous_lines
        previous_lines.append(line)

if __name__ == '__main__':
    with open('somefile.txt') as f:
        for line, prev_lines in search(f, 'python', 5):
            for p_line in prev_lines:
                print(p_line, end='')
            print(line, end='')
            print('-'*20)


# import secrets and tokens from config.py
from config import client_id, client_secret, refresh_token

import requests
import urllib3

# import packages for data manipulation
import pandas as pd
from pandas.io.json import json_normalize
import numpy as np

# disable warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

auth_url = "https://www.strava.com/oauth/token"
activites_url = "https://www.strava.com/api/v3/athlete/activities"

payload = {
    'client_id': client_id,
    'client_secret': client_secret,
    'refresh_token': refresh_token,
    'grant_type': "refresh_token",
    'f': 'json'
}

print("Requesting Token...\n")
res = requests.post(auth_url, data=payload, verify=False)
access_token = res.json()['access_token']
print("Access Token = {}\n".format(access_token))

header = {'Authorization': 'Bearer ' + access_token}
param = {'per_page': 200, 'page': 1}
my_dataset = requests.get(activites_url, headers=header, params=param).json()

print(my_dataset[0]["name"])
print(my_dataset[0]["map"]["summary_polyline"])

activities = json_normalize(my_dataset)
#activities.columns #See a list of all columns in the table
#activities.shape #See the dimensions of the table.

#Create new dataframe with only columns I care about
#cols = ['name', 'upload_id', 'type', 'distance', 'moving_time',
#         'average_speed', 'max_speed','total_elevation_gain',
#         'start_date_local'
#       ]
#activities = activities[cols]
#Break date into start time and date
activities['start_date_local'] = pd.to_datetime(activities['start_date_local'])
activities['start_time'] = activities['start_date_local'].dt.time
activities['start_date_local'] = activities['start_date_local'].dt.date
activities.head(5)

# For testing, only take top 1 record(s)
activities = activities.query("type == 'Ride'")
activities = activities.head(1)

print(my_dataset[0]["name"])
print(my_dataset[0]["map"]["summary_polyline"])
print(np.average(activities["average_speed"]))
print(np.average(activities["distance"]))
###################
# import modules
import os
import time
import matplotlib.pyplot as plt
import folium
import polyline
import base64
from tqdm import tqdm
# disable warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# add decoded summary polylines
activities['map.polyline'] = activities['map.summary_polyline'].apply(polyline.decode)
print("turkey")
#####################
# define function to get elevation data using the open-elevation API
def get_elevation(latitude, longitude):
    base_url = 'https://api.open-elevation.com/api/v1/lookup'
    payload = {'locations': f'{latitude},{longitude}'}
    r = requests.get(base_url, params=payload).json()['results'][0]
    return r['elevation']
# get elevation data
elevation_data = list()
for idx in tqdm(activities.index):
    activity = activities.loc[idx, :]
    elevation = [get_elevation(coord[0], coord[1]) for coord in activity['map.polyline']]
    elevation_data.append(elevation)
# add elevation data to dataframe
activities['map.elevation'] = elevation_data
print("turkey")
print("turkey_two")
######################
# convert data types
activities.loc[:, 'start_date'] = pd.to_datetime(activities['start_date']).dt.tz_localize(None)
activities.loc[:, 'start_date_local'] = pd.to_datetime(activities['start_date_local']).dt.tz_localize(None)
# convert values
activities.loc[:, 'distance'] /= 1000 # convert from m to km
activities.loc[:, 'average_speed'] *= 3.6 # convert from m/s to km/h
activities.loc[:, 'max_speed'] *= 3.6 # convert from m/s to km/h
# set index
activities.set_index('start_date_local', inplace=True)
# drop columns
activities.drop(
    [
        'map.summary_polyline',
        'resource_state',
        'external_id',
        'upload_id',
        'location_city',
        'location_state',
        'has_kudoed',
        'start_date',
        'athlete.resource_state',
        'utc_offset',
        'map.resource_state',
        'athlete.id',
        'visibility',
        'heartrate_opt_out',
        'upload_id_str',
        'from_accepted_tag',
        'map.id',
        'manual',
        'private',
        'flagged',
    ],
    axis=1,
    inplace=True
)
print("turkey")
print("turkey_two")
######################
# select one activity
from IPython.display import display
my_ride = activities.iloc[0, :] # first activity (most recent)
# plot ride on map
centroid_lat_val_list = list()
centroid_long_val_list = list()
counter = 0
for idx in my_ride['map.polyline']:
    centroid_lat_val = my_ride['map.polyline'][counter][0]
    centroid_long_val = my_ride['map.polyline'][counter][1]
    counter += 1
    centroid_lat_val_list.append(centroid_lat_val)
    centroid_long_val_list.append(centroid_long_val)

#centroid = [
    #np.mean([my_ride['map.polyline'][0][0] for coord in my_ride['map.polyline'][0]]),
    #np.mean([coord[0] for coord in my_ride['map.polyline'][0]]),
    #np.mean([coord[0] for coord in my_ride['map.polyline']]),
    #np.mean([coord[1] for coord in my_ride['map.polyline'][0]])
#]
centroid = [np.mean(centroid_lat_val_list), np.mean(centroid_long_val_list)]

m = folium.Map(location=centroid, zoom_start=10)
folium.PolyLine(my_ride['map.polyline'], color='red').add_to(m)
display(m)

print("turkey")
print("turkey_two")


import re
import pyautogui as g
from time import sleep
import pyperclip as clip
import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error
from graphviz import Source
from sklearn.tree import export_graphviz
from sklearn import tree
try:
    from PIL import Image
except ImportError:
    import Image
import pytesseract
g.FAILSAFE = True
sleep(2)
g.size()
g.position()

def c():
    g.mouseDown()
    g.mouseUp()

def c2():
    c()
    c()

def rc():
    g.click(button='right')

def select_all_and_copy():
    rc()
    g.keyDown('a')
    g.keyUp('a')
    g.keyDown('ctrl')
    g.keyDown('c')
    g.keyUp('c')
    g.keyUp('ctrl')

im2 = g.screenshot('output/labels3/{}.png'.format(str(i).zfill(4)))

from PIL import Image

def crop(image_path, coords, saved_location):
    image_obj = Image.open(image_path)
    cropped_image = image_obj.crop(coords)
    cropped_image.save(saved_location)

for i in range(4410):
    image = 'output/labels3/{}.png'.format(str(i).zfill(4))
    crop(image, (300,817,900,860), 'output/cropped_labels3/{}.png'.format(str(i).zfill(4)))

    pytesseract.pytesseract.tesseract_cmd = '/usr/local/Cellar/tesseract/4.0.0_1/bin/tesseract'

labels3 = []
for i in range(4410):
    s = pytesseract.image_to_string(Image.open('output/cropped_labels3/{}.png'.format(str(i).zfill(4))))
    match1 = re.match("(.*?\d+?.\d) ", s)
    try:
        number = float(match1.group(1).strip())
        labels3.append(number)
    except:
        labels3.append(None)

for i, label in zip(range(len(labels3)), labels3):
    print(i, label)


from anytree import Node, RenderTree, search, Walker

def getPath(cdStack):
  return '/'.join(cdStack)

with open('day7/input.in', 'r', encoding="utf-8") as f:
  commands = f.read().split('\n')
  cdStack = [] # tracks the current cd and its path
  root = Node('~', None, type='dir', size=0)

  nodes = {'/': root}
  sumToDelete = 0
  w = Walker()
  # print(commands)
  for line in commands:
    # move up a level by popping the dir off the stack
    if line == '$ cd ..':
      cdStack.pop()

    # move into the dir by pushing to the stack
    elif line.startswith('$ cd'):
      cdStack.append(line[5:])
      # print(cdStack)

    # make new directory
    elif line.startswith('dir'):
      dirName = line[4:]
      # add a node to the dictionary with the dir path as the key and the Node
      # object as the value, and the top of the cdStack as the parent
      parentPath = getPath(cdStack)
      dpath = parentPath + '/' + dirName
      nodes[dpath] = Node(dirName, nodes[parentPath], type='dir', size=0)
      # print(f'new dir: {nodes[dpath]}')

    # ignore
    elif line.startswith('$ ls'):
      continue

    # add new file to directory
    else:
      fsize, fname = line.split(' ')
      parentPath = getPath(cdStack)
      fpath = parentPath + '/' + fname
      nodes[fpath] = Node(fname, nodes[parentPath], type='file', size=int(fsize))

  sumToDelete2 = float('inf')

  # calculate the size of each dir
  for dir in search.findall(root, filter_=lambda node: node.type == 'dir'):
    files = search.findall(dir, filter_=lambda node: node.type == 'file')
    # print(f'chilren of {dir.name}: {files}')
    dir.size = sum(int(f.size) for f in files)
    if(dir.size <= 100000):
      sumToDelete += dir.size

    TOTAL_DISK_SPACE = 70000000
    SPACE_NEEDED = 30000000
    SPACE_USED = nodes['/'].size
    SPACE_AVAILABLE = TOTAL_DISK_SPACE - SPACE_USED
    SPACE_TO_FREE = SPACE_NEEDED - SPACE_AVAILABLE
    print (SPACE_NEEDED, SPACE_AVAILABLE, SPACE_TO_FREE)
    if(dir.size < sumToDelete2 and dir.size > SPACE_TO_FREE):
      sumToDelete2 = dir.size

  # print(RenderTree(root))

  print(f'[PART 1]: sumToDelete: {sumToDelete}')
  print(f'[PART 2]: sumToDelete: {sumToDelete2}')


import torch
import PIL.Image as Image
import numpy as np
import matplotlib.pyplot as plt
import argparse
from pathlib import Path

DATA = '/multiview/datasets/Panthera_tigris/all_flanks_splits_600'

def get_image_file(opt):
    if not opt.isnumeric() or opt == 'rand':
        img_file = opt
    else:
        imglist = list(Path(DATA).iterdir())
        if opt == 'rand':
            img_file = np.random.choice(imglist)
        else:
            img_file = imglist[int(opt)]
    return img_file

def get_image(img_file, size):
    img = Image.open(img_file)
    scale = size / max(img.size)
    w, h = img.size
    img = img.convert('L')
    img = img.resize((int(w * scale), int(h * scale)), Image.BICUBIC)
    img = np.array(img) / np.float32(255)
    return img

def get_point(point, k, height, width):
    if point[0] == -1 and point[1] == -1:
        x = np.random.randint(0, width - k)
        y = np.random.randint(0, height - k)
        point = (x, y)
    return point

def calculate_distance(img, point, k=11, whiten=False):
    img = torch.from_numpy(img).view(1, 1, *img.shape)
    if torch.cuda.is_available():
        img = img.cuda()

    ps = torch.nn.functional.unfold(img, k)
    ps = ps.view(k**2, img.shape[-2] - k + 1, img.shape[-1] - k + 1)

    if whiten:
        mu = ps.mean(0, keepdim=True)
        sig = ps.std(0, keepdim=True)
        ps = (ps - mu) / sig

    x, y = point
    dist = torch.pow(ps - ps[:, y, x].view(-1, 1, 1), 2).sum(0)
    return dist

def show_closest(img, dist, k, n=300, tol=0.75):

    val, ind = torch.sort(dist.view(-1))

    plt.imshow(img)

    cm = plt.get_cmap('autumn', 500)
    tol = int(tol * k)
    pts = []
    for ii, i in enumerate(ind[:n]):
        i = i.item()
        y = i // dist.shape[1]
        x = i - y * dist.shape[1]
        suppress = False
        for yy, xx in pts:
            if (xx - x)**2 + (yy - y)**2 <= tol**2:
                suppress = True
                break
        if suppress: continue
        pts.append([y, x])
        plt.vlines([x, x + k], [y, y], [y + k, y + k], colors=cm(ii))
        plt.hlines([y, y + k], [x, x], [x + k, x + k], colors=cm(ii))
        plt.text(x + 1, y + 1, str(ii), fontsize=8, color='k',
                 verticalalignment='top')
    plt.show()

def main():
    parser = argparse.ArgumentParser('Visualize patch distances')
    parser.add_argument('-i', '--img', type=str, default='0',
        help='Image. If an integer, uses it as an index into a list of image'
             'files. If a filename, uses the image in that file. If the string '
             '"rand", chooses a random image from the list of image files.')
    parser.add_argument('-p', '--point', type=int, nargs=2, default=(-1, -1),
        help='(x, y) point to use as top right corner of reference patch. If '
             '(-1, -1), then choose a random point.')
    parser.add_argument('-k', '--patch-size', type=int, default=15,
        help='Size of a patch (square).')
    parser.add_argument('-s', '--size', type=int, default=320,
        help='Size of the longer side of the image after resize')
    parser.add_argument('-w', '--whiten', action='store_true',
        help='Whiten each patch individually before calculating distances.')

    args = parser.parse_args()

    whiten = args.whiten
    img_file = get_image_file(args.img)
    img = get_image(img_file, args.size)
    k = args.patch_size
    point = get_point(args.point, k, *img.shape)

    print('Calculate distance')
    dist = calculate_distance(img, point, k, whiten)
    print('Show closest patches')
    show_closest(img, dist, k)

if __name__ == '__main__':
    main()