"""Compare local and remote dictionaries and transfer differing files -- like rdist."""

import sys
from reprlib import repr
import FSProxy
import time
import os

def raw_input(prompt):
    sys.stdout.write(prompt)
    sys.stdout.flush()
    return sys.stdin.readline()

def main():
    pwd = os.getcwd()
    s = input("chdir [%s] " % pwd)
    if s:
        os.chdir(s)
        pwd = os.getcwd()
    host = ask("host", 'voorn.cwi.nl')
    port = 4127
    verbose = 1
    mode = ''
    print("""\
Mode should be a string of characters, indicating what to do with differences.
r - read different files to local file system
w - write different files to remote file system
c - create new files, either remote or local
d - delete disappearing files, either remote or local
""")
    s = input("mode [%s] " % mode)
    if s: mode = s
    address = (host, port)
    t1 = time.time()
    local = FSProxy.FSProxyLocal()
    remote = FSProxy.FSProxyClient(address, verbose)
    compare(local, remote, mode)
    remote._close()
    local._close()
    t2 = time.time()
    dt = t2-t1
    mins, secs = divmod(dt, 60)
    print(mins, "minutes and", round(secs), "seconds")
    input("[Return to exit] ")

def ask(prompt, default):
    s = input("%s [%s] " % (prompt, default))
    return s or default

def askint(prompt, default):
    s = input("%s [%s] " % (prompt, str(default)))
    if s: return string.atoi(s)
    return default

def compare(local, remote, mode):
    print()
    print("PWD =", repr(os.getcwd()))
    sums_id = remote._send('sumlist')
    subdirs_id = remote._send('listsubdirs')
    remote._flush()
    print("calculating local sums ...")
    lsumdict = {}
    for name, info in local.sumlist():
        lsumdict[name] = info
    print("getting remote sums ...")
    sums = remote._recv(sums_id)
    print("got", len(sums))
    rsumdict = {}
    for name, rsum in sums:
        rsumdict[name] = rsum
        if name not in lsumdict:
            print(repr(name), "only remote")
            if 'r' in mode and 'c' in mode:
                recvfile(local, remote, name)
        else:
            lsum = lsumdict[name]
            if lsum != rsum:
                print(repr(name), end=' ')
                rmtime = remote.mtime(name)
                lmtime = local.mtime(name)
                if rmtime > lmtime:
                    print("remote newer", end=' ')
                    if 'r' in mode:
                        recvfile(local, remote, name)
                elif lmtime > rmtime:
                    print("local newer", end=' ')
                    if 'w' in mode:
                        sendfile(local, remote, name)
                else:
                    print("same mtime but different sum?!?!", end=' ')
                print()
    for name in lsumdict.keys():
        if not list(rsumdict.keys()):
            print(repr(name), "only locally", end=' ')
            fl()
            if 'w' in mode and 'c' in mode:
                sendfile(local, remote, name)
            elif 'r' in mode and 'd' in mode:
                os.unlink(name)
                print("removed.")
            print()
    print("gettin subdirs ...")
    subdirs = remote._recv(subdirs_id)
    common = []
    for name in subdirs:
        if local.isdir(name):
            print("Common subdirectory", repr(name))
            common.append(name)
        else:
            print("Remote subdirectory", repr(name), "not found locally")
            if 'r' in mode and 'c' in mode:
                pr = "Create local subdirectory %s? [y] " % \
                     repr(name)
                if 'y' in mode:
                    ok = 'y'
                else:
                    ok = ask(pr, "y")
                if ok[:1] in ('y', 'Y'):
                    local.mkdir(name)
                    print("Subdirectory %s made" % \
                            repr(name))
                    common.append(name)
    lsubdirs = local.listsubdirs()
    for name in lsubdirs:
        if name not in subdirs:
            print("Local subdirectory", repr(name), "not found remotely")
    for name in common:
        print("Entering subdirectory", repr(name))
        local.cd(name)
        remote.cd(name)
        compare(local, remote, mode)
        remote.back()
        local.back()

def sendfile(local, remote, name):
    try:
        remote.create(name)
    except (IOError, os.error) as msg:
        print("cannot create:", msg)
        return

    print("sending ...", end=' ')
    fl()

    data = open(name).read()

    t1 = time.time()

    remote._send_noreply('write', name, data)
    remote._flush()

    t2 = time.time()

    dt = t2-t1
    print(len(data), "bytes in", round(dt), "seconds", end=' ')
    if dt:
        print("i.e.", round(len(data)/dt), "bytes/sec", end=' ')
    print()

def recvfile(local, remote, name):
    ok = 0
    try:
        rv = recvfile_real(local, remote, name)
        ok = 1
        return rv
    finally:
        if not ok:
            print("*** recvfile of %r failed, deleting" % (name,))
            local.delete(name)

def recvfile_real(local, remote, name):
    try:
        local.create(name)
    except (IOError, os.error) as msg:
        print("cannot create:", msg)
        return

    print("receiving ...", end=' ')
    fl()

    f = open(name, 'w')
    t1 = time.time()

    length = 4*1024
    offset = 0
    id = remote._send('read', name, offset, length)
    remote._flush()
    while 1:
        newoffset = offset + length
        newid = remote._send('read', name, newoffset, length)
        data = remote._recv(id)
        id = newid
        if not data: break
        f.seek(offset)
        f.write(data)
        offset = newoffset
    size = f.tell()

    t2 = time.time()
    f.close()

    dt = t2-t1
    print(size, "bytes in", round(dt), "seconds", end=' ')
    if dt:
        print("i.e.", int(size//dt), "bytes/sec", end=' ')
    print()
    remote._recv(id) # ignored

def fl():
    sys.stdout.flush()

if __name__ == '__main__':
    main()
