<?php
namespace observers;

/**
 * @version 1.0
 * @copyright (c) 2022, Jérôme Brilland
 * @license http://www.gnu.org/licenses/gpl.txt GNU General Public License
 */
class OrderableObserver implements \SplObserver {
    
    protected $columnName = '';
    
    /**
     * Class constructor
     * @param string $columnName
     * @access public
     */
    public function __construct( string $columnName = 'position' ) {
        $this->columnName = $columnName;
    }
    
    /**
     * Receive update from subject
     * @param SplSubject $subject
     * @param string $key
     * @return boolean
     * @access public
     */
    public function update( \SplSubject $subject, $key = null ) {
        $columnName = $this->columnName;
        $className = get_class( $subject );
        if ( 'before_insert' == $key ) {
            $subject->$columnName = $subject->maximum( 'position' ) + 1;
        } elseif( 'after_delete' == $key ) {
            $models = $className::findMany( [$subject->getPrimaryKey(), $columnName], ['ORDER' => $columnName] );
            $i = 0;
            foreach( $models as $model ) {
                $model->$columnName = ++$i;
                $model->save( false );
            }
        } elseif ( 'move_up' == $key ) {
            if ( $subject->$columnName > 1 ) {
                $previous = $className::findOne( [$subject->getPrimaryKey(), $columnName], [$columnName => $subject->$columnName - 1] );
                $previous->increment( 'position' );
                $subject->decrement( 'position' );
            }
        } elseif ( 'move_down' == $key ) {
            if ( $subject->$columnName < $subject->maximum( $columnName ) ) {
                $next = $className::findOne( [$subject->getPrimaryKey(), $columnName], [$columnName => $subject->$columnName + 1] );
                $next->decrement( $columnName );
                $subject->increment( $columnName );
            }
        }
        return true;
    } 
}
