"use strict";
// -*- mode: typescript; indent-tabs-mode: nil; js-basic-offset: 4 -*-
//
// This file is part of Genie
//
// Copyright 2020 The Board of Trustees of the Leland Stanford Junior University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Silei Xu <silei@cs.stanford.edu>
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.execute = exports.initArgparse = void 0;
const assert_1 = __importDefault(require("assert"));
const fs = __importStar(require("fs"));
const util = __importStar(require("util"));
const ThingTalk = __importStar(require("thingtalk"));
async function loadClassDef(thingpedia) {
    const library = ThingTalk.Syntax.parse(await util.promisify(fs.readFile)(thingpedia, { encoding: 'utf8' }));
    assert_1.default(library instanceof ThingTalk.Ast.Library && library.classes.length === 1);
    return library.classes[0];
}
function includesAnnotation(canonicalList, canonical) {
    if (canonical.endsWith(' #'))
        canonical = canonical.replace(' #', '');
    for (let c of canonicalList) {
        if (c.endsWith(' #'))
            c = c.replace(' #', '');
        if (c === canonical)
            return true;
    }
    return false;
}
function diffAnnotation(a1, a2) {
    const diff = {};
    for (const posType in a1) {
        if (posType === 'default')
            continue;
        if (posType in a2) {
            const missingAnnotations = [];
            for (const canonical of a1[posType]) {
                if (!includesAnnotation(a2[posType], canonical))
                    missingAnnotations.push(canonical);
            }
            if (missingAnnotations.length > 0)
                diff[posType] = missingAnnotations;
        }
        else {
            diff[posType] = a1[posType];
        }
    }
    return diff;
}
function diffQuery(q1, q2) {
    const diff = {};
    for (const arg1 of q1.iterateArguments()) {
        const arg2 = q2.getArgument(arg1.name);
        const d = diffAnnotation(arg1.nl_annotations.canonical, arg2.nl_annotations.canonical);
        if (Object.keys(d).length > 0)
            diff[arg1.name] = d;
    }
    return diff;
}
function initArgparse(subparsers) {
    const parser = subparsers.add_parser('autoqa-annotation-diff', {
        add_help: true,
        description: "Find the canonical annotation difference between two classes; return annotations existed " +
            "in the first one that is not available in the second."
    });
    parser.add_argument('--thingpedia1', {
        required: true,
        help: 'Path to the first ThingTalk file containing class definitions.'
    });
    parser.add_argument('--thingpedia2', {
        required: true,
        help: 'Path to the second ThingTalk file containing class definitions.'
    });
    parser.add_argument('--queries', {
        required: false,
        help: 'Queries to include, split by comma with no space; run on all functions if absent'
    });
}
exports.initArgparse = initArgparse;
async function execute(args) {
    const classDef1 = await loadClassDef(args.thingpedia1);
    const classDef2 = await loadClassDef(args.thingpedia2);
    const queries = args.queries ? args.queries.split(',') : Object.keys(classDef1.queries);
    const diff = {};
    for (const qname of queries) {
        const q1 = classDef1.queries[qname];
        const q2 = classDef2.queries[qname];
        diff[qname] = diffQuery(q1, q2);
    }
    console.log(JSON.stringify(diff, null, 2));
}
exports.execute = execute;
//# sourceMappingURL=annotation-diff.js.map