#!/usr/local/bin/python2.5
#
# gpsfake -- test harness for gpsd
#
# Simulates a GPS, playing back a logfile
# Most of the logic for this now lives in gpsfake.py,
# factored out so we can write other test programs with it.

import sys, os, signal, time, getopt, socket
import gpsfake

# So we can do regression tests without stepping on a production daemon
# According to IANA port 12000 belongs to an IBM SNA service. Picking an
# obsolete service seems safer than picking an unused number that IANA might
# allocate in the future.
fakeport = 12000

class Baton:
    "Ship progress indications to stderr."
    def __init__(self, prompt, endmsg=None):
        self.stream = sys.stderr
        self.stream.write(prompt + "...")
        if os.isatty(self.stream.fileno()):
            self.stream.write(" \010")
        self.stream.flush()
        self.count = 0
        self.endmsg = endmsg
        self.time = time.time()
        return

    def twirl(self, ch=None):
        if self.stream is None:
            return
        if os.isatty(self.stream.fileno()):
            if ch:
                self.stream.write(ch)
            else:
                self.stream.write("-/|\\"[self.count % 4])
                self.stream.write("\010")
            self.stream.flush()
        self.count = self.count + 1
        return

    def end(self, msg=None):
        if msg == None:
            msg = self.endmsg
        if self.stream:
            self.stream.write("...(%2.2f sec) %s.\n" % (time.time() - self.time, msg))
        return

try:
    (options, arguments) = getopt.getopt(sys.argv[1:], "1bc:D:fghilm:no:pr:s:vx")
except getopt.GetoptError, msg:
    print "gpsfake: " + str(msg)
    raise SystemExit, 1

port = None
progress = False
cycle = 0
monitor = ""
speed = 4800
linedump = False
predump = False
pipe = False
singleshot = False
flicker = False
promptme = False
init = "w+r+"
doptions = ""
verbose = 0
for (switch, val) in options:
    if (switch == '-1'):
        singleshot = True
        port = fakeport
    elif (switch == '-b'):
        progress = True
    elif (switch == '-c'):
        cycle = float(val)
    elif (switch == '-D'):
        doptions += " -D " + val
    elif (switch == '-g'):
        monitor = "xterm -e gdb -tui --args "
    elif (switch == '-i'):
        linedump = promptme = True
    elif (switch == '-l'):
        linedump = True
    elif (switch == '-m'):
        monitor = val + " "
    elif (switch == '-n'):
        doptions += " -n"
    elif (switch == '-x'):
        predump = True
    elif (switch == '-o'):
        doptions = val
    elif (switch == '-p'):
        pipe = True
    elif (switch == '-r'):
        if flicker:
            init += val
        else:
            init = val
    elif (switch == '-s'):
        speed = int(val)
    elif (switch == '-v'):
        verbose += 1
    elif (switch == '-h'):
        sys.stderr.write("usage: gpsfake [-h] [-l] [-m monitor] [--D debug] [-o options] [-p] [-s speed] [-c cycle] [-b] logfile\n")
        raise SystemExit,0
logfile = arguments[0]

def hexdump(s):
    rep = ""
    for c in s:
        rep += "%02x" % ord(c)
    return rep

def fakehook(linenumber, fakegps):
    if len(fakegps.testload.sentences) == 0:
        print >>sys.stderr, "fakegps: no sentences in test load."
        raise SystemExit, 1
    if linenumber % len(fakegps.testload.sentences) == 0:
        if singleshot and linenumber > 0:
            return False
        if progress:
            baton.twirl('*\010')
        elif not singleshot:
            sys.stderr.write("gpsfake: log cycle begins.\n")
    time.sleep(cycle)
    if linedump and fakegps.testload.legend:
        ml = fakegps.testload.sentences[linenumber % len(fakegps.testload.sentences)].strip()
        if not fakegps.testload.textual:
            ml = hexdump(ml)
        announce = fakegps.testload.legend % (linenumber % len(fakegps.testload.sentences) + 1) + ml
        if promptme:
            raw_input(announce + "? ")
        else:
            print announce
    if progress:
        baton.twirl()
    return True

if progress:
    baton = Baton("Processing %s" % logfile, "done")
else:
    print >>sys.stderr, "Processing %s" % logfile

test = gpsfake.TestSession(prefix=monitor, port=port, options=doptions, verbose=verbose, predump=predump)

if pipe:
    test.reporter = sys.stdout.write
    if verbose:
        progress = False
        test.progress = sys.stdout.write

try:
    try:
        test.gps_add(logfile, speed=speed, pred=fakehook)
    except gpsfake.TestLoadError, e:
        sys.stderr.write("gpsfake: " + e.msg + "\n")
        raise SystemExit, 1
    except gpsfake.PacketError, e:
        sys.stderr.write("gpsfake: " + e.msg + "\n")
        raise SystemExit, 1
    except gpsfake.DaemonError, e:
        sys.stderr.write("gpsfake: " + e.msg + "\n")
        raise SystemExit, 1
    except IOError, e:
        sys.stderr.write("gpsfake: no such file as %s or file unreadable\n"%e.filename)
        raise SystemExit, 1
    except OSError:
        sys.stderr.write("gpsfake: can't open pty.\n")
        raise SystemExit, 1

    try:
        test.client_add(init + "\n")
        test.run()
    except socket.error, msg:
        sys.stderr.write("gpsfake: socket error %s.\n" % msg)
        raise SystemExit, 1
finally:
    test.cleanup();

if progress:
    baton.end()

# gpsfake ends here
