#! /usr/bin/env python3

import os
import sys
import argparse

version = "1.0"
seperatorStr = "=============================================="

def read_next_test(fp):
    line = ""

    # init the output dictionary
    out = {
        "valid": False,     # did we fill up the record
        "failed": False,    # did the test Pass of Fail
        "name": "",         # name of the test
        "log": [],          # all of the lines of the test output
        "command": "",      # test command line
        "dir": "",          # dir the test was run from
        "cmpDir": "",       # dir nccmp was run from
        "cdataDir": "",     # dir to run cdata from
        "newFile": "",      # new file just created
        "oldFile": ""       # old test file use as comparison
    }

    # find first line of test
    while True:
        line = fp.readline()
        if not line:
            return False
        if " Testing: " in line:
            parts = line.split()
            if len(parts) == 3:
                out["name"] = parts[2]
                break

    # add log header
    out["log"].append(seperatorStr)
    out["log"].append(seperatorStr)
    out["log"].append(seperatorStr)
    
    # search for command
    while True:
        line = fp.readline()
        if not line:
            return False
        out["log"].append(line)
        if line.startswith("Command: "):
            parts = line.split(' ', 1)
            out["command"] = parts[1]
            break;

    # search for dir
    while True:
        line = fp.readline()
        if not line:
            return False
        out["log"].append(line)
        if line.startswith("Directory: "):
            parts = line.split()
            out["dir"] = parts[1]
            break;

    # find new and old filenames
    found = False
    out["cmpDir"] = out["dir"]
    parts = out["command"].split('&&')
    for cmd in parts:
        cmd = cmd.strip()
        if cmd.startswith("cd "):
            cmdParts = cmd.split()
            out["cmpDir"] = cmdParts[1]
        if cmd.startswith("nccmp ") or cmd.startswith("compare_hdf4 ") or cmd.startswith("diff ") or cmd.startswith("tiffcmp ") :
            cmdParts = cmd.split()
            out["newFile"] = out["cmpDir"] + "/" + cmdParts[-1].strip().rstrip('"')
            out["oldFile"] = out["cmpDir"] + "/" + cmdParts[-2].strip()
            found = True
            break
        elif cmd.startswith("compare "):
            cmdParts = cmd.split()
            out["newFile"] = out["cmpDir"] + "/" + cmdParts[-2].strip()
            out["oldFile"] = out["cmpDir"] + "/" + cmdParts[-3].strip()
            found = True
            break
    if not found:
        return out

    # figure out the cdata dir
    line = out["cmpDir"]
    parts = line.split("/")
    if parts[-2] == "testdata":
        out["cdataDir"] = line
    elif parts[-3] == "testdata":
        parts.pop(-1)
        out["cdataDir"] = "/".join(parts)
    else:
        print("ERROR: can't find cdataDir")
        print("    name   =", out["name"])
        print("    cmpDir =", out["cmpDir"])
        print()
        return out

    # delete cdataDir from old and new filenames
    s = out["cdataDir"] + "/"
    out["newFile"] = out["newFile"].replace(s, "")
    out["oldFile"] = out["oldFile"].replace(s, "")

    # search for passed or failed
    lastLine = ""
    while True:
        line = fp.readline()
        if not line:
            return False
        out["log"].append(line)
        if lastLine.startswith("-----------------------------------------"):
            if line == "Test Passed.\n":
                out["failed"] = False
                break;
            if line == "Test Failed.\n":
                out["failed"] = True
                break;
        lastLine = line

    out["valid"] = True
    return out


def runCmd(cmd):
    print("+" + cmd)
    os.system(cmd)


def update(fp):
    cdataSet = set()
    while(True):
        # read the next test record
        rec = read_next_test(fp)
        if not rec:
            break
        
        if rec["valid"] and rec["failed"]:

            cmdList = []
            cmdList.append("cd " + rec["cdataDir"])
            cmdList.append("cp " + rec["newFile"] + " " + rec["oldFile"])
            cmdList.append("cdata add " + rec["oldFile"])

            cdataSet.add(rec["cdataDir"])

            for line in rec["log"]:
                print(line.rstrip())
            for line in cmdList:
                print("+" + line)
            print(seperatorStr)

            val = input("update(u)/ignore(i) (defaut=u): ")
            if val == '' or val == 'u' or val == 'U':
                print("updating")
                runCmd("; ".join(cmdList))
            else:
                print("ignoring")

    print()
    for line in list(cdataSet):
        runCmd("cd " + line + "; cdata push")
    return 0


def listFailed(fp):
    while(True):
        # read the next test record
        rec = read_next_test(fp)
        if not rec:
            break
        
        if rec["valid"] and rec["failed"]:
            for line in rec["log"]:
                print(line.rstrip())
    return 0


def main():
    parser = argparse.ArgumentParser(prog="cdata-log")
    parser.add_argument('--version', action='version', version='%(prog)s ' + version)
    parser.add_argument('--list-failed', action='store_true', default=False,
                        help="list log of failed tests")

    args = parser.parse_args()

    filename = "Testing/Temporary/LastTest.log"

    if not os.path.exists(filename):
        print("ERROR:", filename, "does not exist")
        print("ERROR: cdata-log must be run from the same directory as ctest")
        return 1

    with open(filename) as fp:
        if args.list_failed:
            return listFailed(fp)
        else:
            return update(fp)

if __name__ == "__main__":
    sys.exit(main())
