#include <stdio.h>
#include "httpfsclient.h"

#ifdef WIN32
#include "gnu_getopt\getopt.h"
#endif

#ifdef __unix__
#include <unistd.h>
#endif

#define MINUTES_OFF_ALLOWED 60
#define MAX_RANGE_SIZE 256      /* actually a binary search with this as
                                 * the major term -- allows the range
                                 * to be 2*MAX_RANGE_SIZE-1 seconds */

static void usage(const char * err)
{
    if (err)
        fprintf(stderr, "*** ERROR: %s\n\n", err);
    fprintf(stderr, "Usage: timecheck [-a address] [-o offset]\n"
            "\n"
            "Address defaults to $RTV4K_ADDRESS\n"
            "Starting offset defaults to $TIMEOFF if set, otherwise 0\n"
            "\n");
    exit(err ? 1 : 0);
}

static int check_connectivity(char * address, char * dir, int encrypt)
{
    char * result;

    if (encrypt) {
        replaytv_version.major = 4;
        replaytv_version.minor = 3;
        replaytv_version.patch = 0;
        replaytv_version.build = 280;
    } else {
        replaytv_version.major = 4;
        replaytv_version.minor = 1;
        replaytv_version.patch = 1;
        replaytv_version.build = 190;
    }
    
    if (hfs_do_simple(&result, address, "volinfo",
                      "name", dir,
                      NULL) != 0)
        return -1;
    free(result);
    return 0;
}

static int check_offset(char * address, int offset)
{
    char envbuf[64];
    sprintf(envbuf, "TIMEOFF=%d", offset);
    putenv(envbuf);
    return check_connectivity(address, "/Video", 1);
}

static int find_in_range(char * address, int start_offset, int * p_offset)
{
    int i;
    int offset;

    offset = start_offset;
    
    for (i = 0; i < MINUTES_OFF_ALLOWED; i++) {
        offset = start_offset + i*60;
        if (check_offset(address, offset) == 0)
            break;
        offset = start_offset - i*60;
        if (check_offset(address, offset) == 0)
            break;
    }
    if (i == MINUTES_OFF_ALLOWED)
        return -1;
    *p_offset = offset;
    return 0;
}

static int find_range_bound(char * address, int start_offset,
                            int * p_offset, int direction)
{
    int i;
    int offset, check;

    offset = start_offset;

    for (i = MAX_RANGE_SIZE; i > 0; i /= 2) {
        check = offset + direction * i;
        if (check_offset(address, check) == 0)
            offset = check;
    }

    *p_offset = offset;
    return 0;
}

static int find_range_top(char * address, int start_offset, int * p_offset)
{
    return find_range_bound(address, start_offset, p_offset, 1);
}

static int find_range_bottom(char * address, int start_offset, int * p_offset)
{
    return find_range_bound(address, start_offset, p_offset, -1);
}


int main(int argc, char ** argv)
{
    char * address;
    char * timeoff;
    int offset, offset_high, offset_low;
    int ch;
    
    address = getenv("RTV4K_ADDRESS");
    timeoff = getenv("TIMEOFF");
    
    while ((ch = getopt(argc, argv, "a:o:")) != EOF) {
        switch(ch) {
            case 'a':
                address = optarg;
                break;
            case 'o':
                timeoff = optarg;
                break;
            default:
                usage("Invalid argument");
        }
    }
    if (optind != argc)
        usage("Unneeded argument");

    if (address == NULL)
        usage("Need replay's address");

    if (timeoff == NULL)
        offset = 0;
    else
        offset = atoi(timeoff);
    

    /* First, check to make sure *anything* works */
    if (check_connectivity(address, "/SnapshotDir", 0)) {
        fprintf(stderr, "Error communicating with %s unrelated to time.\n",
                address);
        return -1;
    }

    hfs_output_errors = 0;

    /* Second, make sure encryption is required -- if it's not required,
     * it's not supported, and if it's not supported there's no such thing
     * as a scorrect offset */
    if (check_connectivity(address, "/Video", 0) == 0) {
        fprintf(stderr,
                "Encryption isn't required: is %s really running 4.3+?\n",
                address);
        return -1;
    }

    /* Now, find a time offset that works, any offset */
    if (find_in_range(address, offset, &offset)) {
        fprintf(stderr, "Couldn't find a working offset.\n");
        return -2;
    }

    /* And then find the highest & lowest offsets that works */
    if (find_range_top(address, offset, &offset_high)) {
        fprintf(stderr, "Couldn't find the top of the range(?!)\n");
        return -3;
    }
    if (find_range_bottom(address, offset, &offset_low)) {
        fprintf(stderr, "Couldn't find the bottom of the range(?!)\n");
        return -4;
    }
    
    printf("TIMEOFF=%d\n# acceptable = %d..%d\n",
           (offset_high + offset_low)/2,
           offset_low, offset_high);
    return 0;
}

