<?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__) . '/../Database.php';
require_once dirname(__FILE__) . '/PropelTableDiff.php';

/**
 * Value object for storing Database object diffs
 * Heavily inspired by Doctrine2's Migrations
 * (see http://github.com/doctrine/dbal/tree/master/lib/Doctrine/DBAL/Schema/)
 *
 * @package    propel.generator.model.diff
 */
class PropelDatabaseDiff
{
    protected $addedTables = array();
    protected $removedTables = array();
    protected $modifiedTables = array();
    protected $renamedTables = array();

    /**
     * Setter for the addedTables property
     *
     * @param array $addedTables
     */
    public function setAddedTables($addedTables)
    {
        $this->addedTables = $addedTables;
    }

    /**
     * Add an added table
     *
     * @param string $tableName
     * @param Table  $addedTable
     */
    public function addAddedTable($tableName, Table $addedTable)
    {
        $this->addedTables[$tableName] = $addedTable;
    }

    /**
     * Remove an added table
     *
     * @param string $tableName
     */
    public function removeAddedTable($tableName)
    {
        unset($this->addedTables[$tableName]);
    }

    /**
     * Getter for the addedTables property
     *
     * @return array
     */
    public function getAddedTables()
    {
        return $this->addedTables;
    }

    /**
     * Get the number of added tables
     *
     * @return integer
     */
    public function countAddedTables()
    {
        return count($this->addedTables);
    }

    /**
     * Get an added table
     *
     * @param string $tableName
     *
     * @param Table
     */
    public function getAddedTable($tableName)
    {
        return $this->addedTables[$tableName];
    }

    /**
     * Setter for the removedTables property
     *
     * @param array $removedTables
     */
    public function setRemovedTables($removedTables)
    {
        $this->removedTables = $removedTables;
    }

    /**
     * Add a removed table
     *
     * @param string $tableName
     * @param Table  $removedTable
     */
    public function addRemovedTable($tableName, Table $removedTable)
    {
        $this->removedTables[$tableName] = $removedTable;
    }

    /**
     * Remove a removed table
     *
     * @param string $tableName
     */
    public function removeRemovedTable($tableName)
    {
        unset($this->removedTables[$tableName]);
    }

    /**
     * Getter for the removedTables property
     *
     * @return array
     */
    public function getRemovedTables()
    {
        return $this->removedTables;
    }

    /**
     * Get the number of removed tables
     *
     * @return integer
     */
    public function countRemovedTables()
    {
        return count($this->removedTables);
    }

    /**
     * Get a removed table
     *
     * @param string $tableName
     *
     * @param Table
     */
    public function getRemovedTable($tableName)
    {
        return $this->removedTables[$tableName];
    }

    /**
     * Setter for the modifiedTables property
     *
     * @param array $modifiedTables
     */
    public function setModifiedTables($modifiedTables)
    {
        $this->modifiedTables = $modifiedTables;
    }

    /**
     * Add a table difference
     *
     * @param string          $tableName
     * @param PropelTableDiff $modifiedTable
     */
    public function addModifiedTable($tableName, PropelTableDiff $modifiedTable)
    {
        $this->modifiedTables[$tableName] = $modifiedTable;
    }

    /**
     * Get the number of modified tables
     *
     * @return integer
     */
    public function countModifiedTables()
    {
        return count($this->modifiedTables);
    }

    /**
     * Getter for the modifiedTables property
     *
     * @return array
     */
    public function getModifiedTables()
    {
        return $this->modifiedTables;
    }

    /**
     * Setter for the renamedTables property
     *
     * @param array $renamedTables
     */
    public function setRenamedTables($renamedTables)
    {
        $this->renamedTables = $renamedTables;
    }

    /**
     * Add a renamed table
     *
     * @param string $fromName
     * @param string $toName
     */
    public function addRenamedTable($fromName, $toName)
    {
        $this->renamedTables[$fromName] = $toName;
    }

    /**
     * Getter for the renamedTables property
     *
     * @return array
     */
    public function getRenamedTables()
    {
        return $this->renamedTables;
    }

    /**
     * Get the number of renamed tables
     *
     * @return integer
     */
    public function countRenamedTables()
    {
        return count($this->renamedTables);
    }

    /**
     * Get the reverse diff for this diff
     *
     * @return PropelDatabaseDiff
     */
    public function getReverseDiff()
    {
        $diff = new self();
        $diff->setAddedTables($this->getRemovedTables());
        // idMethod is not set for tables build from reverse engineering
        // FIXME: this should be handled by reverse classes
        foreach ($diff->getAddedTables() as $name => $table) {
            if ($table->getIdMethod() == IDMethod::NO_ID_METHOD) {
                $table->setIdMethod(IDMethod::NATIVE);
            }
        }
        $diff->setRemovedTables($this->getAddedTables());
        $diff->setRenamedTables(array_flip($this->getRenamedTables()));
        $tableDiffs = array();
        foreach ($this->getModifiedTables() as $name => $tableDiff) {
            $tableDiffs[$name] = $tableDiff->getReverseDiff();
        }
        $diff->setModifiedTables($tableDiffs);

        return $diff;
    }

    /**
     * Get a description of the database modifications
     *
     * @return string
     */
    public function getDescription()
    {
        $changes = array();
        if ($count = $this->countAddedTables()) {
            $changes[] = sprintf('%d added tables', $count);
        }
        if ($count = $this->countRemovedTables()) {
            $changes[] = sprintf('%d removed tables', $count);
        }
        if ($count = $this->countModifiedTables()) {
            $changes[] = sprintf('%d modified tables', $count);
        }
        if ($count = $this->countRenamedTables()) {
            $changes[] = sprintf('%d renamed tables', $count);
        }

        return implode(', ', $changes);
    }

    public function __toString()
    {
        $ret = '';
        if ($addedTables = $this->getAddedTables()) {
            $ret .= "addedTables:\n";
            foreach ($addedTables as $tableName => $table) {
                $ret .= sprintf("  - %s\n", $tableName);
            }
        }
        if ($removedTables = $this->getRemovedTables()) {
            $ret .= "removedTables:\n";
            foreach ($removedTables as $tableName => $table) {
                $ret .= sprintf("  - %s\n", $tableName);
            }
        }
        if ($modifiedTables = $this->getModifiedTables()) {
            $ret .= "modifiedTables:\n";
            foreach ($modifiedTables as $tableName => $tableDiff) {
                $ret .= $tableDiff->__toString();
            }
        }
        if ($renamedTables = $this->getRenamedTables()) {
            $ret .= "renamedTables:\n";
            foreach ($renamedTables as $fromName => $toName) {
                $ret .= sprintf("  %s: %s\n", $fromName, $toName);
            }
        }

        return $ret;
    }
}
