<?php

namespace ProjectManagement\prjProjectManagement;

use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Query\QueryBuilder;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Container\ContainerInterface;
use Slim\Routing\RouteCollectorProxy;
use Slim\App;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use Closure;

/**
 * Table class for PerformanceReport
 */
class PerformanceReport extends ReportTable
{
    protected $SqlFrom = "";
    protected $SqlSelect = null;
    protected $SqlSelectList = null;
    protected $SqlWhere = "";
    protected $SqlGroupBy = "";
    protected $SqlHaving = "";
    protected $SqlOrderBy = "";
    public $DbErrorMessage = "";
    public $UseSessionForListSql = true;

    // Column CSS classes
    public $LeftColumnClass = "col-sm-2 col-form-label ew-label";
    public $RightColumnClass = "col-sm-10";
    public $OffsetColumnClass = "col-sm-10 offset-sm-2";
    public $TableLeftColumnClass = "w-col-2";
    public $ShowGroupHeaderAsRow = false;
    public $ShowCompactSummaryFooter = true;

    // Ajax / Modal
    public $UseAjaxActions = false;
    public $ModalSearch = false;
    public $ModalView = false;
    public $ModalAdd = false;
    public $ModalEdit = false;
    public $ModalUpdate = false;
    public $InlineDelete = false;
    public $ModalGridAdd = false;
    public $ModalGridEdit = false;
    public $ModalMultiEdit = false;
    public $PerformanceReport;
    public $TotalTask;

    // Fields
    public $TaskID;
    public $TaskName;
    public $Description;
    public $AssignedTo;
    public $Progress;
    public $Target;
    public $Track;
    public $PlanStart;
    public $PlanEnd;
    public $StartDate;
    public $EndDate;
    public $Priority;
    public $Category;
    public $_ProjectID;
    public $Created_Date;
    public $Created_By;
    public $Last_Updated_Date;
    public $Last_Updated_By;
    public $Complete;

    // Page ID
    public $PageID = ""; // To be overridden by subclass

    // Constructor
    public function __construct()
    {
        parent::__construct();
        global $Language, $CurrentLanguage, $CurrentLocale;

        // Language object
        $Language = Container("app.language");
        $this->TableVar = "PerformanceReport";
        $this->TableName = 'PerformanceReport';
        $this->TableType = "REPORT";
        $this->TableReportType = "summary"; // Report Type
        $this->ReportSourceTable = 'projecttask'; // Report source table
        $this->Dbid = 'DB';
        $this->ExportAll = true;
        $this->ExportPageBreakCount = 0; // Page break per every n record (report only)

        // PDF
        $this->ExportPageOrientation = "portrait"; // Page orientation (PDF only)
        $this->ExportPageSize = "a4"; // Page size (PDF only)

        // PhpSpreadsheet
        $this->ExportExcelPageOrientation = \PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_DEFAULT; // Page orientation (PhpSpreadsheet only)
        $this->ExportExcelPageSize = \PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::PAPERSIZE_A4; // Page size (PhpSpreadsheet only)

        // PHPWord
        $this->ExportWordPageOrientation = "portrait"; // Page orientation (PHPWord only)
        $this->ExportWordPageSize = "A4"; // Page orientation (PHPWord only)
        $this->ExportWordColumnWidth = null; // Cell width (PHPWord only)
        $this->UserIDAllowSecurity = Config("DEFAULT_USER_ID_ALLOW_SECURITY"); // Default User ID allowed permissions

        // TaskID
        $this->TaskID = new ReportField(
            $this, // Table
            'x_TaskID', // Variable name
            'TaskID', // Name
            '`TaskID`', // Expression
            '`TaskID`', // Basic search expression
            3, // Type
            11, // Size
            -1, // Date/Time format
            false, // Is upload field
            '`TaskID`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'NO' // Edit Tag
        );
        $this->TaskID->InputTextType = "text";
        $this->TaskID->Raw = true;
        $this->TaskID->IsAutoIncrement = true; // Autoincrement field
        $this->TaskID->IsPrimaryKey = true; // Primary key field
        $this->TaskID->Nullable = false; // NOT NULL field
        $this->TaskID->DefaultErrorMessage = $Language->phrase("IncorrectInteger");
        $this->TaskID->SearchOperators = ["=", "<>", "IN", "NOT IN", "<", "<=", ">", ">=", "BETWEEN", "NOT BETWEEN"];
        $this->TaskID->SourceTableVar = 'projecttask';
        $this->Fields['TaskID'] = &$this->TaskID;

        // TaskName
        $this->TaskName = new ReportField(
            $this, // Table
            'x_TaskName', // Variable name
            'TaskName', // Name
            '`TaskName`', // Expression
            '`TaskName`', // Basic search expression
            200, // Type
            100, // Size
            -1, // Date/Time format
            false, // Is upload field
            '`TaskName`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'TEXT' // Edit Tag
        );
        $this->TaskName->InputTextType = "text";
        $this->TaskName->Required = true; // Required field
        $this->TaskName->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->TaskName->Lookup = new Lookup($this->TaskName, 'PerformanceReport', true, 'TaskName', ["TaskName","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
            default:
                $this->TaskName->Lookup = new Lookup($this->TaskName, 'PerformanceReport', true, 'TaskName', ["TaskName","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
        }
        $this->TaskName->SearchOperators = ["=", "<>", "IN", "NOT IN", "STARTS WITH", "NOT STARTS WITH", "LIKE", "NOT LIKE", "ENDS WITH", "NOT ENDS WITH", "IS EMPTY", "IS NOT EMPTY", "IS NULL", "IS NOT NULL"];
        $this->TaskName->SourceTableVar = 'projecttask';
        $this->TaskName->SearchType = "dropdown";
        $this->Fields['TaskName'] = &$this->TaskName;

        // Description
        $this->Description = new ReportField(
            $this, // Table
            'x_Description', // Variable name
            'Description', // Name
            '`Description`', // Expression
            '`Description`', // Basic search expression
            200, // Type
            65535, // Size
            -1, // Date/Time format
            false, // Is upload field
            '`Description`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'TEXTAREA' // Edit Tag
        );
        $this->Description->InputTextType = "text";
        $this->Description->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->Description->Lookup = new Lookup($this->Description, 'PerformanceReport', true, 'Description', ["Description","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
            default:
                $this->Description->Lookup = new Lookup($this->Description, 'PerformanceReport', true, 'Description', ["Description","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
        }
        $this->Description->SearchOperators = ["=", "<>", "IN", "NOT IN", "STARTS WITH", "NOT STARTS WITH", "LIKE", "NOT LIKE", "ENDS WITH", "NOT ENDS WITH", "IS EMPTY", "IS NOT EMPTY", "IS NULL", "IS NOT NULL"];
        $this->Description->SourceTableVar = 'projecttask';
        $this->Description->SearchType = "dropdown";
        $this->Fields['Description'] = &$this->Description;

        // AssignedTo
        $this->AssignedTo = new ReportField(
            $this, // Table
            'x_AssignedTo', // Variable name
            'AssignedTo', // Name
            '`AssignedTo`', // Expression
            '`AssignedTo`', // Basic search expression
            3, // Type
            11, // Size
            -1, // Date/Time format
            false, // Is upload field
            '`AssignedTo`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'SELECT' // Edit Tag
        );
        $this->AssignedTo->InputTextType = "text";
        $this->AssignedTo->Raw = true;
        $this->AssignedTo->GroupingFieldId = 1;
        $this->AssignedTo->ShowGroupHeaderAsRow = $this->ShowGroupHeaderAsRow;
        $this->AssignedTo->ShowCompactSummaryFooter = $this->ShowCompactSummaryFooter;
        $this->AssignedTo->GroupByType = "";
        $this->AssignedTo->GroupInterval = "0";
        $this->AssignedTo->GroupSql = "";
        $this->AssignedTo->setSelectMultiple(false); // Select one
        $this->AssignedTo->UsePleaseSelect = true; // Use PleaseSelect by default
        $this->AssignedTo->PleaseSelectText = $Language->phrase("PleaseSelect"); // "PleaseSelect" text
        $this->AssignedTo->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->AssignedTo->Lookup = new Lookup($this->AssignedTo, 'viewprojectmember', true, 'EmployeeID', ["FullName","","",""], '', '', ["x__ProjectID"], [], ["ProjectID"], ["x__ProjectID"], [], [], false, '', '', "`FullName`");
                break;
            default:
                $this->AssignedTo->Lookup = new Lookup($this->AssignedTo, 'viewprojectmember', true, 'EmployeeID', ["FullName","","",""], '', '', ["x__ProjectID"], [], ["ProjectID"], ["x__ProjectID"], [], [], false, '', '', "`FullName`");
                break;
        }
        $this->AssignedTo->DefaultErrorMessage = $Language->phrase("IncorrectInteger");
        $this->AssignedTo->SearchOperators = ["=", "<>", "<", "<=", ">", ">=", "BETWEEN", "NOT BETWEEN", "IS NULL", "IS NOT NULL"];
        $this->AssignedTo->SourceTableVar = 'projecttask';
        $this->AssignedTo->SearchType = "dropdown";
        $this->Fields['AssignedTo'] = &$this->AssignedTo;

        // Progress
        $this->Progress = new ReportField(
            $this, // Table
            'x_Progress', // Variable name
            'Progress', // Name
            '`Progress`', // Expression
            '`Progress`', // Basic search expression
            131, // Type
            7, // Size
            -1, // Date/Time format
            false, // Is upload field
            '`Progress`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'TEXT' // Edit Tag
        );
        $this->Progress->addMethod("getDefault", fn() => 0);
        $this->Progress->InputTextType = "text";
        $this->Progress->Raw = true;
        $this->Progress->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->Progress->Lookup = new Lookup($this->Progress, 'PerformanceReport', true, 'Progress', ["Progress","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
            default:
                $this->Progress->Lookup = new Lookup($this->Progress, 'PerformanceReport', true, 'Progress', ["Progress","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
        }
        $this->Progress->DefaultErrorMessage = $Language->phrase("IncorrectFloat");
        $this->Progress->SearchOperators = ["=", "<>", "IN", "NOT IN", "<", "<=", ">", ">=", "BETWEEN", "NOT BETWEEN", "IS NULL", "IS NOT NULL"];
        $this->Progress->SourceTableVar = 'projecttask';
        $this->Progress->SearchType = "dropdown";
        $this->Fields['Progress'] = &$this->Progress;

        // Target
        $this->Target = new ReportField(
            $this, // Table
            'x_Target', // Variable name
            'Target', // Name
            'CASE
    WHEN PlanEnd IS NULL OR PlanStart IS NULL THEN 0
    ELSE LEAST(1.0, CAST(DATEDIFF(CURDATE(), PlanStart) AS FLOAT) / NULLIF(DATEDIFF(PlanEnd, PlanStart), 0))
END', // Expression
            'CASE
                WHEN PlanEnd IS NULL OR PlanStart IS NULL THEN 0
                ELSE LEAST(1.0, CAST(DATEDIFF(CURDATE(), PlanStart) AS FLOAT) / NULLIF(DATEDIFF(PlanEnd, PlanStart), 0))
            END', // Basic search expression
            5, // Type
            23, // Size
            -1, // Date/Time format
            false, // Is upload field
            'CASE
    WHEN PlanEnd IS NULL OR PlanStart IS NULL THEN 0
    ELSE LEAST(1.0, CAST(DATEDIFF(CURDATE(), PlanStart) AS FLOAT) / NULLIF(DATEDIFF(PlanEnd, PlanStart), 0))
END', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'TEXT' // Edit Tag
        );
        $this->Target->InputTextType = "text";
        $this->Target->Raw = true;
        $this->Target->IsCustom = true; // Custom field
        $this->Target->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->Target->Lookup = new Lookup($this->Target, 'PerformanceReport', true, 'Target', ["Target","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
            default:
                $this->Target->Lookup = new Lookup($this->Target, 'PerformanceReport', true, 'Target', ["Target","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
        }
        $this->Target->DefaultErrorMessage = $Language->phrase("IncorrectFloat");
        $this->Target->SearchOperators = ["=", "<>", "IN", "NOT IN", "<", "<=", ">", ">=", "BETWEEN", "NOT BETWEEN", "IS NULL", "IS NOT NULL"];
        $this->Target->SourceTableVar = 'projecttask';
        $this->Target->SearchType = "dropdown";
        $this->Fields['Target'] = &$this->Target;

        // Track
        $this->Track = new ReportField(
            $this, // Table
            'x_Track', // Variable name
            'Track', // Name
            'CASE WHEN EndDate > PlanEnd THEN \'Late\'
WHEN Progress<1 AND CURDATE()>PlanEnd THEN \'Late\'
        WHEN Progress<(CASE
    WHEN PlanEnd IS NULL OR PlanStart IS NULL THEN 0
    ELSE LEAST(1.0, CAST(DATEDIFF(CURDATE(), PlanStart) AS FLOAT) / NULLIF(DATEDIFF(PlanEnd, PlanStart), 0))
END )THEN \'Warning\'
        ELSE \'On Track\'
    END', // Expression
            'CASE WHEN EndDate > PlanEnd THEN \'Late\'
            WHEN Progress<1 AND CURDATE()>PlanEnd THEN \'Late\'
                    WHEN Progress<(CASE
                WHEN PlanEnd IS NULL OR PlanStart IS NULL THEN 0
                ELSE LEAST(1.0, CAST(DATEDIFF(CURDATE(), PlanStart) AS FLOAT) / NULLIF(DATEDIFF(PlanEnd, PlanStart), 0))
            END )THEN \'Warning\'
                    ELSE \'On Track\'
                END', // Basic search expression
            200, // Type
            8, // Size
            -1, // Date/Time format
            false, // Is upload field
            'CASE WHEN EndDate > PlanEnd THEN \'Late\'
WHEN Progress<1 AND CURDATE()>PlanEnd THEN \'Late\'
        WHEN Progress<(CASE
    WHEN PlanEnd IS NULL OR PlanStart IS NULL THEN 0
    ELSE LEAST(1.0, CAST(DATEDIFF(CURDATE(), PlanStart) AS FLOAT) / NULLIF(DATEDIFF(PlanEnd, PlanStart), 0))
END )THEN \'Warning\'
        ELSE \'On Track\'
    END', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'TEXT' // Edit Tag
        );
        $this->Track->InputTextType = "text";
        $this->Track->IsCustom = true; // Custom field
        $this->Track->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->Track->Lookup = new Lookup($this->Track, 'PerformanceReport', true, 'Track', ["Track","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
            default:
                $this->Track->Lookup = new Lookup($this->Track, 'PerformanceReport', true, 'Track', ["Track","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
        }
        $this->Track->SearchOperators = ["=", "<>", "IN", "NOT IN", "STARTS WITH", "NOT STARTS WITH", "LIKE", "NOT LIKE", "ENDS WITH", "NOT ENDS WITH", "IS EMPTY", "IS NOT EMPTY", "IS NULL", "IS NOT NULL"];
        $this->Track->SourceTableVar = 'projecttask';
        $this->Track->SearchType = "dropdown";
        $this->Fields['Track'] = &$this->Track;

        // PlanStart
        $this->PlanStart = new ReportField(
            $this, // Table
            'x_PlanStart', // Variable name
            'PlanStart', // Name
            '`PlanStart`', // Expression
            CastDateFieldForLike("`PlanStart`", 5, "DB"), // Basic search expression
            133, // Type
            10, // Size
            5, // Date/Time format
            false, // Is upload field
            '`PlanStart`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'TEXT' // Edit Tag
        );
        $this->PlanStart->addMethod("getDefault", fn() => CurrentDate());
        $this->PlanStart->InputTextType = "text";
        $this->PlanStart->Raw = true;
        $this->PlanStart->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->PlanStart->Lookup = new Lookup($this->PlanStart, 'PerformanceReport', true, 'PlanStart', ["PlanStart","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
            default:
                $this->PlanStart->Lookup = new Lookup($this->PlanStart, 'PerformanceReport', true, 'PlanStart', ["PlanStart","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
        }
        $this->PlanStart->DefaultErrorMessage = str_replace("%s", DateFormat(5), $Language->phrase("IncorrectDate"));
        $this->PlanStart->SearchOperators = ["=", "<>", "IN", "NOT IN", "<", "<=", ">", ">=", "BETWEEN", "NOT BETWEEN", "IS NULL", "IS NOT NULL"];
        $this->PlanStart->SourceTableVar = 'projecttask';
        $this->PlanStart->SearchType = "dropdown";
        $this->Fields['PlanStart'] = &$this->PlanStart;

        // PlanEnd
        $this->PlanEnd = new ReportField(
            $this, // Table
            'x_PlanEnd', // Variable name
            'PlanEnd', // Name
            '`PlanEnd`', // Expression
            CastDateFieldForLike("`PlanEnd`", 5, "DB"), // Basic search expression
            133, // Type
            10, // Size
            5, // Date/Time format
            false, // Is upload field
            '`PlanEnd`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'TEXT' // Edit Tag
        );
        $this->PlanEnd->addMethod("getDefault", fn() => date('Y-m-d', strtotime('+1 day')));
        $this->PlanEnd->InputTextType = "text";
        $this->PlanEnd->Raw = true;
        $this->PlanEnd->DefaultErrorMessage = str_replace("%s", DateFormat(5), $Language->phrase("IncorrectDate"));
        $this->PlanEnd->SearchOperators = ["=", "<>", "IN", "NOT IN", "<", "<=", ">", ">=", "BETWEEN", "NOT BETWEEN", "IS NULL", "IS NOT NULL"];
        $this->PlanEnd->SourceTableVar = 'projecttask';
        $this->Fields['PlanEnd'] = &$this->PlanEnd;

        // StartDate
        $this->StartDate = new ReportField(
            $this, // Table
            'x_StartDate', // Variable name
            'StartDate', // Name
            '`StartDate`', // Expression
            CastDateFieldForLike("`StartDate`", 5, "DB"), // Basic search expression
            133, // Type
            10, // Size
            5, // Date/Time format
            false, // Is upload field
            '`StartDate`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'TEXT' // Edit Tag
        );
        $this->StartDate->addMethod("getDefault", fn() => CurrentDate());
        $this->StartDate->InputTextType = "text";
        $this->StartDate->Raw = true;
        $this->StartDate->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->StartDate->Lookup = new Lookup($this->StartDate, 'PerformanceReport', true, 'StartDate', ["StartDate","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
            default:
                $this->StartDate->Lookup = new Lookup($this->StartDate, 'PerformanceReport', true, 'StartDate', ["StartDate","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
        }
        $this->StartDate->DefaultErrorMessage = str_replace("%s", DateFormat(5), $Language->phrase("IncorrectDate"));
        $this->StartDate->SearchOperators = ["=", "<>", "IN", "NOT IN", "<", "<=", ">", ">=", "BETWEEN", "NOT BETWEEN", "IS NULL", "IS NOT NULL"];
        $this->StartDate->SourceTableVar = 'projecttask';
        $this->StartDate->SearchType = "dropdown";
        $this->Fields['StartDate'] = &$this->StartDate;

        // EndDate
        $this->EndDate = new ReportField(
            $this, // Table
            'x_EndDate', // Variable name
            'EndDate', // Name
            '`EndDate`', // Expression
            CastDateFieldForLike("`EndDate`", 5, "DB"), // Basic search expression
            133, // Type
            10, // Size
            5, // Date/Time format
            false, // Is upload field
            '`EndDate`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'TEXT' // Edit Tag
        );
        $this->EndDate->addMethod("getDefault", fn() => date('Y-m-d', strtotime('+1 day')));
        $this->EndDate->InputTextType = "text";
        $this->EndDate->Raw = true;
        $this->EndDate->DefaultErrorMessage = str_replace("%s", DateFormat(5), $Language->phrase("IncorrectDate"));
        $this->EndDate->SearchOperators = ["=", "<>", "IN", "NOT IN", "<", "<=", ">", ">=", "BETWEEN", "NOT BETWEEN", "IS NULL", "IS NOT NULL"];
        $this->EndDate->SourceTableVar = 'projecttask';
        $this->Fields['EndDate'] = &$this->EndDate;

        // Priority
        $this->Priority = new ReportField(
            $this, // Table
            'x_Priority', // Variable name
            'Priority', // Name
            '`Priority`', // Expression
            '`Priority`', // Basic search expression
            3, // Type
            11, // Size
            -1, // Date/Time format
            false, // Is upload field
            '`Priority`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'SELECT' // Edit Tag
        );
        $this->Priority->addMethod("getDefault", fn() => 1);
        $this->Priority->InputTextType = "text";
        $this->Priority->Raw = true;
        $this->Priority->Required = true; // Required field
        $this->Priority->setSelectMultiple(false); // Select one
        $this->Priority->UsePleaseSelect = true; // Use PleaseSelect by default
        $this->Priority->PleaseSelectText = $Language->phrase("PleaseSelect"); // "PleaseSelect" text
        $this->Priority->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->Priority->Lookup = new Lookup($this->Priority, 'PerformanceReport', true, 'Priority', ["Priority","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
            default:
                $this->Priority->Lookup = new Lookup($this->Priority, 'PerformanceReport', true, 'Priority', ["Priority","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
        }
        $this->Priority->OptionCount = 3;
        $this->Priority->DefaultErrorMessage = $Language->phrase("IncorrectInteger");
        $this->Priority->SearchOperators = ["=", "<>", "<", "<=", ">", ">=", "BETWEEN", "NOT BETWEEN", "IS NULL", "IS NOT NULL"];
        $this->Priority->SourceTableVar = 'projecttask';
        $this->Priority->SearchType = "dropdown";
        $this->Fields['Priority'] = &$this->Priority;

        // Category
        $this->Category = new ReportField(
            $this, // Table
            'x_Category', // Variable name
            'Category', // Name
            '`Category`', // Expression
            '`Category`', // Basic search expression
            200, // Type
            100, // Size
            -1, // Date/Time format
            false, // Is upload field
            '`Category`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'SELECT' // Edit Tag
        );
        $this->Category->addMethod("getSelectFilter", fn() => "`Active`=1");
        $this->Category->InputTextType = "text";
        $this->Category->Required = true; // Required field
        $this->Category->setSelectMultiple(false); // Select one
        $this->Category->UsePleaseSelect = true; // Use PleaseSelect by default
        $this->Category->PleaseSelectText = $Language->phrase("PleaseSelect"); // "PleaseSelect" text
        $this->Category->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->Category->Lookup = new Lookup($this->Category, 'masterprojectcategory', true, 'CategoryName', ["CategoryName","","",""], '', '', [], [], [], [], [], [], false, '', '', "`CategoryName`");
                break;
            default:
                $this->Category->Lookup = new Lookup($this->Category, 'masterprojectcategory', true, 'CategoryName', ["CategoryName","","",""], '', '', [], [], [], [], [], [], false, '', '', "`CategoryName`");
                break;
        }
        $this->Category->SearchOperators = ["=", "<>", "IS NULL", "IS NOT NULL"];
        $this->Category->SourceTableVar = 'projecttask';
        $this->Category->SearchType = "dropdown";
        $this->Fields['Category'] = &$this->Category;

        // ProjectID
        $this->_ProjectID = new ReportField(
            $this, // Table
            'x__ProjectID', // Variable name
            'ProjectID', // Name
            '`ProjectID`', // Expression
            '`ProjectID`', // Basic search expression
            3, // Type
            11, // Size
            -1, // Date/Time format
            false, // Is upload field
            '`ProjectID`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'SELECT' // Edit Tag
        );
        $this->_ProjectID->InputTextType = "text";
        $this->_ProjectID->Raw = true;
        $this->_ProjectID->GroupingFieldId = 2;
        $this->_ProjectID->ShowGroupHeaderAsRow = $this->ShowGroupHeaderAsRow;
        $this->_ProjectID->ShowCompactSummaryFooter = $this->ShowCompactSummaryFooter;
        $this->_ProjectID->GroupByType = "";
        $this->_ProjectID->GroupInterval = "0";
        $this->_ProjectID->GroupSql = "";
        $this->_ProjectID->Required = true; // Required field
        $this->_ProjectID->setSelectMultiple(false); // Select one
        $this->_ProjectID->UsePleaseSelect = true; // Use PleaseSelect by default
        $this->_ProjectID->PleaseSelectText = $Language->phrase("PleaseSelect"); // "PleaseSelect" text
        $this->_ProjectID->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->_ProjectID->Lookup = new Lookup($this->_ProjectID, 'masterproject', true, 'ProjectID', ["ProjectName","","",""], '', '', [], ["x_AssignedTo"], [], [], [], [], false, '', '', "`ProjectName`");
                break;
            default:
                $this->_ProjectID->Lookup = new Lookup($this->_ProjectID, 'masterproject', true, 'ProjectID', ["ProjectName","","",""], '', '', [], ["x_AssignedTo"], [], [], [], [], false, '', '', "`ProjectName`");
                break;
        }
        $this->_ProjectID->DefaultErrorMessage = $Language->phrase("IncorrectInteger");
        $this->_ProjectID->SearchOperators = ["=", "<>", "<", "<=", ">", ">=", "BETWEEN", "NOT BETWEEN", "IS NULL", "IS NOT NULL"];
        $this->_ProjectID->SourceTableVar = 'projecttask';
        $this->_ProjectID->SearchType = "dropdown";
        $this->Fields['ProjectID'] = &$this->_ProjectID;

        // Created_Date
        $this->Created_Date = new ReportField(
            $this, // Table
            'x_Created_Date', // Variable name
            'Created_Date', // Name
            '`Created_Date`', // Expression
            CastDateFieldForLike("`Created_Date`", 109, "DB"), // Basic search expression
            135, // Type
            19, // Size
            109, // Date/Time format
            false, // Is upload field
            '`Created_Date`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'HIDDEN' // Edit Tag
        );
        $this->Created_Date->addMethod("getDefault", fn() => CurrentDateTime());
        $this->Created_Date->InputTextType = "text";
        $this->Created_Date->Raw = true;
        $this->Created_Date->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->Created_Date->Lookup = new Lookup($this->Created_Date, 'PerformanceReport', true, 'Created_Date', ["Created_Date","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
            default:
                $this->Created_Date->Lookup = new Lookup($this->Created_Date, 'PerformanceReport', true, 'Created_Date', ["Created_Date","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
        }
        $this->Created_Date->DefaultErrorMessage = str_replace("%s", DateFormat(109), $Language->phrase("IncorrectDate"));
        $this->Created_Date->SearchOperators = ["=", "<>", "IS NULL", "IS NOT NULL"];
        $this->Created_Date->SourceTableVar = 'projecttask';
        $this->Created_Date->SearchType = "dropdown";
        $this->Fields['Created_Date'] = &$this->Created_Date;

        // Created_By
        $this->Created_By = new ReportField(
            $this, // Table
            'x_Created_By', // Variable name
            'Created_By', // Name
            '`Created_By`', // Expression
            '`Created_By`', // Basic search expression
            200, // Type
            255, // Size
            -1, // Date/Time format
            false, // Is upload field
            '`Created_By`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'HIDDEN' // Edit Tag
        );
        $this->Created_By->addMethod("getDefault", fn() => CurrentUserName());
        $this->Created_By->InputTextType = "text";
        $this->Created_By->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->Created_By->Lookup = new Lookup($this->Created_By, 'PerformanceReport', true, 'Created_By', ["Created_By","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
            default:
                $this->Created_By->Lookup = new Lookup($this->Created_By, 'PerformanceReport', true, 'Created_By', ["Created_By","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
        }
        $this->Created_By->SearchOperators = ["=", "<>", "IS NULL", "IS NOT NULL"];
        $this->Created_By->SourceTableVar = 'projecttask';
        $this->Created_By->SearchType = "dropdown";
        $this->Fields['Created_By'] = &$this->Created_By;

        // Last_Updated_Date
        $this->Last_Updated_Date = new ReportField(
            $this, // Table
            'x_Last_Updated_Date', // Variable name
            'Last_Updated_Date', // Name
            '`Last_Updated_Date`', // Expression
            CastDateFieldForLike("`Last_Updated_Date`", 109, "DB"), // Basic search expression
            135, // Type
            19, // Size
            109, // Date/Time format
            false, // Is upload field
            '`Last_Updated_Date`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'HIDDEN' // Edit Tag
        );
        $this->Last_Updated_Date->addMethod("getAutoUpdateValue", fn() => CurrentDateTime());
        $this->Last_Updated_Date->addMethod("getDefault", fn() => CurrentDateTime());
        $this->Last_Updated_Date->InputTextType = "text";
        $this->Last_Updated_Date->Raw = true;
        $this->Last_Updated_Date->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->Last_Updated_Date->Lookup = new Lookup($this->Last_Updated_Date, 'PerformanceReport', true, 'Last_Updated_Date', ["Last_Updated_Date","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
            default:
                $this->Last_Updated_Date->Lookup = new Lookup($this->Last_Updated_Date, 'PerformanceReport', true, 'Last_Updated_Date', ["Last_Updated_Date","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
        }
        $this->Last_Updated_Date->DefaultErrorMessage = str_replace("%s", DateFormat(109), $Language->phrase("IncorrectDate"));
        $this->Last_Updated_Date->SearchOperators = ["=", "<>", "IS NULL", "IS NOT NULL"];
        $this->Last_Updated_Date->SourceTableVar = 'projecttask';
        $this->Last_Updated_Date->SearchType = "dropdown";
        $this->Fields['Last_Updated_Date'] = &$this->Last_Updated_Date;

        // Last_Updated_By
        $this->Last_Updated_By = new ReportField(
            $this, // Table
            'x_Last_Updated_By', // Variable name
            'Last_Updated_By', // Name
            '`Last_Updated_By`', // Expression
            '`Last_Updated_By`', // Basic search expression
            200, // Type
            255, // Size
            -1, // Date/Time format
            false, // Is upload field
            '`Last_Updated_By`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'HIDDEN' // Edit Tag
        );
        $this->Last_Updated_By->addMethod("getAutoUpdateValue", fn() => CurrentUserName());
        $this->Last_Updated_By->addMethod("getDefault", fn() => CurrentUserName());
        $this->Last_Updated_By->InputTextType = "text";
        $this->Last_Updated_By->UseFilter = true; // Table header filter
        global $CurrentLanguage;
        switch ($CurrentLanguage) {
            case "en-US":
                $this->Last_Updated_By->Lookup = new Lookup($this->Last_Updated_By, 'PerformanceReport', true, 'Last_Updated_By', ["Last_Updated_By","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
            default:
                $this->Last_Updated_By->Lookup = new Lookup($this->Last_Updated_By, 'PerformanceReport', true, 'Last_Updated_By', ["Last_Updated_By","","",""], '', '', [], [], [], [], [], [], false, '', '', "");
                break;
        }
        $this->Last_Updated_By->SearchOperators = ["=", "<>", "IS NULL", "IS NOT NULL"];
        $this->Last_Updated_By->SourceTableVar = 'projecttask';
        $this->Last_Updated_By->SearchType = "dropdown";
        $this->Fields['Last_Updated_By'] = &$this->Last_Updated_By;

        // Complete
        $this->Complete = new ReportField(
            $this, // Table
            'x_Complete', // Variable name
            'Complete', // Name
            '`Complete`', // Expression
            '`Complete`', // Basic search expression
            200, // Type
            13, // Size
            -1, // Date/Time format
            false, // Is upload field
            '`Complete`', // Virtual expression
            false, // Is virtual
            false, // Force selection
            false, // Is Virtual search
            'FORMATTED TEXT', // View Tag
            'TEXT' // Edit Tag
        );
        $this->Complete->InputTextType = "text";
        $this->Complete->SearchOperators = ["=", "<>", "IN", "NOT IN", "STARTS WITH", "NOT STARTS WITH", "LIKE", "NOT LIKE", "ENDS WITH", "NOT ENDS WITH", "IS EMPTY", "IS NOT EMPTY", "IS NULL", "IS NOT NULL"];
        $this->Complete->SourceTableVar = 'projecttask';
        $this->Fields['Complete'] = &$this->Complete;

        // Performance Report
        $this->PerformanceReport = new DbChart($this, 'PerformanceReport', 'Performance Report', 'Track', 'TaskID', 1006, '', 0, 'COUNT', 600, 500);
        $this->PerformanceReport->Position = 4;
        $this->PerformanceReport->PageBreakType = "before";
        $this->PerformanceReport->YAxisFormat = [""];
        $this->PerformanceReport->YFieldFormat = [""];
        $this->PerformanceReport->SortType = 0;
        $this->PerformanceReport->SortSequence = "";
        $this->PerformanceReport->SqlSelect = $this->getQueryBuilder()->select("CASE WHEN EndDate > PlanEnd THEN 'Late'
WHEN Progress<1 AND CURDATE()>PlanEnd THEN 'Late'
        WHEN Progress<(CASE
    WHEN PlanEnd IS NULL OR PlanStart IS NULL THEN 0
    ELSE LEAST(1.0, CAST(DATEDIFF(CURDATE(), PlanStart) AS FLOAT) / NULLIF(DATEDIFF(PlanEnd, PlanStart), 0))
END )THEN 'Warning'
        ELSE 'On Track'
    END", "''", "COUNT(`TaskID`)");
        $this->PerformanceReport->SqlGroupBy = "CASE WHEN EndDate > PlanEnd THEN 'Late'
WHEN Progress<1 AND CURDATE()>PlanEnd THEN 'Late'
        WHEN Progress<(CASE
    WHEN PlanEnd IS NULL OR PlanStart IS NULL THEN 0
    ELSE LEAST(1.0, CAST(DATEDIFF(CURDATE(), PlanStart) AS FLOAT) / NULLIF(DATEDIFF(PlanEnd, PlanStart), 0))
END )THEN 'Warning'
        ELSE 'On Track'
    END";
        $this->PerformanceReport->SqlOrderBy = "";
        $this->PerformanceReport->SeriesDateType = "";
        $this->PerformanceReport->ID = "PerformanceReport_PerformanceReport"; // Chart ID
        $this->PerformanceReport->setParameters([
            ["type", "1006"],
            ["seriestype", "0"]
        ]); // Chart type / Chart series type
        $this->PerformanceReport->setParameters([
            ["caption", $this->PerformanceReport->caption()],
            ["xaxisname", $this->PerformanceReport->xAxisName()]
        ]); // Chart caption / X axis name
        $this->PerformanceReport->setParameter("yaxisname", $this->PerformanceReport->yAxisName()); // Y axis name
        $this->PerformanceReport->setParameters([
            ["shownames", "1"],
            ["showvalues", "1"],
            ["showhovercap", "1"]
        ]); // Show names / Show values / Show hover
        $this->PerformanceReport->setParameter("alpha", DbChart::getDefaultAlpha()); // Chart alpha (datasets background color)
        $this->PerformanceReport->setParameters([["options.plugins.legend.display",true],["options.plugins.legend.fullWidth",false],["options.plugins.legend.reverse",false],["options.plugins.legend.rtl",false],["options.plugins.legend.labels.usePointStyle",false],["options.plugins.title.display",true],["options.plugins.tooltip.enabled",true],["options.plugins.tooltip.intersect",false],["options.plugins.tooltip.displayColors",false],["options.plugins.tooltip.rtl",false],["options.plugins.filler.propagate",false],["options.animation.animateRotate",false],["options.animation.animateScale",false],["options.scales.r.angleLines.display",false],["options.plugins.stacked100.enable",false],["dataset.showLine",false],["dataset.spanGaps",false],["dataset.steppedLine",false],["dataset.circular",false],["scale.offset",false],["scale.gridLines.offsetGridLines",false],["options.plugins.datalabels.clamp",false],["options.plugins.datalabels.clip",false],["options.plugins.datalabels.display",true],["annotation1.show",false],["annotation1.secondaryYAxis",false],["annotation2.show",false],["annotation2.secondaryYAxis",false],["annotation3.show",false],["annotation3.secondaryYAxis",false],["annotation4.show",false],["annotation4.secondaryYAxis",false]]);
        $this->Charts[$this->PerformanceReport->ID] = &$this->PerformanceReport;

        // TotalTask
        $this->TotalTask = new DbChart($this, 'TotalTask', 'TotalTask', 'AssignedTo', 'TaskID', 1001, '', 0, 'COUNT', 600, 500);
        $this->TotalTask->Position = 4;
        $this->TotalTask->PageBreakType = "before";
        $this->TotalTask->YAxisFormat = [""];
        $this->TotalTask->YFieldFormat = [""];
        $this->TotalTask->SortType = 4;
        $this->TotalTask->SortSequence = "";
        $this->TotalTask->SqlSelect = $this->getQueryBuilder()->select("`AssignedTo`", "''", "COUNT(`TaskID`)");
        $this->TotalTask->SqlGroupBy = "`AssignedTo`";
        $this->TotalTask->SqlOrderBy = "";
        $this->TotalTask->SeriesDateType = "";
        $this->TotalTask->ID = "PerformanceReport_TotalTask"; // Chart ID
        $this->TotalTask->setParameters([
            ["type", "1001"],
            ["seriestype", "0"]
        ]); // Chart type / Chart series type
        $this->TotalTask->setParameters([
            ["caption", $this->TotalTask->caption()],
            ["xaxisname", $this->TotalTask->xAxisName()]
        ]); // Chart caption / X axis name
        $this->TotalTask->setParameter("yaxisname", $this->TotalTask->yAxisName()); // Y axis name
        $this->TotalTask->setParameters([
            ["shownames", "1"],
            ["showvalues", "1"],
            ["showhovercap", "1"]
        ]); // Show names / Show values / Show hover
        $this->TotalTask->setParameter("alpha", DbChart::getDefaultAlpha()); // Chart alpha (datasets background color)
        $this->TotalTask->setParameters([["options.plugins.legend.display",true],["options.plugins.legend.fullWidth",false],["options.plugins.legend.reverse",false],["options.plugins.legend.rtl",false],["options.plugins.legend.labels.usePointStyle",false],["options.plugins.title.display",true],["options.plugins.tooltip.enabled",true],["options.plugins.tooltip.intersect",false],["options.plugins.tooltip.displayColors",false],["options.plugins.tooltip.rtl",false],["options.plugins.filler.propagate",false],["options.animation.animateRotate",false],["options.animation.animateScale",false],["options.scales.r.angleLines.display",false],["options.plugins.stacked100.enable",false],["dataset.showLine",false],["dataset.spanGaps",false],["dataset.steppedLine",false],["dataset.circular",false],["scale.offset",false],["scale.gridLines.offsetGridLines",false],["options.plugins.datalabels.clamp",false],["options.plugins.datalabels.clip",false],["options.plugins.datalabels.display",true],["annotation1.show",false],["annotation1.startValue",0],["annotation1.alpha",1],["annotation1.secondaryYAxis",false],["annotation2.show",false],["annotation2.secondaryYAxis",false],["annotation3.show",false],["annotation3.secondaryYAxis",false],["annotation4.show",false],["annotation4.secondaryYAxis",false]]);
        $this->Charts[$this->TotalTask->ID] = &$this->TotalTask;

        // Add Doctrine Cache
        $this->Cache = new \Symfony\Component\Cache\Adapter\ArrayAdapter();
        $this->CacheProfile = new \Doctrine\DBAL\Cache\QueryCacheProfile(0, $this->TableVar);

        // Call Table Load event
        $this->tableLoad();
    }

    // Field Visibility
    public function getFieldVisibility($fldParm)
    {
        global $Security;
        return $this->$fldParm->Visible; // Returns original value
    }

    // Single column sort
    protected function updateSort(&$fld)
    {
        if ($this->CurrentOrder == $fld->Name) {
            $sortField = $fld->Expression;
            $lastSort = $fld->getSort();
            if (in_array($this->CurrentOrderType, ["ASC", "DESC", "NO"])) {
                $curSort = $this->CurrentOrderType;
            } else {
                $curSort = $lastSort;
            }
            $fld->setSort($curSort);
            $lastOrderBy = in_array($lastSort, ["ASC", "DESC"]) ? $sortField . " " . $lastSort : "";
            $curOrderBy = in_array($curSort, ["ASC", "DESC"]) ? $sortField . " " . $curSort : "";
            if ($fld->GroupingFieldId == 0) {
                $this->setDetailOrderBy($curOrderBy); // Save to Session
            }
        } else {
            if ($fld->GroupingFieldId == 0) {
                $fld->setSort("");
            }
        }
    }

    // Get Sort SQL
    protected function sortSql()
    {
        $dtlSortSql = $this->getDetailOrderBy(); // Get ORDER BY for detail fields from session
        $argrps = [];
        foreach ($this->Fields as $fld) {
            if (in_array($fld->getSort(), ["ASC", "DESC"])) {
                $fldsql = $fld->Expression;
                if ($fld->GroupingFieldId > 0) {
                    if ($fld->GroupSql != "") {
                        $argrps[$fld->GroupingFieldId] = str_replace("%s", $fldsql, $fld->GroupSql) . " " . $fld->getSort();
                    } else {
                        $argrps[$fld->GroupingFieldId] = $fldsql . " " . $fld->getSort();
                    }
                }
            }
        }
        $sortSql = "";
        foreach ($argrps as $grp) {
            if ($sortSql != "") {
                $sortSql .= ", ";
            }
            $sortSql .= $grp;
        }
        if ($dtlSortSql != "") {
            if ($sortSql != "") {
                $sortSql .= ", ";
            }
            $sortSql .= $dtlSortSql;
        }
        return $sortSql;
    }

    // Table Level Group SQL
    private $sqlFirstGroupField = "";
    private $sqlSelectGroup = null;
    private $sqlOrderByGroup = "";

    // First Group Field
    public function getSqlFirstGroupField($alias = false)
    {
        if ($this->sqlFirstGroupField != "") {
            return $this->sqlFirstGroupField;
        }
        $firstGroupField = &$this->AssignedTo;
        $expr = $firstGroupField->Expression;
        if ($firstGroupField->GroupSql != "") {
            $expr = str_replace("%s", $firstGroupField->Expression, $firstGroupField->GroupSql);
            if ($alias) {
                $expr .= " AS " . QuotedName($firstGroupField->getGroupName(), $this->Dbid);
            }
        }
        return $expr;
    }

    public function setSqlFirstGroupField($v)
    {
        $this->sqlFirstGroupField = $v;
    }

    // Select Group
    public function getSqlSelectGroup()
    {
        return $this->sqlSelectGroup ?? $this->getQueryBuilder()->select($this->getSqlFirstGroupField(true))->distinct();
    }

    public function setSqlSelectGroup($v)
    {
        $this->sqlSelectGroup = $v;
    }

    // Order By Group
    public function getSqlOrderByGroup()
    {
        if ($this->sqlOrderByGroup != "") {
            return $this->sqlOrderByGroup;
        }
        return $this->getSqlFirstGroupField() . " ASC";
    }

    public function setSqlOrderByGroup($v)
    {
        $this->sqlOrderByGroup = $v;
    }

    // Summary properties
    private $sqlSelectAggregate = null;
    private $sqlAggregatePrefix = "";
    private $sqlAggregateSuffix = "";
    private $sqlSelectCount = null;

    // Select Aggregate
    public function getSqlSelectAggregate()
    {
        return $this->sqlSelectAggregate ?? $this->getQueryBuilder()->select("COUNT(*) AS cnt_taskid");
    }

    public function setSqlSelectAggregate($v)
    {
        $this->sqlSelectAggregate = $v;
    }

    // Aggregate Prefix
    public function getSqlAggregatePrefix()
    {
        return ($this->sqlAggregatePrefix != "") ? $this->sqlAggregatePrefix : "";
    }

    public function setSqlAggregatePrefix($v)
    {
        $this->sqlAggregatePrefix = $v;
    }

    // Aggregate Suffix
    public function getSqlAggregateSuffix()
    {
        return ($this->sqlAggregateSuffix != "") ? $this->sqlAggregateSuffix : "";
    }

    public function setSqlAggregateSuffix($v)
    {
        $this->sqlAggregateSuffix = $v;
    }

    // Select Count
    public function getSqlSelectCount()
    {
        return $this->sqlSelectCount ?? $this->getQueryBuilder()->select("COUNT(*)");
    }

    public function setSqlSelectCount($v)
    {
        $this->sqlSelectCount = $v;
    }

    // Render for lookup
    public function renderLookup()
    {
        $this->PlanEnd->ViewValue = FormatDateTime($this->PlanEnd->CurrentValue, $this->PlanEnd->formatPattern());
        $this->EndDate->ViewValue = FormatDateTime($this->EndDate->CurrentValue, $this->EndDate->formatPattern());
    }

    // Render X Axis for chart
    public function renderChartXAxis($chartVar, $chartRow)
    {
        if ($chartVar == "TotalTask") {
            $this->AssignedTo->CurrentValue = $chartRow[0];
            $curVal = strval($this->AssignedTo->CurrentValue);
            if ($curVal != "") {
                $this->AssignedTo->ViewValue = $this->AssignedTo->lookupCacheOption($curVal);
                if ($this->AssignedTo->ViewValue === null) { // Lookup from database
                    $filterWrk = SearchFilter($this->AssignedTo->Lookup->getTable()->Fields["EmployeeID"]->searchExpression(), "=", $curVal, $this->AssignedTo->Lookup->getTable()->Fields["EmployeeID"]->searchDataType(), "");
                    $sqlWrk = $this->AssignedTo->Lookup->getSql(false, $filterWrk, '', $this, true, true);
                    $conn = Conn();
                    $config = $conn->getConfiguration();
                    $config->setResultCache($this->Cache);
                    $rswrk = $conn->executeCacheQuery($sqlWrk, [], [], $this->CacheProfile)->fetchAll();
                    $ari = count($rswrk);
                    if ($ari > 0) { // Lookup values found
                        $arwrk = $this->AssignedTo->Lookup->renderViewRow($rswrk[0]);
                        $this->AssignedTo->ViewValue = $this->AssignedTo->displayValue($arwrk);
                    } else {
                        $this->AssignedTo->ViewValue = FormatNumber($this->AssignedTo->CurrentValue, $this->AssignedTo->formatPattern());
                    }
                }
            } else {
                $this->AssignedTo->ViewValue = null;
            }
            $chartRow[0] = is_object($this->AssignedTo->ViewValue) ? $this->AssignedTo->ViewValue->__toString() : $this->AssignedTo->ViewValue;
        }
        return $chartRow;
    }

    // Get FROM clause
    public function getSqlFrom()
    {
        return ($this->SqlFrom != "") ? $this->SqlFrom : "projecttask";
    }

    // Get FROM clause (for backward compatibility)
    public function sqlFrom()
    {
        return $this->getSqlFrom();
    }

    // Set FROM clause
    public function setSqlFrom($v)
    {
        $this->SqlFrom = $v;
    }

    // Get SELECT clause
    public function getSqlSelect()
    {
        if ($this->SqlSelect) {
            return $this->SqlSelect;
        }
        $select = $this->getQueryBuilder()->select($this->sqlSelectFields());
        $groupField = &$this->AssignedTo;
        if ($groupField->GroupSql != "") {
            $expr = str_replace("%s", $groupField->Expression, $groupField->GroupSql) . " AS " . QuotedName($groupField->getGroupName(), $this->Dbid);
            $select->addSelect($expr);
        }
        $groupField = &$this->_ProjectID;
        if ($groupField->GroupSql != "") {
            $expr = str_replace("%s", $groupField->Expression, $groupField->GroupSql) . " AS " . QuotedName($groupField->getGroupName(), $this->Dbid);
            $select->addSelect($expr);
        }
        return $select;
    }

    // Get list of fields
    private function sqlSelectFields()
    {
        return "*, IF(Progress>=1,'Complete','Not Completed') AS Complete, CASE
    WHEN PlanEnd IS NULL OR PlanStart IS NULL THEN 0
    ELSE LEAST(1.0, CAST(DATEDIFF(CURDATE(), PlanStart) AS FLOAT) / NULLIF(DATEDIFF(PlanEnd, PlanStart), 0))
END AS Target, CASE WHEN EndDate > PlanEnd THEN 'Late'
WHEN Progress<1 AND CURDATE()>PlanEnd THEN 'Late'
        WHEN Progress<(CASE
    WHEN PlanEnd IS NULL OR PlanStart IS NULL THEN 0
    ELSE LEAST(1.0, CAST(DATEDIFF(CURDATE(), PlanStart) AS FLOAT) / NULLIF(DATEDIFF(PlanEnd, PlanStart), 0))
END )THEN 'Warning'
        ELSE 'On Track'
    END AS Track, CASE
    WHEN PlanEnd IS NULL OR PlanStart IS NULL THEN 0
    ELSE LEAST(1.0, CAST(DATEDIFF(CURDATE(), PlanStart) AS FLOAT) / NULLIF(DATEDIFF(PlanEnd, PlanStart), 0))
END AS `Target`, CASE WHEN EndDate > PlanEnd THEN 'Late'
WHEN Progress<1 AND CURDATE()>PlanEnd THEN 'Late'
        WHEN Progress<(CASE
    WHEN PlanEnd IS NULL OR PlanStart IS NULL THEN 0
    ELSE LEAST(1.0, CAST(DATEDIFF(CURDATE(), PlanStart) AS FLOAT) / NULLIF(DATEDIFF(PlanEnd, PlanStart), 0))
END )THEN 'Warning'
        ELSE 'On Track'
    END AS `Track`";
    }

    // Get SELECT clause (for backward compatibility)
    public function sqlSelect()
    {
        return $this->getSqlSelect();
    }

    // Set SELECT clause
    public function setSqlSelect($v)
    {
        $this->SqlSelect = $v;
    }

    // Get WHERE clause
    public function getSqlWhere()
    {
        $where = ($this->SqlWhere != "") ? $this->SqlWhere : "";
        $this->DefaultFilter = "";
        AddFilter($where, $this->DefaultFilter);
        return $where;
    }

    // Get WHERE clause (for backward compatibility)
    public function sqlWhere()
    {
        return $this->getSqlWhere();
    }

    // Set WHERE clause
    public function setSqlWhere($v)
    {
        $this->SqlWhere = $v;
    }

    // Get GROUP BY clause
    public function getSqlGroupBy()
    {
        return $this->SqlGroupBy != "" ? $this->SqlGroupBy : "";
    }

    // Get GROUP BY clause (for backward compatibility)
    public function sqlGroupBy()
    {
        return $this->getSqlGroupBy();
    }

    // set GROUP BY clause
    public function setSqlGroupBy($v)
    {
        $this->SqlGroupBy = $v;
    }

    // Get HAVING clause
    public function getSqlHaving() // Having
    {
        return ($this->SqlHaving != "") ? $this->SqlHaving : "";
    }

    // Get HAVING clause (for backward compatibility)
    public function sqlHaving()
    {
        return $this->getSqlHaving();
    }

    // Set HAVING clause
    public function setSqlHaving($v)
    {
        $this->SqlHaving = $v;
    }

    // Get ORDER BY clause
    public function getSqlOrderBy()
    {
        return ($this->SqlOrderBy != "") ? $this->SqlOrderBy : "";
    }

    // Get ORDER BY clause (for backward compatibility)
    public function sqlOrderBy()
    {
        return $this->getSqlOrderBy();
    }

    // set ORDER BY clause
    public function setSqlOrderBy($v)
    {
        $this->SqlOrderBy = $v;
    }

    // Apply User ID filters
    public function applyUserIDFilters($filter, $id = "")
    {
        return $filter;
    }

    // Check if User ID security allows view all
    public function userIDAllow($id = "")
    {
        $allow = $this->UserIDAllowSecurity;
        switch ($id) {
            case "add":
            case "copy":
            case "gridadd":
            case "register":
            case "addopt":
                return ($allow & Allow::ADD->value) == Allow::ADD->value;
            case "edit":
            case "gridedit":
            case "update":
            case "changepassword":
            case "resetpassword":
                return ($allow & Allow::EDIT->value) == Allow::EDIT->value;
            case "delete":
                return ($allow & Allow::DELETE->value) == Allow::DELETE->value;
            case "view":
                return ($allow & Allow::VIEW->value) == Allow::VIEW->value;
            case "search":
                return ($allow & Allow::SEARCH->value) == Allow::SEARCH->value;
            case "lookup":
                return ($allow & Allow::LOOKUP->value) == Allow::LOOKUP->value;
            default:
                return ($allow & Allow::LIST->value) == Allow::LIST->value;
        }
    }

    /**
     * Get record count
     *
     * @param string|QueryBuilder $sql SQL or QueryBuilder
     * @param mixed $c Connection
     * @return int
     */
    public function getRecordCount($sql, $c = null)
    {
        $cnt = -1;
        $sqlwrk = $sql instanceof QueryBuilder // Query builder
            ? (clone $sql)->resetQueryPart("orderBy")->getSQL()
            : $sql;
        $pattern = '/^SELECT\s([\s\S]+)\sFROM\s/i';
        // Skip Custom View / SubQuery / SELECT DISTINCT / ORDER BY
        if (
            in_array($this->TableType, ["TABLE", "VIEW", "LINKTABLE"]) &&
            preg_match($pattern, $sqlwrk) &&
            !preg_match('/\(\s*(SELECT[^)]+)\)/i', $sqlwrk) &&
            !preg_match('/^\s*SELECT\s+DISTINCT\s+/i', $sqlwrk) &&
            !preg_match('/\s+ORDER\s+BY\s+/i', $sqlwrk)
        ) {
            $sqlcnt = "SELECT COUNT(*) FROM " . preg_replace($pattern, "", $sqlwrk);
        } else {
            $sqlcnt = "SELECT COUNT(*) FROM (" . $sqlwrk . ") COUNT_TABLE";
        }
        $conn = $c ?? $this->getConnection();
        $cnt = $conn->fetchOne($sqlcnt);
        if ($cnt !== false) {
            return (int)$cnt;
        }
        // Unable to get count by SELECT COUNT(*), execute the SQL to get record count directly
        $result = $conn->executeQuery($sqlwrk);
        $cnt = $result->rowCount();
        if ($cnt == 0) { // Unable to get record count, count directly
            while ($result->fetch()) {
                $cnt++;
            }
        }
        return $cnt;
    }

    // Record filter WHERE clause
    protected function sqlKeyFilter()
    {
        return "`TaskID` = @TaskID@";
    }

    // Get Key
    public function getKey($current = false, $keySeparator = null)
    {
        $keys = [];
        $val = $current ? $this->TaskID->CurrentValue : $this->TaskID->OldValue;
        if (EmptyValue($val)) {
            return "";
        } else {
            $keys[] = $val;
        }
        $keySeparator ??= Config("COMPOSITE_KEY_SEPARATOR");
        return implode($keySeparator, $keys);
    }

    // Set Key
    public function setKey($key, $current = false, $keySeparator = null)
    {
        $keySeparator ??= Config("COMPOSITE_KEY_SEPARATOR");
        $this->OldKey = strval($key);
        $keys = explode($keySeparator, $this->OldKey);
        if (count($keys) == 1) {
            if ($current) {
                $this->TaskID->CurrentValue = $keys[0];
            } else {
                $this->TaskID->OldValue = $keys[0];
            }
        }
    }

    // Get record filter
    public function getRecordFilter($row = null, $current = false)
    {
        $keyFilter = $this->sqlKeyFilter();
        if (is_array($row)) {
            $val = array_key_exists('TaskID', $row) ? $row['TaskID'] : null;
        } else {
            $val = !EmptyValue($this->TaskID->OldValue) && !$current ? $this->TaskID->OldValue : $this->TaskID->CurrentValue;
        }
        if (!is_numeric($val)) {
            return "0=1"; // Invalid key
        }
        if ($val === null) {
            return "0=1"; // Invalid key
        } else {
            $keyFilter = str_replace("@TaskID@", AdjustSql($val, $this->Dbid), $keyFilter); // Replace key value
        }
        return $keyFilter;
    }

    // Return page URL
    public function getReturnUrl()
    {
        $referUrl = ReferUrl();
        $referPageName = ReferPageName();
        $name = PROJECT_NAME . "_" . $this->TableVar . "_" . Config("TABLE_RETURN_URL");
        // Get referer URL automatically
        if ($referUrl != "" && $referPageName != CurrentPageName() && $referPageName != "login") { // Referer not same page or login page
            $_SESSION[$name] = $referUrl; // Save to Session
        }
        return $_SESSION[$name] ?? GetUrl("");
    }

    // Set return page URL
    public function setReturnUrl($v)
    {
        $_SESSION[PROJECT_NAME . "_" . $this->TableVar . "_" . Config("TABLE_RETURN_URL")] = $v;
    }

    // Get modal caption
    public function getModalCaption($pageName)
    {
        global $Language;
        return match ($pageName) {
            "" => $Language->phrase("View"),
            "" => $Language->phrase("Edit"),
            "" => $Language->phrase("Add"),
            default => ""
        };
    }

    // Default route URL
    public function getDefaultRouteUrl()
    {
        return "performancereport";
    }

    // API page name
    public function getApiPageName($action)
    {
        return "PerformanceReportSummary";
    }

    // Current URL
    public function getCurrentUrl($parm = "")
    {
        $url = CurrentPageUrl(false);
        if ($parm != "") {
            $url = $this->keyUrl($url, $parm);
        } else {
            $url = $this->keyUrl($url, Config("TABLE_SHOW_DETAIL") . "=");
        }
        return $this->addMasterUrl($url);
    }

    // List URL
    public function getListUrl()
    {
        return "";
    }

    // View URL
    public function getViewUrl($parm = "")
    {
        if ($parm != "") {
            $url = $this->keyUrl("", $parm);
        } else {
            $url = $this->keyUrl("", Config("TABLE_SHOW_DETAIL") . "=");
        }
        return $this->addMasterUrl($url);
    }

    // Add URL
    public function getAddUrl($parm = "")
    {
        if ($parm != "") {
            $url = "?" . $parm;
        } else {
            $url = "";
        }
        return $this->addMasterUrl($url);
    }

    // Edit URL
    public function getEditUrl($parm = "")
    {
        $url = $this->keyUrl("", $parm);
        return $this->addMasterUrl($url);
    }

    // Inline edit URL
    public function getInlineEditUrl()
    {
        $url = $this->keyUrl("", "action=edit");
        return $this->addMasterUrl($url);
    }

    // Copy URL
    public function getCopyUrl($parm = "")
    {
        $url = $this->keyUrl("", $parm);
        return $this->addMasterUrl($url);
    }

    // Inline copy URL
    public function getInlineCopyUrl()
    {
        $url = $this->keyUrl("", "action=copy");
        return $this->addMasterUrl($url);
    }

    // Delete URL
    public function getDeleteUrl($parm = "")
    {
        if ($this->UseAjaxActions && ConvertToBool(Param("infinitescroll")) && CurrentPageID() == "list") {
            return $this->keyUrl(GetApiUrl(Config("API_DELETE_ACTION") . "/" . $this->TableVar));
        } else {
            return $this->keyUrl("", $parm);
        }
    }

    // Add master url
    public function addMasterUrl($url)
    {
        return $url;
    }

    public function keyToJson($htmlEncode = false)
    {
        $json = "";
        $json .= "\"TaskID\":" . VarToJson($this->TaskID->CurrentValue, "number");
        $json = "{" . $json . "}";
        if ($htmlEncode) {
            $json = HtmlEncode($json);
        }
        return $json;
    }

    // Add key value to URL
    public function keyUrl($url, $parm = "")
    {
        if ($this->TaskID->CurrentValue !== null) {
            $url .= "/" . $this->encodeKeyValue($this->TaskID->CurrentValue);
        } else {
            return "javascript:ew.alert(ew.language.phrase('InvalidRecord'));";
        }
        if ($parm != "") {
            $url .= "?" . $parm;
        }
        return $url;
    }

    // Render sort
    public function renderFieldHeader($fld)
    {
        global $Security, $Language;
        $sortUrl = "";
        $attrs = "";
        if ($this->PageID != "grid" && $fld->Sortable) {
            $sortUrl = $this->sortUrl($fld);
            $attrs = ' role="button" data-ew-action="sort" data-ajax="' . ($this->UseAjaxActions ? "true" : "false") . '" data-sort-url="' . $sortUrl . '" data-sort-type="1"';
            if ($this->ContextClass) { // Add context
                $attrs .= ' data-context="' . HtmlEncode($this->ContextClass) . '"';
            }
        }
        $html = '<div class="ew-table-header-caption"' . $attrs . '>' . $fld->caption() . '</div>';
        if ($sortUrl) {
            $html .= '<div class="ew-table-header-sort">' . $fld->getSortIcon() . '</div>';
        }
        if ($this->PageID != "grid" && !$this->isExport() && $fld->UseFilter && $Security->canSearch()) {
            $html .= '<div class="ew-filter-dropdown-btn" data-ew-action="filter" data-table="' . $fld->TableVar . '" data-field="' . $fld->FieldVar .
                '"><div class="ew-table-header-filter" role="button" aria-haspopup="true">' . $Language->phrase("Filter") .
                (is_array($fld->EditValue) ? str_replace("%c", count($fld->EditValue), $Language->phrase("FilterCount")) : '') .
                '</div></div>';
        }
        $html = '<div class="ew-table-header-btn">' . $html . '</div>';
        if ($this->UseCustomTemplate) {
            $scriptId = str_replace("{id}", $fld->TableVar . "_" . $fld->Param, "tpc_{id}");
            $html = '<template id="' . $scriptId . '">' . $html . '</template>';
        }
        return $html;
    }

    // Sort URL
    public function sortUrl($fld)
    {
        global $DashboardReport;
        if (
            $this->CurrentAction || $this->isExport() ||
            $this->DrillDown ||
            in_array($fld->Type, [128, 204, 205])
        ) { // Unsortable data type
                return "";
        } elseif ($fld->Sortable) {
            $urlParm = "order=" . urlencode($fld->Name) . "&amp;ordertype=" . $fld->getNextSort();
            if ($DashboardReport) {
                $urlParm .= "&amp;" . Config("PAGE_DASHBOARD") . "=" . $DashboardReport;
            }
            return $this->addMasterUrl($this->CurrentPageName . "?" . $urlParm);
        } else {
            return "";
        }
    }

    // Get record keys from Post/Get/Session
    public function getRecordKeys()
    {
        $arKeys = [];
        $arKey = [];
        if (Param("key_m") !== null) {
            $arKeys = Param("key_m");
            $cnt = count($arKeys);
        } else {
            $isApi = IsApi();
            $keyValues = $isApi
                ? (Route(0) == "export"
                    ? array_map(fn ($i) => Route($i + 3), range(0, 0))  // Export API
                    : array_map(fn ($i) => Route($i + 2), range(0, 0))) // Other API
                : []; // Non-API
            if (($keyValue = Param("TaskID") ?? Route("TaskID")) !== null) {
                $arKeys[] = $keyValue;
            } elseif ($isApi && (($keyValue = Key(0) ?? $keyValues[0] ?? null) !== null)) {
                $arKeys[] = $keyValue;
            } else {
                $arKeys = null; // Do not setup
            }
        }
        // Check keys
        $ar = [];
        if (is_array($arKeys)) {
            foreach ($arKeys as $key) {
                if (!is_numeric($key)) {
                    continue;
                }
                $ar[] = $key;
            }
        }
        return $ar;
    }

    // Get filter from records
    public function getFilterFromRecords($rows)
    {
        $keyFilter = "";
        foreach ($rows as $row) {
            if ($keyFilter != "") {
                $keyFilter .= " OR ";
            }
            $keyFilter .= "(" . $this->getRecordFilter($row) . ")";
        }
        return $keyFilter;
    }

    // Get filter from record keys
    public function getFilterFromRecordKeys($setCurrent = true)
    {
        $arKeys = $this->getRecordKeys();
        $keyFilter = "";
        foreach ($arKeys as $key) {
            if ($keyFilter != "") {
                $keyFilter .= " OR ";
            }
            if ($setCurrent) {
                $this->TaskID->CurrentValue = $key;
            } else {
                $this->TaskID->OldValue = $key;
            }
            $keyFilter .= "(" . $this->getRecordFilter() . ")";
        }
        return $keyFilter;
    }

    // Load result set based on filter/sort
    public function loadRs($filter, $sort = "")
    {
        $sql = $this->getSql($filter, $sort); // Set up filter (WHERE Clause) / sort (ORDER BY Clause)
        $conn = $this->getConnection();
        return $conn->executeQuery($sql);
    }

    // Get file data
    public function getFileData($fldparm, $key, $resize, $width = 0, $height = 0, $plugins = [])
    {
        global $DownloadFileName;

        // No binary fields
        return false;
    }

    // Table level events

    // Table Load event
    public function tableLoad()
    {
        // Enter your code here
    }

    // Email Sending event
    public function emailSending($email, $args)
    {
        //var_dump($email, $args); exit();
        return true;
    }

    // Lookup Selecting event
    public function lookupSelecting($fld, &$filter)
    {
        //var_dump($fld->Name, $fld->Lookup, $filter); // Uncomment to view the filter
        // Enter your code here
    }

    // Row Rendering event
    public function rowRendering()
    {
        // Enter your code here
    }

    // Row Rendered event
    public function rowRendered()
    {
        $progress = floatval($this->Progress->CurrentValue);
        $target = floatval($this->Target->CurrentValue);
        $planStart = $this->PlanStart->CurrentValue;
        $planEnd = $this->PlanEnd->CurrentValue;
        $today = CurrentDate();// Membuat objek DateTime
        if ($progress == 1) {
             $this->Target->CellAttrs["class"] = "table-bg-success";
        }
        // Ganti warna latar belakang kolom Progress sesuai kondisi
        else if ($today > $planEnd && $progress < 1) {
            // Warna merah
            $this->Progress->CellAttrs["class"] = "table-bg-danger";
        } else if ($target >= $progress) {
            // Warna kuning
            $this->Progress->CellAttrs["class"] = "table-bg-warning";
        } else {
            // Warna hijau
            $this->Progress->CellAttrs["class"] = "table-bg-success";
        }
    }

    // User ID Filtering event
    public function userIdFiltering(&$filter)
    {
        // Enter your code here
    }
}
