<?php

namespace Velis\Bpm\Workflow;

use Velis\Model\BaseModel;
use Velis\Bpm\Workflow;
use Velis\Bpm\Workflow\Action;
use Velis\App;
use Velis\Output;

/**
 * Workflow event action handler base
 * @author Olek Procki <olo@velis.pl>
 */
abstract class Handler extends BaseModel
{
    /**
     * Workflow object
     * @var \Velis\Bpm\Workflow
     */
    protected $_workflow;

    /**
     * Workflow action
     * @var \Velis\Bpm\Workflow\Action
     */
    protected $_action;



    /**
     * Constructor
     * @param \Velis\Bpm\Workflow
     * @param \Velis\Bpm\Workflow\Action
     */
    public function __construct(Workflow $workflow, Action $action)
    {
        $this->_workflow = $workflow;
        $this->_action   = $action;

        parent::__construct($action->getParams());
    }


    /**
     * Returns related action
     * @return \Workflow\Action
     */
    public function getAction()
    {
        return $this->_action;
    }


    /**
     * Abstract function to be overriden by handler implementation
     */
    abstract public function run($subject, $additionalData);


    /**
     * Suppose to return parameters reflection (if any parameter needed)
     * @return array
     */
    public static function getParamsReflection()
    {
        return array();
    }


    /**
     * Shortcut function to report execution success
     *
     * @param object $subject
     * @param mixed $additionalParams
     * @param mixed $info
     *
     * @return \Velis\Bpm\Workflow\Handler
     */
    public function success($subject, $additionalParams = null, $info = null)
    {
        return $this->log(
            Log::SUCCESS,
            $subject,
            $additionalParams,
            $info
        );
    }


    /**
     * Shortcut function to report execution notice
     *
     * @param object $subject
     * @param mixed $additionalParams
     * @param mixed $info
     *
     * @return \Velis\Bpm\Workflow\Handler
     */
    public function notice($subject, $additionalParams = null, $info = null)
    {
        return $this->log(
            Log::NOTICE,
            $subject,
            $additionalParams,
            $info
        );
    }


    /**
     * Shortcut function to report execution failure
     *
     * @param object $subject
     * @param mixed $additionalParams
     * @param mixed $info
     *
     * @return \Velis\Bpm\Workflow\Handler
     */
    public function error($subject, $additionalParams = null, $info = null)
    {
        return $this->log(
            Log::ERROR,
            $subject,
            $additionalParams,
            $info
        );
    }


    /**
     * Logs action execution
     *
     * @param string $status
     * @param object $subject
     * @param mixed $additionalParams
     * @param mixed $info
     *
     * @return \Velis\Bpm\Workflow\Handler
     */
    public function log($status, $subject, $additionalParams = null, $info = null)
    {
        if (!Log::isLogAvailable()) {
            return $this;
        }

        $description = 'invoked event: ' . $this->_workflow->getInvokedEvent()->getType();
        if ($info) {
            $description .= ', ' . $info;
        }

        $log = new Log([
            'workflow_id'               => $this->_workflow->id(),
            'workflow_event_id'         => $this->_workflow['workflow_event_id'],
            'workflow_action_type_id'   => $this->_action['workflow_action_type_id'],
            'action_params'             => $this->_action['params'],
            'additional_params'         => Output::jsonEncode($additionalParams),
            'subject_id'                => is_object($subject) && method_exists($subject, 'id') ? $subject->id() : null,
            'user_id'                   => App::$user->id(),
            'status'                    => $status,
            'info'                      => $description
        ]);

        $log->add();
        return $this;
    }
}
