<?php

/**
 * This file is part of the Propel package.
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @license    MIT License
 */

require_once dirname(__FILE__) . '/BasePropelMigrationTask.php';
require_once dirname(__FILE__) . '/../util/PropelMigrationManager.php';

/**
 * This Task executes the next migration up
 *
 * @author     Francois Zaninotto
 * @package    propel.generator.task
 */
class PropelMigrationUpTask extends BasePropelMigrationTask
{
    /**
     * Main method builds all the targets for a typical propel project.
     */
    public function main()
    {
        $manager = new PropelMigrationManager();
        $manager->setConnections($this->getGeneratorConfig()->getBuildConnections());
        $manager->setMigrationTable($this->getMigrationTable());
        $manager->setMigrationDir($this->getOutputDirectory());

        if (!$nextMigrationTimestamp = $manager->getFirstUpMigrationTimestamp()) {
            $this->log('All migrations were already executed - nothing to migrate.');

            return false;
        }
        $this->log(sprintf(
            'Executing migration %s up',
            $manager->getMigrationClassName($nextMigrationTimestamp)
        ));

        $migration = $manager->getMigrationObject($nextMigrationTimestamp);
        if (false === $migration->preUp($manager)) {
            $this->log('preUp() returned false. Aborting migration.', Project::MSG_ERR);

            return false;
        }

        foreach ($migration->getUpSQL() as $datasource => $sql) {
            $connection = $manager->getConnection($datasource);
            $this->log(sprintf(
                'Connecting to database "%s" using DSN "%s"',
                $datasource,
                $connection['dsn']
            ), Project::MSG_VERBOSE);
            $pdo = $manager->getPdoConnection($datasource);
            $res = 0;
            $statements = PropelSQLParser::parseString($sql);
            foreach ($statements as $statement) {
                try {
                    $this->log(sprintf('Executing statement "%s"', $statement), Project::MSG_VERBOSE);
                    $stmt = $pdo->prepare($statement);
                    $stmt->execute();
                    $res++;
                } catch (PDOException $e) {
                    $this->log(sprintf('Failed to execute SQL "%s". Aborting migration.', $statement), Project::MSG_ERR);

                    return false;
                    // continue
                }
            }
            if (!$res) {
                $this->log('No statement was executed. The version was not updated.');
                $this->log(sprintf(
                    'Please review the code in "%s"',
                    $manager->getMigrationDir() . DIRECTORY_SEPARATOR . $manager->getMigrationClassName($nextMigrationTimestamp)
                ));
                $this->log('Migration aborted', Project::MSG_ERR);

                return false;
            }
            $this->log(sprintf(
                '%d of %d SQL statements executed successfully on datasource "%s"',
                $res,
                count($statements),
                $datasource
            ));
            $manager->updateLatestMigrationTimestamp($datasource, $nextMigrationTimestamp);
            $this->log(sprintf(
                'Updated latest migration date to %d for datasource "%s"',
                $nextMigrationTimestamp,
                $datasource
            ), Project::MSG_VERBOSE);
        }

        $migration->postUp($manager);

        if ($timestamps = $manager->getValidMigrationTimestamps()) {
            $this->log(sprintf(
                'Migration complete. %d migrations left to execute.',
                count($timestamps)
            ));
        } else {
            $this->log('Migration complete. No further migration to execute.');
        }
    }
}
