#!/usr/bin/env python
# @Author: carlosgilgonzalez
# @Date:   2019-07-09T20:49:15+01:00
# @Last modified by:   carlosgilgonzalez
# @Last modified time: 2019-07-13T22:18:43+01:00

import socket
import time as time_mac
import os
import argparse
import ast
import netifaces
import subprocess
import shlex
import sys
from upydevice import W_UPYDEVICE


parser = argparse.ArgumentParser()
parser.add_argument("-f", help='file to sync', required=True)
parser.add_argument("-p", help='password', required=False)
parser.add_argument("-t", help='target', required=False)
parser.add_argument("-lh", help='local ip', required=False)
parser.add_argument("-o", help='output file name', required=False)
parser.add_argument("-port", help='tcp port', required=False, default=8005, type=int)
parser.add_argument(
    "-s", help='source dir to look for in (default '' flash, "sd" for micro sd) ', required=False)
args = parser.parse_args()

# Start a socket listening for connections on 0.0.0.0:8000 (0.0.0.0 means
# all interfaces)

# TODO: make get_ip() platform independent


def get_ip():
    # scanoutput = subprocess.check_output(["ipconfig", "getifaddr", "en0"])
    # ip = scanoutput.decode('utf-8').split('\n')[0]
    ip = netifaces.ifaddresses('en0')[netifaces.AF_INET][0]['addr']
    return ip


# def do_pg_bar(index, wheel):
#     sys.stdout.write("\033[K")
#     print('[{:<100}]{:>5}{:>5} %'.format('*'*(index), wheel[index % 4], index),
#           end='\r')
#     sys.stdout.flush()

def do_pg_bar(index, wheel, nb_of_total, speed):
    sys.stdout.write("\033[K")
    print('[{:<100}]{:>5}{:>5} % | DATA: {} | SPEED: {} MB/s'.format('*'*(index), wheel[index % 4],
                                                   index, nb_of_total, speed),
          end='\r')
    sys.stdout.flush()


dir = ''
if args.s is not None:
    dir = '/sd'

if args.lh is None:
    local_ip = get_ip()
if args.lh is not None:
    local_ip = args.lh

espdev = W_UPYDEVICE(args.t, args.p)

# sync_cmd = 'upycmd -c "{}" -t {} -p {}'.format(
#     'import sync_tool as synct', args.t, args.p)
espdev.output = None
while espdev.output is None:
    espdev.cmd('import sync_tool as synct;[1]', silent=True)


# sync_tool = subprocess.call(sync_cmd, shell=True)
time_mac.sleep(1)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((local_ip, args.port))
server_socket.listen(1)
print('Server listening...')
sync_connect_cmd = "cli_soc = synct.connect_SOC('{}', {})".format(local_ip, args.port)
espdev.output = None
# while espdev.output is None:
espdev.cmd_nb(sync_connect_cmd, silent=True)
conn, addr = server_socket.accept()
print('Connection received...')
conn.settimeout(2)


def sync_file_raw(soc, filetoget, dir, espdev=espdev):
    cmd_filesize_str = "synct.print_sizefile('{}','{}', rtl=True)".format(dir, filetoget)
    espdev.output = None
    while espdev.output is None:
        espdev.cmd(cmd_filesize_str, silent=True)
    filesize = espdev.output
    print('File size: {:>40.2f} kB'.format(filesize/1024))
    flushed = 0
    while flushed == 0:
        try:
            conn.recv(128)
        except Exception as e:
            flushed = 1
    time_mac.sleep(1)
    sync_tool_cmd = "synct.read_sd_file_sync_raw({},cli_soc)".format("'{}/{}'".format(dir, filetoget))
    espdev.cmd_nb(sync_tool_cmd)
    print('Syncing file {} from upy device'.format(filetoget))
    print('Saving {} file'.format(filetoget))
    print('Progress:\n')
    t0 = 0
    buff = b''
    wheel = ['|', '/', '-', "\\"]
    if args.o is not None:
        filetoget = args.o
    with open(filetoget, 'wb') as log:
        pass
    while True:
        t_0 = time_mac.time()
        try:
            chunk = soc.recv(32*(1024**2))  # 2 KB
            if chunk != b'':
                buff += chunk
                loop_index = int(((len(buff))/filesize)*100)
                nb_of_total = "{:.2f}/{:.2f} MB".format(len(buff)/(1024**2), filesize/(1024**2))
                tdiff = time_mac.time() - t_0
                t_speed = "{:^2.2f}".format((len(chunk)/(1024**2))/tdiff)
                do_pg_bar(loop_index, wheel, nb_of_total, t_speed)
                # do_pg_bar(loop_index, wheel)
                with open(filetoget, 'ab') as log:
                    log.write(chunk)
            else:
                pass
                # print('\nEND OF FILE')
                # soc.sendall
                # final_time = abs(time_mac.time()-t0)
                # print('\nDone in {} seconds'.format(round(final_time, 2)))
                # break
            if t0 == 0:
                t0 = time_mac.time()

            final_time = abs(time_mac.time()-t0)
        except Exception as e:
            if e == KeyboardInterrupt:
                break

            else:
                # print(e)
                if str(e) == 'timed out':
                    print('\nDone in {} seconds'.format(round(final_time, 2)))
                    print('Total data received: {:>30.2f} kB'.format(filesize/1024))
                    break


sync_file_raw(conn, args.f, dir)

conn.close()
sys.exit()
