<?php
/**
* Rights installer component class file.
*
* @author Christoffer Niska <cniska@live.com>
* @copyright Copyright &copy; 2010 Christoffer Niska
* @since 0.9.3
*/
class RInstaller extends CApplicationComponent
{
    const ERROR_NONE=0;
    const ERROR_QUERY_FAILED=1;

	/**
	* @property array the roles assigned to users implicitly.
	*/
	public $defaultRoles;
	/**
	* @property string the name of the superuser role.
	*/
	public $superuserName;
	/**
	* @property string the name of the authenticated role.
	*/
	public $authenticatedName;
	/**
	* @property string the name of the guest role.
	*/
	public $guestName;
    /**
     * @property RAuthManager the authorization manager.
     */
	private $_authManager;
    /**
     * @property boolean whether Rights is installed.
     */
	private $_installed;

	/**
	* @property CDbConnection
	*/
	public $db;

	/**
	* Initializes the installer.
	* @throws CException if the authorization manager or the web user
	* is not configured to use the correct class.
	*/
	public function init()
	{
		parent::init();

		// Make sure the application is configured
		// to use a valid authorization manager.
		$authManager = Yii::app()->getAuthManager();
		if( ($authManager instanceof RDbAuthManager)===false )
			throw new CException(Rights::t('install', 'Application authorization manager must extend the RDbAuthManager class.'));

		// Make sure the application is configured
		// to use a valid web user.
		$user = Yii::app()->getUser();
		if( ($user instanceof RWebUser)===false )
			throw new CException(Rights::t('install', 'Application web user must extend the RWebUser class.'));

		$this->_authManager = $authManager;
		$this->db = $this->_authManager->db;
	}

	/**
	* Runs the installer.
	* @param boolean whether to drop tables if they exists.
	* @return boolean whether the installer ran successfully.
	*/
	public function run()
	{
        // Get the table names.
        $itemTable = $this->_authManager->itemTable;
        $itemChildTable = $this->_authManager->itemChildTable;
        $assignmentTable = $this->_authManager->assignmentTable;
        $rightsTable = $this->_authManager->rightsTable;

        // Fetch the schema.
        $schema = file_get_contents(dirname(__FILE__).'/../data/schema.sql');

        // Correct the table names.
        $schema = strtr($schema, array(
            'AuthItem'=>$itemTable,
            'AuthItemChild'=>$itemChildTable,
            'AuthAssignment'=>$assignmentTable,
            'Rights'=>$rightsTable,
        ));

        // Convert the schema into an array of sql queries.
        $schema = preg_split("/;\s*/", trim($schema, ';'));

        // Start transaction
        $txn = $this->db->beginTransaction();

        try
        {
            // Execute each query in the schema.
            foreach( $schema as $sql )
            {
                $command = $this->db->createCommand($sql);
                $command->execute();
            }

            // Insert the necessary roles.
            $roles = $this->getUniqueRoles();
            foreach( $roles as $roleName )
            {
                $sql = "INSERT INTO {$itemTable} (name, type, data)
                    VALUES (:name, :type, :data)";
                $command = $this->db->createCommand($sql);
                $command->bindValue(':name', $roleName);
                $command->bindValue(':type', CAuthItem::TYPE_ROLE);
                $command->bindValue(':data', 'N;');
                $command->execute();
            }

            // Assign the logged in user the superusers role.
            $sql = "INSERT INTO {$assignmentTable} (itemname, userid, data)
                VALUES (:itemname, :userid, :data)";
            $command = $this->db->createCommand($sql);
            $command->bindValue(':itemname', $this->superuserName);
            $command->bindValue(':userid', Yii::app()->getUser()->id);
            $command->bindValue(':data', 'N;');
            $command->execute();

            // All commands executed successfully, commit.
            $txn->commit();
            return self::ERROR_NONE;
        }
        catch( CDbException $e )
        {
            // Something went wrong, rollback.
            $txn->rollback();

            return self::ERROR_QUERY_FAILED;
        }
	}

	/**
	* Returns a list of unique roles names.
	* @return array the list of roles.
	*/
	private function getUniqueRoles()
	{
		$roles = CMap::mergeArray($this->defaultRoles, array(
            $this->superuserName,
            $this->authenticatedName,
            $this->guestName,
        ));
		return array_unique($roles);
	}

	/**
	* @return boolean whether Rights is installed.
	*/
	public function getInstalled()
	{
		if( $this->_installed!==null )
		{
			return $this->_installed;
		}
		else
		{
            $schema = array(
                "SELECT COUNT(*) FROM {$this->_authManager->itemTable}",
                "SELECT COUNT(*) FROM {$this->_authManager->itemChildTable}",
                "SELECT COUNT(*) FROM {$this->_authManager->assignmentTable}",
                "SELECT COUNT(*) FROM {$this->_authManager->rightsTable}",
            );

			try
			{
                foreach( $schema as $sql )
                {
                    $command = $this->db->createCommand($sql);
                    $command->queryScalar();
                }

				$installed = true;
			}
			catch( CDbException $e )
			{
				$installed = false;
			}

			return $this->_installed = $installed;
		}
	}
}
