<?php
// This file is part of the Studyplan plugin for Moodle
//
// Moodle 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.
//
// Moodle 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 Moodle.  If not, see <https://www.gnu.org/licenses/>.
/**
 * Database upgrade script
 * @package    local_treestudyplan
 * @copyright  2023 P.M. Kuipers
 * @license    https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

/**
 * Hook to upgrade database upon plugin upgrade
 * @param mixed $oldversion Version of plugin database before upgrade
 * @return bool Upgrade success status
 *
 */
function xmldb_local_treestudyplan_upgrade($oldversion) {
    global $DB;
    $dbman = $DB->get_manager();

    if ($oldversion < 2020112900) {

        // Define table local_treestudyplan_gradeinc to be created.
        $table = new xmldb_table('local_treestudyplan_gradeinc');

        // Adding fields to table local_treestudyplan_gradeinc.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '18', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('grade_item_id', XMLDB_TYPE_INTEGER, '20', null, null, null, null);
        $table->add_field('include', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');

        // Adding keys to table local_treestudyplan_gradeinc.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
        $table->add_key('grade_item_id-id', XMLDB_KEY_FOREIGN, ['grade_item_id'], 'grade_item', ['id']);

        // Conditionally launch create table for local_treestudyplan_gradeinc.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2020112900, 'local', 'treestudyplan');
    }

    if ($oldversion < 2020120301) {

        // Define field studyitem_id to be added to local_treestudyplan_gradeinc.
        $table = new xmldb_table('local_treestudyplan_gradeinc');
        $field = new xmldb_field('studyitem_id', XMLDB_TYPE_INTEGER, '20', null, null, null, null, 'include');

        // Conditionally launch add field studyitem_id.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }

        $key = new xmldb_key('studyitem_id-id', XMLDB_KEY_FOREIGN, ['studyitem_id'], 'local_treestudyplan_item', ['id']);

        // Launch add key studyitem_id-id.
        $dbman->add_key($table, $key);

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2020120301, 'local', 'treestudyplan');
    }
    if ($oldversion < 2020120500) {

        // Define table local_treestudyplan_gradecfg to be created.
        $table = new xmldb_table('local_treestudyplan_gradecfg');

        // Adding fields to table local_treestudyplan_gradecfg.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('scale_id', XMLDB_TYPE_INTEGER, '20', null, null, null, null);
        $table->add_field('grade_points', XMLDB_TYPE_INTEGER, '20', null, null, null, null);
        $table->add_field('min_completed', XMLDB_TYPE_INTEGER, '20', null, null, null, null);
        $table->add_field('min_excellent', XMLDB_TYPE_INTEGER, '20', null, null, null, null);

        // Adding keys to table local_treestudyplan_gradecfg.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
        $table->add_key('scale_id-id', XMLDB_KEY_FOREIGN, ['scale_id'], 'scale', ['id']);

        // Conditionally launch create table for local_treestudyplan_gradecfg.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2020120500, 'local', 'treestudyplan');
    }

    if ($oldversion < 2021082300) {

        // Define field aggregation to be added to local_treestudyplan.
        $table = new xmldb_table('local_treestudyplan');
        $field = new xmldb_field('aggregation', XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, 'tristate', 'enddate');

        // Conditionally launch add field aggregation.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }

        // Define field aggregation_config to be added to local_treestudyplan.
        $field = new xmldb_field('aggregation_config', XMLDB_TYPE_TEXT, null, null, null, null, null, 'aggregation');

        // Conditionally launch add field aggregation_config.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2021082300, 'local', 'treestudyplan');
    }

    if ($oldversion < 2021082600) {

        // Define field min_progress to be dropped from local_treestudyplan_gradecfg.
        $table = new xmldb_table('local_treestudyplan_gradecfg');
        $field = new xmldb_field('min_excellent');

        // Conditionally launch drop field min_progress.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }

        $field = new xmldb_field('min_progress', XMLDB_TYPE_INTEGER, '20', null, null, null, null, 'min_completed');

        // Conditionally launch add field min_progress.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2021082600, 'local', 'treestudyplan');
    }

    if ($oldversion < 2021082601) {

        $table = new xmldb_table('local_treestudyplan_gradecfg');

        // Changing type of field min_completed on table local_treestudyplan_gradecfg to number.
        $field = new xmldb_field('min_completed', XMLDB_TYPE_NUMBER, '20', null, null, null, null, 'grade_points');
        // Launch change of type for field min_completed.
        $dbman->change_field_type($table, $field);

        // Changing type of field min_progress on table local_treestudyplan_gradecfg to number.
        $field = new xmldb_field('min_progress', XMLDB_TYPE_NUMBER, '20', null, null, null, null, 'min_completed');
        // Launch change of type for field min_progress.
        $dbman->change_field_type($table, $field);

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2021082601, 'local', 'treestudyplan');
    }

    if ($oldversion < 2021082700) {

        $table = new xmldb_table('local_treestudyplan_gradecfg');
        // Changing precision of field min_completed on table local_treestudyplan_gradecfg to (20, 2).
        $field = new xmldb_field('min_completed', XMLDB_TYPE_NUMBER, '20, 1', null, null, null, null, 'grade_points');
        // Launch change of precision for field min_completed.
        $dbman->change_field_precision($table, $field);

        // Changing precision of field min_progress on table local_treestudyplan_gradecfg to (20, 2).
        $field = new xmldb_field('min_progress', XMLDB_TYPE_NUMBER, '20, 1', null, null, null, null, 'min_completed');

        // Launch change of precision for field min_progress.
        $dbman->change_field_precision($table, $field);

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2021082700, 'local', 'treestudyplan');
    }

    if ($oldversion < 2021082701) {

        // Define field required to be added to local_treestudyplan_gradeinc.
        $table = new xmldb_table('local_treestudyplan_gradeinc');
        $field = new xmldb_field('required', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'studyitem_id');

        // Conditionally launch add field required.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2021082701, 'local', 'treestudyplan');
    }
    if ($oldversion < 2023051700) {

        // Define field context_id to be added to local_treestudyplan.
        $table = new xmldb_table('local_treestudyplan');
        $field = new xmldb_field('context_id', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'aggregation_config');

        // Conditionally launch add field context_id.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2023051700, 'local', 'treestudyplan');
    }

    if ($oldversion < 2023062603) {

        // Define field csync_flag to be added to local_treestudyplan.
        $table = new xmldb_table('local_treestudyplan');
        $field = new xmldb_field('csync_flag', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'context_id');

        // Conditionally launch add field csync_flag.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2023062603, 'local', 'treestudyplan');
    }
    if ($oldversion < 2023063002) {

        // Define table local_treestudyplan_teachers to be created.
        $table = new xmldb_table('local_treestudyplan_teachers');

        // Adding fields to table local_treestudyplan_teachers.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '20', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('teacher_id', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('studyplan_id', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('update_time', XMLDB_TYPE_INTEGER, '10', null, null, null, null);

        // Adding keys to table local_treestudyplan_teachers.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);

        // Conditionally launch create table for local_treestudyplan_teachers.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2023063002, 'local', 'treestudyplan');
    }
    if ($oldversion < 2023071900) {

        /******
         * Prepare the studyline table to hold links to pages insted of study plans
         * And drop the foreign key constraint for the studyplan_id-id relation
         */
        // Define field page_id to be added to local_treestudyplan_line.
        $table = new xmldb_table('local_treestudyplan_line');
        $field = new xmldb_field('page_id', XMLDB_TYPE_INTEGER, '20', null, null, null, null, 'studyplan_id');

        // Conditionally launch add field page_id.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }

        // Define key studyplan_id-id (foreign) to be dropped form local_treestudyplan_line.
        $table = new xmldb_table('local_treestudyplan_line');
        $key = new xmldb_key('studyplan_id-id', XMLDB_KEY_FOREIGN, ['studyplan_id'], 'local_treestudyplan', ['id']);

        // Launch drop key studyplan_id-id.
        $dbman->drop_key($table, $key);

        /******
         * Create the page table and copy data from treestudyplan there
         * Also re-link the studylines to the newly created page instead of the studyplan
         */
        // Define table local_treestudyplan_page to be created.
        $table = new xmldb_table('local_treestudyplan_page');

        // Adding fields to table local_treestudyplan_page.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '20', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('studyplan_id', XMLDB_TYPE_INTEGER, '20', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('periods', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('fullname', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('shortname', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('startdate', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('enddate', XMLDB_TYPE_TEXT, null, null, null, null, null);

        // Adding keys to table local_treestudyplan_page.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);

        // Conditionally launch create table for local_treestudyplan_page.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);

            // Create a page 0 with it's data copied.
            $plans = $DB->get_recordset("local_treestudyplan");
            foreach ($plans as $p) {
                $o = [  "studyplan_id" => $p->id,
                        "periods" => $p->slots,
                        "fullname" => $p->name,
                        "shortname" => $p->shortname,
                        "description" => $p->description,
                        "startdate" => $p->startdate,
                        "enddate" => $p->enddate,
                ];
                $pageid = $DB->insert_record("local_treestudyplan_page", $o);

                // Now find all studyline references to the studyplan .
                // And update their record to reference the page instead of the plan.
                $lines = $DB->get_recordset("local_treestudyplan_line", ["studyplan_id" => $p->id]);
                foreach ($lines as $l) {
                    $lo = [
                        "id" => $l->id,
                        "page_id" => $pageid,
                    ];
                    $DB->update_record("local_treestudyplan_line", $lo);
                }
                $lines->close();
            }
            $plans->close();
        }

        /*******
         * Finalize studyline table to drop studyplan_id field and have page id be a non-nullable and foreign key
         */

        // Changing nullability of field page_id on table local_treestudyplan_line to not null.
        $table = new xmldb_table('local_treestudyplan_line');
        $field = new xmldb_field('page_id', XMLDB_TYPE_INTEGER, '20', null, XMLDB_NOTNULL, null, null, 'studyplan_id');

        // Launch change of nullability for field page_id.
        $dbman->change_field_notnull($table, $field);

        // Define field studyplan_id to be dropped from local_treestudyplan_line.
        $table = new xmldb_table('local_treestudyplan_line');
        $field = new xmldb_field('studyplan_id');

        // Conditionally launch drop field studyplan_id.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }

        // Define key page_id-id (foreign) to be added to local_treestudyplan_line.
        $table = new xmldb_table('local_treestudyplan_line');
        $key = new xmldb_key('page_id-id', XMLDB_KEY_FOREIGN, ['page_id'], 'local_treestudyplan_page', ['id']);

        // Launch add key page_id-id.
        $dbman->add_key($table, $key);

        /*******
         *  Create Period table and make a period record for all studyplan periods
         */

        // Define table local_treestudyplan_period to be created.
        $table = new xmldb_table('local_treestudyplan_period');

        // Adding fields to table local_treestudyplan_period.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '20', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('page_id', XMLDB_TYPE_INTEGER, '20', null, null, null, null);
        $table->add_field('period', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('startdate', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('enddate', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('shortname', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('fullname', XMLDB_TYPE_TEXT, null, null, null, null, null);

        // Adding keys to table local_treestudyplan_period.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
        $table->add_key('page_id-id', XMLDB_KEY_FOREIGN, ['page_id'], 'local_treestudyplan_page', ['id']);

        // Conditionally launch create table for local_treestudyplan_period.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);

            // Create a period page for all slots in the study.
            $recordset = $DB->get_recordset("local_treestudyplan_page");
            foreach ($recordset as $r) {

                // Make a best guess for the periods based on the specified period for the plan and the .
                $pcount = $r->periods;
                $ystart = strtotime($r->startdate) + 0;
                $yend = strtotime($r->enddate) + 0;
                if ($yend < $ystart) {
                    // If no end time is given, assume a year duration for period calculations.
                    $ydelta = (365 * 24 * 60 * 60) / $pcount;
                } else {
                    $ydelta = $yend - $ystart;
                }
                $ptime = $ydelta / $pcount;

                for ($i = 0; $i < $pcount; $i++) {
                    $pnum = $i + 1;
                    $pstart = $ystart + ($i * $ptime);
                    $pend = ($pstart + $ptime) - (24 * 60 * 60); // Minus one day.

                    $o = [  "page_id" => $r->id,
                            "period" => $pnum,
                            "fullname" => "Period {$pnum}",
                            "shortname" => "P{$pnum}",
                            "startdate" => date("Y-m-d", $pstart),
                            "enddate" => date("Y-m-d", $pend)
                    ];
                    $DB->insert_record("local_treestudyplan_period", $o);
                }
            }
            $recordset->close();
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2023071900, 'local', 'treestudyplan');
    }
    if ($oldversion < 2023072000) {

        // Define field slots to be dropped from local_treestudyplan.
        $table = new xmldb_table('local_treestudyplan');
        $field = new xmldb_field('slots');

        // Conditionally launch drop field slots.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }

        // Define field startdate to be dropped from local_treestudyplan.
        $table = new xmldb_table('local_treestudyplan');
        $field = new xmldb_field('startdate');

        // Conditionally launch drop field startdate.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }

        // Define field enddate to be dropped from local_treestudyplan.
        $table = new xmldb_table('local_treestudyplan');
        $field = new xmldb_field('enddate');

        // Conditionally launch drop field enddate.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2023072000, 'local', 'treestudyplan');
    }

    if ($oldversion < 2023080300) {

        // Define field span to be added to local_treestudyplan_item.
        $table = new xmldb_table('local_treestudyplan_item');
        $field = new xmldb_field('span', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '1', 'continuation_id');

        // Conditionally launch add field span.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2023080300, 'local', 'treestudyplan');
    }

    if ($oldversion < 2023080900) {

        // Rename field date on table local_treestudyplan_invit to idate.
        $table = new xmldb_table('local_treestudyplan_invit');
        $field = new xmldb_field('date', XMLDB_TYPE_INTEGER, '20', null, null, null, null, 'invitekey');

        // Launch rename field idate.
        $dbman->rename_field($table, $field, 'idate');

        // Define field idnumber to be added to local_treestudyplan.
        $table = new xmldb_table('local_treestudyplan');
        $field = new xmldb_field('idnumber', XMLDB_TYPE_TEXT, null, null, null, null, null, 'description');

        // Conditionally launch add field idnumber.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2023080900, 'local', 'treestudyplan');
    }

    if ($oldversion < 2023082100) {

        // Up to version 20230821 the studyplan_id field still existed in the install.xml file.
        // Below code remedies that - even though this is a repeat of part of an earlier upgrade.

        // Define field studyplan_id to be dropped from local_treestudyplan_line.
        $table = new xmldb_table('local_treestudyplan_line');
        $field = new xmldb_field('studyplan_id');

        // Conditionally launch drop field studyplan_id.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2023082100, 'local', 'treestudyplan');
    }

    if ($oldversion < 2023101900) {

        // Define field descriptionformat to be added to local_treestudyplan.
        $table = new xmldb_table('local_treestudyplan');
        $field = new xmldb_field('descriptionformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '1', 'description');

        // Conditionally launch add field descriptionformat.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2023101900, 'local', 'treestudyplan');
    }
    if ($oldversion < 2023102200) {

        // Define field descriptionformat to be added to local_treestudyplan.
        $table = new xmldb_table('local_treestudyplan_page');
        $field = new xmldb_field('descriptionformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '1', 'description');

        // Conditionally launch add field descriptionformat.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }

        // Treestudyplan savepoint reached.
        upgrade_plugin_savepoint(true, 2023102200, 'local', 'treestudyplan');
    }
    return true;
}