# Refresh the feed file from the original source
# Only download the file if the source is newer than the local copy
# This code was adapted from https://forums.raspberrypi.com/viewtopic.php?t=152226#p998268

import email.utils
import os
import sys
import time
import requests

# First we construct a handful of functions - testing happens down at the end
def httpdate_to_ts(dt):
    time_tuple = email.utils.parsedate_tz(dt)
    return 0 if time_tuple is None else email.utils.mktime_tz(time_tuple)


def ts_to_httpdate(ts):
    return email.utils.formatdate(timeval=ts, localtime=False, usegmt=True)


def write_file_with_time(filename, content, timestamp):
    # put the content into the file
    with open(filename, 'wb') as fp:
        fp.write(content)

    # Then set the file's timestamps as requested
    os.utime(filename, times=(time.time(), timestamp))


# v1: download remote file if HTTP's Last-Modified header indicates that
#     the file has been updated. This requires the remote server to support
#     sending the Last-Modified header.
#
def update_local_file_from_url_v1(last_mtime, local_file, url):

    # Check the status of the remote file without downloading it
    r1 = requests.head(url)
    if r1.status_code != requests.codes.ok:
        # http request failed
        print('HEY! get for {} returned {}'.format(url, r1.status_code),
              file=sys.stderr)
        return False, last_mtime

    # Get the modification time for the file, if possible
    if 'Last-Modified' in r1.headers:
        mtime = httpdate_to_ts(r1.headers['Last-Modified'])
    else:
        print('HEY! no Last-Modified header for {}'.format(url),
              file=sys.stderr)
        return False, last_mtime

    # If file is newer than last one we saw, get it
    updated = False
    print('Comparing feed mtimes: feed: {} vs remote {}'.format(str(last_mtime), str(mtime)), file=sys.stderr)
    if not last_mtime or mtime > int(last_mtime):
        print('Refreshing feed..', file=sys.stderr)
        updated = True
        r2 = requests.get(url)  # download the new file content
        if r2.status_code != requests.codes.ok:
            # http request failed
            print('HEY! get for {} returned {}'.format(url, r2.status_code),
                  file=sys.stderr)
            return False, last_mtime

        # write new content to local file
        write_file_with_time(local_file, r2.content, mtime)
        print('Downloaded {}.'.format(local_file), file=sys.stderr)
    else:   
        print('No need to refresh feed.', file=sys.stderr)

    return updated, mtime


# v2: download remote file conditionally, with HTTP's If-Modified-Since header.
#     This requires the remote server to support both sending the Last-Modified
#     header and receiving the If-Modified-Since header.
#
def update_local_file_from_url_v2(last_mtime, local_file, url):

    # Get the remote file, but only if it has changed
    r = requests.get(url, headers={
                              'If-Modified-Since': ts_to_httpdate(last_mtime)
                          })

    updated, mtime = False, last_mtime

    if r.status_code == requests.codes.ok:
        # File is updated and we just downloaded the content
        updated = True

        # write new content to local file
        write_file_with_time(local_file, r.content, mtime)

        # Update our notion of the file's last modification time
        if 'Last-Modified' in r.headers:
            mtime = httpdate_to_ts(r.headers['Last-Modified'])
        else:
            print('HEY! no Last-Modified header for {}'.format(url),
                  file=sys.stderr)

    elif r.status_code == requests.codes.not_modified:
        # Successful call, but no updates to file
        print('As of {}, server says {} is the same'.format(time.ctime(), url))
    else:
        # http request failed
        print('HEY! get for {} returned {}'.format(url, r.status_code),
              file=sys.stderr)

    return updated, mtime
