#!/usr/bin/perl
# ---------------------------------------------------------------
# Copyright © 2024 Jason J.A. Stephenson <jason@sigio.com>
#
# This program 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.
#
# This program 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.
# ---------------------------------------------------------------

# This program is mostly undocumented. You will need to run it
# somewhere you have access to a PostgreSQL database with the latest
# Evergreen schema installed.

use strict;
use warnings;
use Getopt::Long qw(:config no_ignore_case no_auto_abbrev);
use DBI;
use DBD::Pg qw(:pg_types);

use XML::LibXML;

use constant QUERY => <<'ESQL';
select case when column_default is null and is_nullable = 'NO' then true
       else false end as is_required
from information_schema.columns
where table_schema = $1
and table_name = $2
and column_name = $3;
ESQL

# These should be modified for your environment or turned into CLI
# options.
use constant {
    INPATH => "$ENV{HOME}/src/Evergreen/Open-ILS/examples/fm_IDL.xml",
    OUTPATH => "$ENV{HOME}/src/Evergreen/Open-ILS/examples/fixed_IDL.xml"
};

# DBI options with defaults:
my $db_user = $ENV{PGUSER} || 'evergreen';
my $db_host = $ENV{PGHOST} || 'localhost';
my $db_database = $ENV{PGDATABASE} || 'evergreen';
my $db_password = $ENV{PGPASSWORD} || 'evergreen';
my $db_port = $ENV{PGPORT} || 5432;

# Use input file for output
my $same = 0;

GetOptions('user|U=s' => \$db_user,
           'host|h=s' => \$db_host,
           'database|d=s' => \$db_database,
           'password|P=s' => \$db_password,
           'port|p=i' => \$db_port,
           'same|s' => \$same)
    or die('Error in command line arguments');

my $dbh = DBI->connect("dbi:Pg:database=$db_database;host=$db_host;port=$db_port",
                       $db_user, $db_password,{AutoCommit=>1}) or die('No database connection');

my $sth = $dbh->prepare(QUERY);

my $idl = XML::LibXML->load_xml(location => INPATH);

foreach my $class ($idl->getElementsByTagName("class")) {
    if (! $class->getAttribute("oils_persist:virtual")
            && ! $class->getAttribute("oils_persist:readonly")) {
        my $tablename = $class->getAttribute("oils_persist:tablename");
        if ($tablename) {
            my ($schema, $table) = split(/\./, $tablename);
            foreach my $field ($class->getElementsByTagName("field")) {
                if (! $field->getAttribute("oils_persist:virtual")
                        && ! $field->getAttribute("oils_obj:required")) {
                    my $name = $field->getAttribute("name");
                    if (isRequired($schema, $table, $name)) {
                        $field->setAttributeNS("http://open-ils.org/spec/opensrf/IDL/objects/v1",
                                               "required", "true");
                    }
                }
            }
        }
    }
}

$dbh->disconnect();

$idl->toFile((($same) ? INPATH : OUTPATH), 0);
print $idl->toString(0);

sub isRequired {
    my $schema = shift;
    my $table = shift;
    my $field = shift;
    $sth->bind_param(1, $schema);
    $sth->bind_param(2, $table);
    $sth->bind_param(3, $field);
    if ($sth->execute()) {
        my $rows = $sth->fetchall_arrayref();
        return $rows->[0]->[0];
    }
    return 0;
}
