<?php

declare(strict_types=1);

/**
 * This file is part of LEPTON Core, released under the GNU GPL
 * Please see LICENSE and COPYING files in your package for details, specially for terms and warranties.
 * 
 * NOTICE:LEPTON CMS Package has several different licenses.
 * Please see the individual license in the header of each single file or info.php of modules and templates.
 *
 * @author          LEPTON Project
 * @copyright       2010-2026 LEPTON Project
 * @link            https://lepton-cms.org
 * @license         https://gnu.org/licenses/gpl.html
 * @license_terms   please see LICENSE and COPYING files in your package
 *
 */


class LEPTON_order
{
    private string $table = '';
    private string $order_field = '';
    private string $id_field = '';
    private string $common_field = '';
    
    public string $errorMessage = '';

    public static $instance;

    /**
     * @param string $table
     * @param string $order_field
     * @param string $id_field
     * @param string $common_field
     * @return object
     */
    public static function getInstance(string $table, string $order_field = 'position', string $id_field = 'id', string $common_field = ''): object
    {
        if (null === static::$instance)
        {
            static::$instance = new static($table, $order_field, $id_field, $common_field);
        }
        return static::$instance;
    }

    /**
     * @param string $table
     * @param string $order_field
     * @param string $id_field
     * @param string $common_field
     */
    public function __construct(string $table, string $order_field = 'position', string $id_field = 'id', string $common_field = '')
    {
        $this->table        = $table;
        $this->order_field  = $order_field;
        $this->id_field     = $id_field;
        $this->common_field = $common_field;
    }

    /**
     * Move a row up
     *
     * @param int $id
     * @return bool
     */
    public function move_up(int $id): bool
    {
        $database = LEPTON_database::getInstance();
        // get current record
        
        $this->errorMessage = "";

        $sql = 'SELECT `'.$this->order_field.'`';
        if ($this->common_field != '')
        {
            $sql .= ',`'.$this->common_field.'`';
        }
        $sql .= ' FROM `'.$this->table.'` WHERE `'.$this->id_field.'`='.$id;
        
        $rec_current = [];
        $database->execute_query(
            $sql,
            true,
            $rec_current,
            false
        );
        
        if (!empty($rec_current))
        {   
            // get previous record
            $sql = 'SELECT `'.$this->id_field.'`,`'.$this->order_field.'` ';
            $sql .= 'FROM `'.$this->table.'` ';
            $sql .= 'WHERE (`'.$this->order_field.'`<'.$rec_current[$this->order_field].') ';
            if ($this->common_field != '')
            {
                $sql .= 'AND (`'.$this->common_field.'`=\''.$rec_current[$this->common_field].'\') ';
            }
            $sql .= 'ORDER BY `'.$this->order_field.'` DESC';
            
            $rec_prev = [];
            $database->execute_query(
                $sql,
                true,
                $rec_prev,
                false
            );
            if (!empty($rec_prev))
            {
                // update current record
                $sql = 'UPDATE `'.$this->table.'` ';
                $sql .= 'SET `'.$this->order_field.'`='.$rec_prev[$this->order_field].' ';
                $sql .= 'WHERE `'.$this->id_field.'`='.$id;
                if ($database->simple_query($sql))
                {
                    // update previous record
                    $sql = 'UPDATE `'.$this->table.'` ';
                    $sql .= 'SET `'.$this->order_field.'`='.$rec_current[$this->order_field].' ';
                    $sql .= 'WHERE `'.$this->id_field.'`='.$rec_prev[$this->id_field];
                    if ($database->simple_query($sql))
                    {
                        return true;
                    
                    } else {
                        $this->errorMessage = $database->get_error()." [1]";
                        return false;
                    }
                } else {
                    $this->errorMessage = $database->get_error()." [2]";
                    return false;
                }
            
            } else {
                $this->errorMessage = $database->get_error()." [3]";
                return false;
            }
        
        }
        $this->errorMessage = $database->get_error()." [4]";
        return false;
    }
    
    /**
     * Move a row down
     *
     * @param int $id
     * @return bool
     */
    public function move_down(int $id): bool
    {
        global $database;
        
        $this->errorMessage = "";
        
        // get current record
        $sql = 'SELECT `'.$this->order_field.'`';
        if ($this->common_field != '')
        {
            $sql .= ',`'.$this->common_field.'`';
        }
        $sql .= ' FROM `'.$this->table.'` WHERE `'.$this->id_field.'`='.(int)$id;
        
        $rec_current = [];
        $database->execute_query(
            $sql,
            true,
            $rec_current,
            false
        );
        
        if (!empty($rec_current))
        {
            
            // get next record
            $sql = 'SELECT `'.$this->id_field.'`,`'.$this->order_field.'` ';
            $sql .= 'FROM `'.$this->table.'` ';
            $sql .= 'WHERE (`'.$this->order_field.'`>'.$rec_current[$this->order_field].') ';
            if ($this->common_field != '')
            {
                $sql .= 'AND (`'.$this->common_field.'`=\''.$rec_current[$this->common_field].'\') ';
            }
            $sql .= 'ORDER BY `'.$this->order_field.'` ASC';
            $rec_next = [];
            $database->execute_query(
                $sql,
                true,
                $rec_next,
                false
            );
            
            if (!empty($rec_next))
            {       
                // update current record
                $sql = 'UPDATE `'.$this->table.'` ';
                $sql .= 'SET `'.$this->order_field.'`='.$rec_next[$this->order_field].' ';
                $sql .= 'WHERE `'.$this->id_field.'`='.$id;
                
                if ($database->simple_query($sql))
                {
                    // update next record
                    $sql = 'UPDATE `'.$this->table.'` ';
                    $sql .= 'SET `'.$this->order_field.'`='.$rec_current[$this->order_field].' ';
                    $sql .= 'WHERE `'.$this->id_field.'`='.$rec_next[$this->id_field];
                    if ($database->simple_query($sql))
                    {
                        return true;
                    } else {
                        $this->errorMessage = $database->get_error()." [5]";
                        return false;
                    }
                } else {
                    $this->errorMessage = $database->get_error()." [6]";
                    return false;
                }
            
            } else {
                $this->errorMessage = $database->get_error()." [7]";
                return false;
            }
        
        }
        $this->errorMessage = $database->get_error()." [8]";
        return false;
    }
    
    /**
     * Get new number for order
     *
     * @param string $cf_value
     * @return int
     */
    public function get_new(string $cf_value = ''): int
    {
        $database = LEPTON_database::getInstance();
        // Get last order
        $sql = 'SELECT MAX(`' . $this->order_field . '`) FROM `' . $this->table . '` ';
        if ($cf_value != '')
        {
            $sql .= 'WHERE `' . $this->common_field . '`=\'' . $cf_value . '\'';
        }
        return 1+ intval($database->get_one($sql));
    }

    /**
     * Clean ordering (should be called time by time if rows in the middle have been deleted)
     *
     * @param string|int $cf_value
     * @return bool
     */
    public function clean(string|int $cf_value = ''): bool
    {
        $database = LEPTON_database::getInstance();
        // Loop through all records and give new order
        $sql = 'SELECT `'.$this->id_field.'` FROM `'.$this->table.'` ';
        if ($cf_value > -1)
        {
            $sql .= 'WHERE `'.$this->common_field.'`=\''.$cf_value.'\'';
        }
        $sql .= 'ORDER BY `'.$this->order_field.'` ASC';
        
        $res_ids = [];
        $database->execute_query(
            $sql,
            true,
            $res_ids,
            true
        );
        if (!empty($res_ids))
        {
            $count = 1;
            foreach ($res_ids as $rec_id)
            {
                $sql = 'UPDATE `'.$this->table.'` SET `'.$this->order_field.'`='.($count++).' ';
                $sql .= 'WHERE `'.$this->id_field.'`='.$rec_id[$this->id_field];
                if (!$database->simple_query($sql))
                {
                    $this->errorMessage = $database->get_error()." [9]";
                    return false;
                }
            }
            return true;
        }
        $this->errorMessage = $database->get_error();
        return false;
    }
}
