<?php
/*
 *   This file is part of NOALYSS.
 *
 *   NOALYSS is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   NOALYSS is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with NOALYSS; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
// Copyright Author Dany De Bontridder danydb@aevalys.eu 10/08/24
/*! 
 * \file
 * \brief Main class for widget
 */

namespace Noalyss\Widget;

/*!
 *\class
 * \brief Main class for widget
 */
abstract class Widget
{
    //!< $var_name string name of the variable in javascript
    protected $var_name;



    public function __construct(protected int $user_widget_id=0,protected string $widget_code="",protected  $db=null)
    {
        if ($db == null) {
            $this->db=\Dossier::connect();
        }
        $this->var_name='';
    }

    /**
     * @return mixed
     */
    public function get_var_name()
    {
        return $this->var_name;
    }

    /**
     * @param mixed $var_name
     */
    public function set_var_name($var_name):Widget
    {
        $this->var_name = $var_name;
        return $this;
    }

    public function get_user_widget_id(): int
    {
        return $this->user_widget_id;
    }

    public function set_user_widget_id(int $user_widget_id): Widget
    {
        $this->user_widget_id = $user_widget_id;
        return $this;
    }

    public function get_widget_code(): string
    {
        return $this->widget_code;
    }

    public function set_widget_code(string $widget_code):  Widget
    {
        $this->widget_code = $widget_code;
        return $this;
    }

    /**
     * @brief display the content for the current connected user of the widget with the parameter
     * @return mixed
     */
    abstract function display();

    /**
     * @brief display a description of the widget and allow to save it for the current user, call input_param function
     * of the widget if it exists
     * @return mixed
     */
    function input($flnumber=true)
    {
        static $nb=0;
        $nb++;
        //read description from database
        $row=$this->db->get_row("
                    select 
                        wd_code
                        ,wd_name
                        ,wd_parameter,
                        wd_description 
                    from 
                        widget_dashboard 
                    where 
                        wd_code=$1",
        [$this->widget_code]);
        $strNumber="";
        if ( $flnumber) $strNumber="[ $nb ]";
        echo "<li id=\"elt_{$this->user_widget_id}\">  $strNumber <span class='widget-name'>{$row['wd_name']}</span>{$row['wd_description']}";

        if ( $this->user_widget_id > 0) {
            if ( $row['wd_parameter'] == 1) {
                $this->display_parameter();
            }
            echo '<span style="float:right;color:red">'.\Icon_Action::trash(uniqid(),sprintf("widget.delete('%s')",$this->user_widget_id));
        }
        else {
            if ( $row['wd_parameter'] == 1) {
                $this->input_parameter();
            }
            echo '<span style="float:right;">'.\Icon_Action::icon_add(uniqid(),sprintf("widget.add('%s')",$this->widget_code));
        }

        echo '</span>';
        echo '</li>';
    }

    /**
     * @brief returns an array  of widget for the connected user, ordered
     * @return array [ uw_id,dashboard_widget_id,wd_code,wd_description
     */
    static function get_enabled_widget():array
    {
        global $g_user,$cn;
        return $cn->get_array("
        select 
	uw.uw_id,
	uw.dashboard_widget_id ,
	wd.wd_code,
	wd.wd_description
	from user_widget uw 
join widget_dashboard wd on (uw.dashboard_widget_id=wd.wd_id)
where use_login=$1 order by uw.uw_order
",[$g_user->login]);

    }

    /**
     * @brief Build a widget thank the user_widget_id (SQL :PK :  USER_WIDGET.UW_ID) and $widget_code
     * @param $user_widget_id integer (SQL :PK :  USER_WIDGET.UW_ID)
     * @param $widget_code string (SQL WIDGET_DASHBOARD.WD_CODE)
     * @return Widget
     */
    static function build_user_widget($user_widget_id,$widget_code):?Widget
    {
        // load the class if file (code/code.php) exists.
        if (file_exists(NOALYSS_INCLUDE."/widget/$widget_code/$widget_code.php")) {
            require_once NOALYSS_INCLUDE."/widget/$widget_code/$widget_code.php";
            $class=sprintf("\\Noalyss\\Widget\\%s",$widget_code);
            $obj= new $class;
            $obj->set_widget_code($widget_code);
            $obj->set_user_widget_id($user_widget_id);
            return $obj;
        }

        // return the object
        return null;
    }

    /**
     * @brief output the DIV HTML with class and id for the widget
     * @return void
     */
    function open_div() {
        printf( '<div id="%s" class="box widget-box">',$this->get_div_domid());
    }

    /**
     * @brief compute the DIV ID
     * @return string
     */
    function get_div_domid() :string {
        return sprintf( "%s_%s",$this->widget_code,$this->user_widget_id);
    }
    function close_div() {
        echo '</div>';
    }

    /**
     * @brief display a box and fills it with the content of an ajax calls , the ajax calls Widget::display
     * @param Widget $widget
     * @return void
     */
    static function ajax_display(Widget $widget ){
        $box= sprintf( '%s_%s',$widget->get_widget_code(),$widget->get_user_widget_id());
        $widget->open_div();
        echo h2(_("Un instant, on charge :-)"),' class="title" ');


        print '<div style="display:flex;justify-content: center">';
        print '<div style="margin-top: 50px;margin-left: 20px;">';
        print '<div class="loading_msg"></div>';
        print '<div class="loading_msg"></div>';
        print '<div class="loading_msg"></div>';
        print '<div class="loading_msg"></div>';
        print '<div class="loading_msg"></div>';
        print '</div>';
        print '</div>';

        $widget->close_div();

        $dossier_id=\Dossier::id();
        $widgetjs=uniqid('widget');
        echo <<<EOF
<script>
var {$widgetjs}= new Widget('{$dossier_id}') 
{$widgetjs}.display('{$box}',{$widget->get_user_widget_id()},'{$widget->get_widget_code()}','{$widgetjs}')
</script>


EOF;



    }

    /**
     * @brier display activated widgets
     * @return void
     */
    static function display_available()
    {

        $aWidget=Widget::get_enabled_widget();
        echo '<ul class="list-unstyled" id="contain_widget">';
        foreach ($aWidget as $item) {
            $widget=Widget::build_user_widget($item['uw_id'],$item['wd_code']);
            $widget->input();
        }
        echo '</ul>';
        echo \HtmlInput::hidden("order_widget_hidden", "");
        create_script("widget.create_sortable()");
    }

    /**
     * @brief save widget order from an array
     * @param $array array of USER_WIDGET.UW_ID
     * @return void
     * @exception DatabaseCore fails , cannot update
     */
    static function save($array) {
        global $cn,$g_user;
        if (empty($array)) {
            $cn->exec_sql("delete from user_widget where use_login = $1",[$g_user->getLogin()]);
            return;
        }
        try {
            $cn->start();
            $order=10;
            $cn->exec_sql("create temporary table tmp_widget(user_widget_id integer,tw_order integer )");
            foreach ($array as $item) {
                $cn->exec_sql('insert into tmp_widget(user_widget_id,tw_order ) values ($1,$2)',
                [$item,$order]);
                $order+=20;
            }
            $cn->exec_sql("delete from user_widget where use_login = $1 and uw_id not in (select user_widget_id from tmp_widget)",
                array($g_user->getLogin()));

            $cn->exec_sql("update user_widget set uw_order =tw_order from  tmp_widget where user_widget_id=uw_id");

            $cn->commit();

        } catch (\Exception $e) {
            throw ($e);
        }


    }

    /**
     * @brief show all the widget that can be added
     * @return void
     */
    public static function select_available()
    {
        global $cn;
        Widget::scanfolder();
        $aWidget=$cn->get_array("select wd_code,wd_name, wd_description,wd_parameter from widget_dashboard order by wd_name");
        echo '<ul id="widget_add" class="list-unstyled">';
        foreach ($aWidget as $item) {
            $widget=Widget::build_user_widget(-1,$item['wd_code']);
            $widget?->input(false);

        }
        echo '</ul>';
    }

    /**
     * @brief open a form with the DOMID "widget_code"_param, it appears once only for each widget in the dialog box
     * for adding widget to the dashboard
     * @param $html_input string HTML string with all the HTML  INPUT that will be enclosed by the FORM
     * @return void
     */
    function make_form($html_input)
    {
        printf ('<form id="%s_param" style="display:inline">',$this->widget_code);
        echo $html_input;
        printf ('</form>');
    }

    /**
     * @brief MUST BE overrided if the widget needs extra parameters, create a FORM to add extra-parameter
     * @return void
     * @throws \Exception
     */
    function input_parameter ()
    {
        throw new \Exception(__FUNCTION__." not implemented");
    }

    /**
     * @brief MUST BE overrided if the widget needs extra parameters, display the content of extra-parameter
     * @param $user_widget_id
     * @return void
     * @throws \Exception
     */

    function display_parameter() {
        throw new \Exception(__FUNCTION__." not implemented");
    }

    /**
     * @brief scan folder to find install.php file , include them if the code is not in DB
     * @return void
     */
    static   function scanfolder()
    {
        global $cn;
        $handle=opendir(NOALYSS_INCLUDE."/widget");
        while (($dir = readdir($handle)) != false ) {
            $directory=NOALYSS_INCLUDE."/widget".DIRECTORY_SEPARATOR.$dir;
            if (is_dir($directory) && $dir != "." && $dir != "..") {
                // code exists in DB ?
                $cnt=$cn->get_value("select count(*) from widget_dashboard where wd_code = $1",[$dir]);
                if ( $cnt > 0) {
                    continue;
                } else {
                    // include the install.php file if any and install the widget
                    if (file_exists($directory . DIRECTORY_SEPARATOR . "install.php")){
                        include $directory . DIRECTORY_SEPARATOR . "install.php";
                    }
                }
            }
        }

    }

    /**
     * @brief get the parameter of the widget and returns an array
     * @return array  key=>value
     */
    function get_parameter()
    {
        $param = $this->db->get_value("select uw_parameter from user_widget where uw_id=$1",[$this->user_widget_id]);
        if (empty ($param)) return [];
        parse_str($param,$aParam);
        return $aParam;
    }

    /**
     * @brief compute the button ZOOM to put in the title
     * @return \html
     */
    function button_zoom() {
        $bt = \Icon_Action::zoom(uniqid(), sprintf("widget.toggle_full_size('%s')",$this->get_div_domid()));
        return $bt;
    }
    /**
     * @brief display the title and the icon for zooming + refresh if possible
     * @param $title string title of the widget
     */
    function title( $title) {
        // var $refresh string javascript to refresh the widget
        $refresh='';
        if ( $this->get_var_name() !="") {
            $refresh=Widget::build_refresh_js( $this->get_widget_code(),
                $this->get_user_widget_id(),
                $this->get_var_name());

        }

        $r='<div class="bxbutton">';
        $r.=\Icon_Action::refresh(uniqid(), $refresh);
        $r.='<span  id="span_'.uniqid().'" style="float:right;margin-right:5px">'.$this->button_zoom()."</span>";
        $r.='</div>';
        $r.=sprintf('<h2 class="title">%s</h2>',$title);
        echo $r;
    }
    /**
     * @brief build refresh javascript
     * @param $widget_id int id from DB
     * @param $widget_code string code of the widget
     * @param $var_name string name of the js variable
     */
    static function build_refresh_js($widget_code,$widget_id,$var_name)
    {
        // var $box string DOM ID  of the DIV containing the widget
        $box= sprintf( '%s_%s',$widget_code,$widget_id);
        $refresh=sprintf("%s.display('%s','%s','%s','%s')",
            $var_name,
            $box,
            $widget_id,
            $widget_code,
            $var_name
        );
        return $refresh;
    }
}