/*

Copyright © 2023-26 Sean Holden. All rights reserved.

*/
/*

This file is part of Connect++.

Connect++ is free software: you can redistribute it and/or modify it 
under the terms of the GNU General Public License as published by the 
Free Software Foundation, either version 3 of the License, or (at your 
option) any later version.

Connect++ is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
more details.

You should have received a copy of the GNU General Public License along 
with Connect++. If not, see <https://www.gnu.org/licenses/>. 

*/

#include "TPTPRecords.hpp"

//--------------------------------------------------------------
ostream& operator<<(ostream& _out, const TPTPRecordType& _type) {
    switch(_type) {
        case TPTPRecordType::Empty:
            _out << "Empty";
            break;
        case TPTPRecordType::FileCNF:
            _out << "FileCNF";
            break;
        case TPTPRecordType::FileFOF:
            _out << "FileFOF";
            break;
        case TPTPRecordType::Introduced:
            _out << "Introduced";
            break;
        case TPTPRecordType::Inference:
            _out << "Inference";
            break;
        case TPTPRecordType::Skolem:
            _out << "Skolem";
            break;
        case TPTPRecordType::Theory:
            _out << "Theory";
            break;
        case TPTPRecordType::TFClause:
            _out << "TFClause";
            break;
        default:
            break;
    }
    return _out;
}
//--------------------------------------------------------------
ostream& operator<<(ostream& _out, const TPTPRecord& _r) {
    _out << "TPTPRecord: type = " << _r.type << endl;
    _out << "Name = " << _r.name << ", Role = " << _r.role
         << ", i1 = " << to_string(_r.index_1) << ", i2 = " << to_string(_r.index_2) << endl;
    _out << "Full name: " << _r.make_full_name();
    return _out;
}
//--------------------------------------------------------------
string TPTPRecord::to_tptp_string() const {
    string s;
    if (params::generate_tptp_proof) {
    switch(type) {
            case TPTPRecordType::Empty:

                break;
            case TPTPRecordType::FileCNF:
                s += "cnf(";
                s += name;
                s += ", ";
                s += role;
                s += ",\n    ";
                s += f;
                s += ",\n    file('"; 
                s += path.string();
                s += "', ";
                s += info;
                s += ") ).";
                break;
            case TPTPRecordType::FileFOF:
                s += "fof(";
                s += name;
                s += ", ";
                s += role;
                s += ",\n    ";
                s += f;
                s += ",\n    file('"; 
                s += path.string();
                s += "', ";
                s += info;
                s += ") ).";
                break;
            case TPTPRecordType::Introduced:
             

                break;
            case TPTPRecordType::Skolem:
                s += "fof(";
                s += make_full_name();
                 s += ", ";
                 s += role;
                 s += ",\n    ";
                 s += f;
                 s += ",\n    inference(";
                 s += info;
                 s += ",[";
                 s += source[0];
                 s += "]) ).";
                break;
            case TPTPRecordType::Inference:
                if (has_formula) {
                    s += "fof(";
                }
                else {
                    s += "cnf(";
                }
                s += make_full_name();
                s += ", ";
                s += role;
                s += ",\n    ";
                s += f;
                s += ",\n    inference(";
                s += info;
                s += ",[";
                s += source[0];
                s += "]) ).";
                break;
            case TPTPRecordType::Theory:
                 s += "cnf(";
                 s += make_full_name();
                 s += ", ";
                 s += role;
                 s += ",\n    ";
                 s += f;
                 s += ",\n    theory(";
                 s += name;
                 s += ",[";
                 s += info;
                 s += "]) ).";
                break;
            case TPTPRecordType::TFClause:
                s += "cnf(";
                s += name;
                s += ", ";
                s += role;
                s += ",\n    ";
                s += f;
                s += ",\n    inference(";
                if (f == string("$true")) 
                    s += "clause_is_true";
                else 
                    s += "clause_is_false";
                s += ",[status(thm)],[";
                s += source[0];
                s += "]) ).";
            default:
                break;
        }
    }
    return s;
}
//--------------------------------------------------------------
//--------------------------------------------------------------
//--------------------------------------------------------------
void TPTPRecords::mark_used_records(const string& _name) {
    size_t i = find_record_by_name(_name);
    if (used_records[i]) 
        return;
    used_records[i] = true;
    string current_source = records[i].source[0];
    // The initial file records have a name and source that are 
    // the same.
    if (current_source != _name) 
        mark_used_records(current_source);
}
//--------------------------------------------------------------
void TPTPRecords::mark_all_used_records(const unordered_set<string>& _names) {
    for (const string& name : _names) {
        mark_used_records(name);
    }
}
//--------------------------------------------------------------
size_t TPTPRecords::find_record_by_name(const string& _name) const {
    for (size_t i = 0; i < records.size(); i++) {
        string full_name = records[i].make_full_name();
        if (full_name == _name) 
            return i;
    }
    cerr << "You're looking for a record that doesn't exist." << endl;
    cerr << "Searching for: " << _name << endl;
    cerr << "Names available:" << endl;
    for (size_t i = 0; i < records.size(); i++) {
        string full_name = records[i].make_full_name();
        cerr << full_name << endl;
    }
    exit(EXIT_FAILURE);
    return 0;
}
//--------------------------------------------------------------
string TPTPRecords::find_clause_name(size_t _i) const {
    for (const TPTPRecord& r : records) {
        if (r.type == TPTPRecordType::FileCNF && r.clause_file_number == _i) {
            return r.name;
        }
    }
    return "";
}
//--------------------------------------------------------------
string TPTPRecords::find_fof_name(size_t _i) const {
    for (const TPTPRecord& r : records) {
        if (r.type == TPTPRecordType::FileFOF && r.fof_file_number == _i) {
            return r.name;
        }
    }
    return "";
}
//--------------------------------------------------------------
string TPTPRecords::to_tptp_string(const unordered_set<string>& _names) {
    string s;
    if (params::generate_tptp_proof) {
        used_records = vector<bool>(records.size(), false);
        mark_all_used_records(_names);
        size_t i = 0;
        for (const TPTPRecord& r : records) {
            if (params::all_tptp_records || used_records[i]) {
                s += r.to_tptp_string();
                s += "\n\n";
            }
            i++;
        }
    }
    return s;
}
//--------------------------------------------------------------
string TPTPRecords::to_tptp_string_all() {
    bool saved = params::generate_tptp_proof;
    params::generate_tptp_proof = true;
    string s;
    for (const TPTPRecord& r : records) {
        s += r.to_tptp_string();
        s += "\n\n";    
    }
    params::generate_tptp_proof = saved;
    return s;
}
//--------------------------------------------------------------
void TPTPRecords::add_cnf_file_record(const string& _name, 
                                      const string& _role, 
                                      const string& _f,
                                      const fs::path& _path) {
    TPTPRecord r(TPTPRecordType::FileCNF, ++current_index_1, _name, _role, _f, _path);
    records.push_back(r);
}
//--------------------------------------------------------------
void TPTPRecords::add_fof_file_record(const string& _name, 
                                      const string& _role, 
                                      const string& _f,
                                      const fs::path& _path) {
    TPTPRecord r(TPTPRecordType::FileFOF, ++current_index_2, _name, _role, _f, _path);
    records.push_back(r);
}
//--------------------------------------------------------------
void TPTPRecords::add_theory_record(const string& _name,
                                    const string& _info, 
                                    const string& _f) {
    TPTPRecord r(_name, ++current_index_1, _info, _f);
    records.push_back(r);
}
//--------------------------------------------------------------
void TPTPRecords::add_fof_inference_record(const string& _info, 
                                    const string& _f) {
    TPTPRecord r(current_name, 
                 current_index_1, 
                 ++current_index_2,
                 current_role, 
                 _info, 
                 true, 
                 _f,
                 current_source);
    if (_f != last_f) {
      records.push_back(r);
      current_source = r.make_full_name();
      last_f = _f;
    }
    else {
        --current_index_2;
    }
}
//--------------------------------------------------------------
void TPTPRecords::add_skolemization_record(const string& _f,
                    const string& _v,
                    const string& _sk_t,
                    const string& _sk_n) {
    string skolem_info("skolemize,[status(esa),new_symbols(skolem,[");
    skolem_info += _sk_n;
    skolem_info += "]),skolemize(";
    skolem_info += _v;
    skolem_info += ",";
    skolem_info += _sk_t;
    skolem_info += ")]";

    TPTPRecord r(current_name, 
                 current_index_1, 
                 ++current_index_2,
                 current_role, 
                 _f,
                 current_source, 
                 skolem_info);

    records.push_back(r);
    current_source = r.make_full_name();
    last_f = _f;
}
//--------------------------------------------------------------
void TPTPRecords::add_herbrandization_record(const string& _f,
                    const string& _v,
                    const string& _sk_t,
                    const string& _sk_n) {
    string skolem_info("herbrandize,[status(tap),new_symbols(herbrand,[");
    skolem_info += _sk_n;
    skolem_info += "]),herbrandize(";
    skolem_info += _v;
    skolem_info += ",";
    skolem_info += _sk_t;
    skolem_info += ")]";

    TPTPRecord r(current_name, 
                 current_index_1, 
                 ++current_index_2,
                 current_role, 
                 _f,
                 current_source, 
                 skolem_info);

    records.push_back(r);
    current_source = r.make_full_name();
    last_f = _f;
}
//--------------------------------------------------------------
void TPTPRecords::add_definitional_record(const string& _f,
                    const string& _symbols) {
    string def_info("definitional_conversion,[status(ctp)");
    if (_symbols.size() > 0) {
        def_info += ",new_symbols(definitional,";
        def_info += _symbols;
        def_info += ")";
    }
    def_info += "]";
    
    TPTPRecord r(current_name, 
                 current_index_1, 
                 ++current_index_2,
                 current_role, 
                 _f,
                 current_source, 
                 def_info);

    records.push_back(r);
    current_source = r.make_full_name();
    last_f = _f;
}
//--------------------------------------------------------------
string TPTPRecords::add_clause_record(const Clause& _c, const string& _role) {
    TPTPRecord r(current_name,
                 current_index_1, 
                 ++current_index_2,
                 _role,
                 "clausify,[status(thm)]",
                 false,
                 _c.to_tptp_string(),
                 current_source);

    records.push_back(r);
    return r.make_full_name();
}
//--------------------------------------------------------------
string TPTPRecords::add_clause_record(const Clause& _c, const string& _role, const string& _source) {
    string new_name = _source;
    new_name += "_simplified";

    TPTPRecord r(new_name,
                 0, 
                 0,
                 _role,
                 "simplify_clause,[status(thm)]",
                 false,
                 _c.to_tptp_string(),
                 _source);

    if (_role != string("negated_conjecture")) 
        r.role = "plain";
    records.push_back(r);
    return new_name;
}
//--------------------------------------------------------------
void TPTPRecords::add_tf_clause_record(const string& _source, const string& _role, const string& _f) {
    string name(_source);
    if (_f == string("$true"))
        name += "_true";
    else 
        name += "-_alse";
    TPTPRecord r(name, _source, _f);
    r.role = "negated_conjecture";
    if (_role != string("negated_conjecture")) {
        r.role = "plain";
    }
    records.push_back(r);
}
//--------------------------------------------------------------
ostream& operator<<(ostream& _out, const TPTPRecords& _rs) {
    for (const TPTPRecord& r : _rs.records) {
        _out << r << endl;
    }
    return _out;
}