<?php
/**
 *  OrderActions - helper class to handle automatic actions from steps
 */
class OrderActions{
    private $idAssignProcessStep = 2;

    /**
     * execute automated step
     * @param  INT $idOrder       id for the order
     * @param  INT $idProcessStep id for the process step
     * @return INT                execution status; 1 for success and 0 for fail
     */
    public function executeAutomatedStep($idOrder, $idProcessStep){
        global $database;
        $status = [];

        $sql = "SELECT psa.actionCode, psa.stepType, ps.id as idProcessStep
                FROM ".TABLES['process_step']." ps
                INNER JOIN ".TABLES['process_step_actions']." psa
                ON psa.id=ps.idActionCode
                INNER JOIN ".TABLES['rel_process_steps']." rps
                ON rps.idStep=ps.id
                WHERE rps.id=$idProcessStep
                LIMIT 1";
        $step = $database->fetchResultArray($sql);

        if($step && count($step) > 0){
            $status['actionExectution'] = $this->{ $step[0]['actionCode'] }($idOrder, $idProcessStep);
            $childSteps = $this->getStepChilds($idProcessStep);
            $status['updateCurrentStep'] = $this->updateActiveStep($idOrder, $idProcessStep, $childSteps);

            foreach ($childSteps as $child) {
                if($child['stepType'] === 'auto'){
                    return $this->executeAutomatedStep($idOrder, $child['idProcessStep']);
                }else{
                    return $status['actionExectution'] > 0 && $status['updateCurrentStep'] > 0 ? 1 :0;
                }
            }
        }else{
            return 0;
        }

    }
    /**
     * update the status for the step in progress
     * @param  INT $idOrder       id for the order
     * @param  INT $idProcessStep id for the process step
     * @return INT                affected rows
     */
    public function updateActiveStep($idOrder, $idProcessStep, $childSteps){
        global $database;

        $sqlUpdateCurrentStep = "UPDATE ".TABLES['rel_order_process_step']."
                    SET status='done',
                        actualDate = IF(actualDate IS NULL, '".date("Y-m-d")."', actualDate)
                WHERE idOrder=$idOrder
                    AND idProcessStep=$idProcessStep
        ";
        $query = $database->query($sqlUpdateCurrentStep);
        $status['current'] = $database->affectedRows();

        $childValues = '';
        if(count($childSteps) > 0){
            foreach ($childSteps as $child) {
                $childValues .= $child['idProcessStep'].',';
            }
            $childValues = rtrim($childValues, ',');
            $sqlUpdateChilds = "UPDATE ".TABLES['rel_order_process_step']."
                                SET status='in-progress'
                                WHERE idOrder=$idOrder AND idProcessStep IN($childValues)";
            $query = $database->query($sqlUpdateChilds);
            $status['child'] = $database->affectedRows();
        }else{
            $status['child'] = 1;
        }

        return $status['current'] > 0 && $status['child'] > 0 ? 1 : 0;
    }

    /**
     * remove a process from a package inan order
     * @param  INT $idOrder   id for the order
     * @return INT            number of affected rows
     */
    private function removeProcess($idOrder){
        global $database;

        $sql = "DELETE FROM ".TABLES['rel_order_process_step']."
                WHERE idOrder=$idOrder";
        $query = $database->query($sql);
        $affectedRows = $database->affectedRows();

        $sql = "UPDATE ".TABLES['rel_order_packages']."
                SET status='no-process'
                WHERE idOrder=$idOrder";
        $query = $database->query($sql);
        $affectedRows += $database->affectedRows();

        $sql = "UPDATE ".TABLES['orders']."
                SET status='open'
                WHERE id=$idOrder";
        $query = $database->query($sql);
        $affectedRows += $database->affectedRows();

        return $affectedRows;
    }

    /**
     * undo an open step
     * @param  INT $idOrder       id for the order
     * @param  INT $idProcessStep id for the process step
     * @return INT                1 in case the step has benn undone and 0 in case of failure
     */
    public function undoStep($idOrder, $idProcessStep){
        global $database;

        $database->beginTransaction();

        $sqlUpdateCurrentStep = "
                UPDATE ".TABLES['rel_order_process_step']."
                    SET status='inactive'
                WHERE idOrder=$idOrder
                    AND idProcessStep=$idProcessStep
        ";
        $query = $database->query($sqlUpdateCurrentStep);
        $status['current'] = $database->affectedRows();

        $sql = "SELECT parent.idStep
            FROM ".TABLES['rel_process_steps']." parent
            INNER JOIN ".TABLES['rel_process_steps']." current
                ON current.idParent=parent.id
            WHERE current.id=$idProcessStep";
        $step = $database->fetchResultArray($sql)[0];

        if(intval($step['idStep']) === $this->idAssignProcessStep){
            $status['parent'] = $this->removeProcess($idOrder);
        }else{
            $sqlUpdateParent = "
                    UPDATE ".TABLES['rel_order_process_step']."
                        SET status='in-progress'
                    WHERE idOrder=$idOrder
                        AND idProcessStep=(SELECT idParent
                            FROM ".TABLES['rel_process_steps']."
                            WHERE id=$idProcessStep)";
            $query = $database->query($sqlUpdateParent);
            $status['parent'] = $database->affectedRows();
        }

        if($status['current'] < 1 && $status['parent'] < 1){
            $database->rollback();

            return 0;
        }

        $database->commit();

        return 1;
    }

    /**
     * get childs for a step
     * @param  INT $idProcessStep   id for the process step
     * @return Array                Array with childs
     */
    public function getStepChilds($idProcessStep){
        global $database;

        $sqlChilds = "SELECT rps.id AS idProcessStep,
                            psa.actionCode,
                            psa.stepType
                    FROM ".TABLES['rel_process_steps']." rps
                    INNER JOIN ".TABLES['process_step']." ps
                        ON ps.id=rps.idStep
                    INNER JOIN ".TABLES['process_step_actions']." psa
                        ON psa.id=ps.idActionCode
                    WHERE rps.idParent=$idProcessStep";

        return $database->fetchResultArray($sqlChilds);
    }

    /**
     * update the current step and activate childs (execute automated steps if they exist)
     * @param  INT $idOrder       id for the order
     * @param  INT $idPackage     id for the package
     * @param  INT $idProcessStep id for the process step
     * @return Array                number of update childs and executed automated steps
     */
    public function updateChildSteps($idOrder, $idPackage, $idProcessStep){
        global $database;

        $childsUpdated = [
            'manual' => 0,
            'automated' => 0
        ];
        $childSteps = $this->getStepChilds($idProcessStep);

        if(!empty($childSteps)){
            $childValues = '';
            $automatedSteps = [];
            foreach ($childSteps as $child) {
                if($child['stepType'] === 'auto'){
                    $automatedSteps[] = $child;
                }
                $childValues .= $child['idProcessStep'].',';
            }
            $childValues = rtrim($childValues, ',');
            $sqlUpdateChilds = "UPDATE ".TABLES['rel_order_process_step']."
                                SET status='in-progress'
                                WHERE idOrder=$idOrder AND idPackage=$idPackage AND idProcessStep IN($childValues)";
            $query = $database->query($sqlUpdateChilds);

            $childsUpdated['manual'] = $database->affectedRows();

            foreach ($automatedSteps as $child) {
                $childActionStatus = $this->{ $child['actionCode'] }($idOrder, $idPackage, $child['idProcessStep']);
                if($childActionStatus){
                    $childsUpdated['automated'] = $this->updateActiveStep($idOrder, $child['idProcessStep']);
                    $automatedNewChilds = $this->updateChildSteps($idOrder, $idPackage, $child['idProcessStep']);
                }
            }
        }

        return $childsUpdated;
    }

    /**
     * automatic action executed for Order Placed step
     * @param  INT $idOrder       id of the order
     * @param  INT $idProcessStep id of the link of the step to the process
     * @return boolean                result for executing automated step
     */
    public function newOrder($idOrder, $idProcessStep){
        global $database;

        $sql = "SELECT o.orderDate
                FROM ".TABLES['orders']." o
                WHERE id=$idOrder";
        $order = $database->fetchResultArray($sql);
        if(!isset($order[0])){
            $order[0]['orderDate'] = date("Y-m-d");
        }

        $sql = "UPDATE ".TABLES['rel_order_process_step']."
                SET estimateDate='".$order[0]['orderDate']."',
                    actualDate='".$order[0]['orderDate']."',
                    status='done'
                WHERE idOrder=$idOrder AND idProcessStep=$idProcessStep";
        $query = $database->query($sql);

        return  $database->affectedRows() === 1;
    }

    /**
     * automatic action for assign process
     * @param  INT $idOrder   id of the order
     * @return boolean        result for executing automated step
     */
    public function processAssigned($idOrder){
        global $database;

        $sql = "UPDATE ".TABLES['rel_order_packages']."
                SET status='processing'
                WHERE idOrder=$idOrder";
        $query = $database->query($sql);

        return $database->affectedRows() > 0;
    }
}
?>
