<?php

class ModelTest extends CDbTestCase
{

    public $model;

    public function __construct()
    {
        parent::__construct();
        $className = str_replace('Test', '', get_class($this));
        $this->model = new $className(null);
    }

    public function testAttributeLabels()
    {
        $attributes = array_keys($this->model->attributes);
        $modelName = get_class($this);

        foreach ($attributes as $attribute) {
            $this->assertArrayHasKey(
                $attribute,
                $this->model->attributeLabels(),
                "No attribute label found for '$attribute', in the model '$modelName''"
            );
        }
    }

    public function checkRequiredRules($attribute, $scenario = null)
    {
        // supports attribute as string and as attribute array as well
        if (is_array($attribute)) {
            foreach ($attribute as $singleAttribute) {
                $this->checkRequiredRules($singleAttribute, $scenario);
            }
            return;
        }

        $oldScenario = $this->model->scenario;

        if ($scenario != null) {
            $this->model->scenario = $scenario;
        }

        $this->model->$attribute = '';
        $this->assertFalse($this->model->validate(array($attribute)));

        $this->model->scenario = $oldScenario;
    }

    public function checkNumericalRules($attribute, $scenario, $params = array())
    {
        if (is_array($attribute)) {
            foreach ($attribute as $singleAttribute) {
                $this->checkNumericalRules($singleAttribute, $scenario);
            }
            return;
        }

        $oldScenario = $this->model->scenario;

        if ($scenario != null) {
            $this->model->scenario = $scenario;
        }

        foreach ($params as $param => $paramValue) {

            if ($param == "min") {
                $this->model->$attribute = ($paramValue - 1);
                $this->assertFalse($this->model->validate(array($attribute)));
            }

            if ($params == 'max') {
                $this->model->$attribute = ($paramValue + 1);
                $this->assertFalse($this->model->validate(array($attribute)));
            }
        }

        $this->model->$attribute = "abc";
        $this->assertFalse($this->model->validate(array($attribute)));
        $this->model->scenario = $oldScenario;
    }

    public function testActiveRecord()
    {
        $className = get_class($this->model);

        $this->assertInstanceOf('PhonalisaRecord', $this->model);

        // new model
        $this->assertTrue($this->model->isNewRecord, 'isNewRecord property of new record is FALSE');
        $this->assertTrue($this->model->isNewRecord(), 'isNewRecord() function on new record returns FALSE');


        // new model save
        $this->setTestRecordValues();


        $this->beforeValidateTestRecord();
        $this->assertTrue($this->model->validate(), 'Model validation fails');
        $this->afterValidateTestRecord();

        $this->beforeSaveTestRecord();
        $this->assertTrue($this->model->save(false), 'Can not save new model, without validation');
        $this->afterSaveTestRecord();

        $this->assertTrue($this->model->isNewRecord, 'isNewRecord property returns FALSE after save()');
        $this->assertFalse($this->model->isNewRecord(), 'isNewRecord() function returns TRUE after save()');


        // model after load
        $this->model = $className::model()->findByPk($this->model->id);

        $this->assertSame(
            array_diff($this->getAttributeValues(), $this->model->attributes),
            array_diff($this->model->attributes, $this->getAttributeValues())
        );

        $this->assertFalse($this->model->isNewRecord, 'isNewRecord property returns TRUE after find()');
        $this->assertFalse($this->model->isNewRecord(), 'isNewRecord() function returns TRUE after find()');


        // update model
        $this->updateTestRecordValues();

        $this->beforeValidateTestRecord();
        $this->assertTrue($this->model->validate(), 'Model validation after update fails');
        $this->afterValidateTestRecord();

        $this->beforeSaveTestRecord();
        $this->assertTrue($this->model->save(false), 'Can not update model, without validation');
        $this->afterSaveTestRecord();


        // delete model
        $this->beforeDeleteTestRecord();
        $this->assertTrue($this->model->delete(), 'Can not delete model');
        $this->afterDeleteTestRecord();
        $this->assertNull($className::model()->findByPk($this->model->id), 'Model found after successful delete');

        $this->model = $className::model();
    }

    public function getAttributeValues()
    {
        return array_fill_keys(array_keys($this->model->myAttributes()), null);
    }

    public function setTestRecordValues()
    {
        $this->model->setAttributes($this->getAttributeValues(), false);
    }

    public function updateTestRecordValues()
    {
        $this->setTestRecordValues();
    }


    public function beforeValidateTestRecord()
    {

    }

    public function afterValidateTestRecord()
    {

    }

    public function beforeSaveTestRecord()
    {

    }

    public function afterSaveTestRecord()
    {

    }

    public function beforeDeleteTestRecord()
    {

    }

    public function afterDeleteTestRecord()
    {

    }
}
