// Displays orders in the grid. Allows the user
// to sort the entries, filter their search, and search for a specific person.
// Authors:
// Cameron Hayes
// Mac Stephens

unit View.Orders;

interface

uses
  System.SysUtils, System.Generics.Collections, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
  WEBLib.Forms, WEBLib.Dialogs, WEBLib.Menus, WEBLib.ExtCtrls, WEBLib.StdCtrls,
  WEBLib.JSON, Auth.Service, XData.Web.Client, WebLib.Storage,
  ConnectionModule, App.Types, Vcl.StdCtrls, Vcl.Controls, WEBLib.DBCtrls,
  XData.Web.JsonDataset, WEBLib.DB, Data.DB, XData.Web.Dataset,
  WEBLib.Grids;

type
  TFViewOrders = class(TWebForm)
    XDataWebClient1: TXDataWebClient;
    xdwdsOrders: TXDataWebDataSet;
    lblEntries: TWebLabel;
    wdsOrders: TWebDataSource;
    xdwdsOrderscompanyName: TStringField;
    xdwdsOrdersjobName: TStringField;
    xdwdsOrdersorderDate: TStringField;
    xdwdsOrdersproofDue: TStringField;
    xdwdsOrdersproofDone: TStringField;
    xdwdsOrdersartDue: TStringField;
    xdwdsOrdersartDone: TStringField;
    xdwdsOrdersmountDue: TStringField;
    xdwdsOrdersmountDone: TStringField;
    xdwdsOrdersshipDue: TStringField;
    xdwdsOrdersshipDone: TStringField;
    xdwdsOrdersprice: TStringField;
    xdwdsOrdersID: TStringField;
    xdwdsOrdersqbRefNum: TStringField;
    xdwdsOrderscolors: TStringField;
    btnAddOrder: TWebButton;
    btnSearch: TWebButton;
    xdwdsOrdersplateDue: TStringField;
    xdwdsOrdersplateDone: TStringField;
    xdwdsOrdersorderType: TStringField;
    pnlMessage: TWebPanel;
    lblMessage: TWebLabel;
    btnCloseNotification: TWebButton;
    WebButton1: TWebButton;
    btnPDF: TWebButton;
    wdsCustomers: TWebDataSource;
    xdwdsCustomers: TXDataWebDataSet;
    xdwdsCustomersNAME: TStringField;
    xdwdsCustomersID: TIntegerField;
    xdwdsCustomersCURR_ID: TIntegerField;
    xdwdsSave: TXDataWebDataSet;
    wdsSave: TWebDataSource;
    xdwdsSaveCURR_ID: TIntegerField;
    wdbtcOrders: TWebDBTableControl;
    wcbPageSize: TWebComboBox;
    wlcbOrderBy: TWebLookupComboBox;
    lblSearch: TWebLabel;
    procedure WebFormCreate(Sender: TObject);
    procedure btnAddOrderClick(Sender: TObject);
    procedure btnSearchClick(Sender: TObject);
    procedure btnCloseNotificationClick(Sender: TObject);
    procedure WebFormShow(Sender: TObject);
    procedure btnConfirmClick(Sender: TObject);
    procedure btnPDFClick(Sender: TObject);
    procedure wcbPageSizeChange(Sender: TObject);
    procedure wlcbOrderByChange(Sender: TObject);
  private
    FChildForm: TWebForm;
    procedure ClearTable();
    procedure GeneratePagination(TotalPages: Integer);
    function GenerateSearchOptions(): string;
    procedure orderEntry(orderInfo, customerInfo, mode: string);
    procedure HideNotification();
    procedure ShowNotification(Notification: string);
    procedure ShowAddOrderForm();
    procedure ShowSearchForm();
    [async] procedure Search(searchOptions: string);
    [async] procedure GetOrders(searchOptions: string);
    [async] procedure getUser();
    procedure GeneratePDF(OrderID: string);
    [async] procedure GenerateReportPDF;
    var
      PageNumber: integer;
      PageSize: integer;
      TotalPages: integer;
      OrderID: string;
      CompanyID: string;
      JobName: string;
      orderType: string;

      //Status 1
      StartDate1: string;
      EndDate1: string;
      filterType1: string;
      null1: boolean;

      //Status 2
      StartDate2: string;
      EndDate2: string;
      filterType2: string;
      null2: boolean;

      OrderBy: string;
      filters: boolean;
      info: string;
  public
    class function CreateForm(AElementID, Info: string): TWebForm;

  end;

var
  FViewOrders: TFViewOrders;

implementation

uses
  XData.Model.Classes, View.Main, View.AddOrder, View.Search, View.PDF;

{$R *.dfm}

procedure TFViewOrders.btnPDFClick(Sender: TObject);
begin
  GenerateReportPDF;
end;

[async] procedure TFViewOrders.GenerateReportPDF;
var
  xdcResponse: TXDataClientResponse;
  searchOptions, pdfURL: string;
  jsObject: TJSObject;
begin
  searchOptions := GenerateSearchOptions;

  // Call the server method to generate the PDF
  xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GenerateReportPDF', [searchOptions]));
  jsObject := JS.TJSObject(xdcResponse.Result);
  pdfURL := JS.toString(jsObject.Properties['value']);

  // Open the PDF in a new browser tab without needing a different form
  // This method is much faster too, even for large datasets
  window.open(pdfURL, '_blank');
end;



procedure TFViewOrders.WebFormCreate(Sender: TObject);
// Initializes important values:
// PageNumber: What page number the user is on IE 1: 1-10, 2: 11-20 etc
// TotalPages: Total number of pages returned from the search.
// PageSize: Number of entries per page.
var
  today: TDateTime;
begin
  DMConnection.ApiConnection.Connected := True;
  PageNumber := 1;
  TotalPages := 1; // Initial total pages

  //Status 1
  startDate1 := FormatDateTime('yyyy/mm/dd', 0);
  endDate1 := FormatDateTime('yyyy/mm/dd', 0);
  filterType1 := '';
  null1 := false;

  //Status 2
  startDate2 := FormatDateTime('yyyy/mm/dd', 0);
  endDate2 := FormatDateTime('yyyy/mm/dd', 0);
  filterType2 := '';
  null2 := false;

  orderType := '';

  //today := TDateTime.Today;
  wcbPageSize.Text := '500';
  PageSize := 500;
  wlcbOrderBy.DisplayText := 'Order Date';
  OrderBy := 'o.ORDER_DATE DESC';
  getOrders(GenerateSearchOptions());
end;


procedure TFViewOrders.WebFormShow(Sender: TObject);
begin
  if info <> '' then
    ShowNotification(info)
  else
    HideNotification();
end;


procedure TFViewOrders.wlcbOrderByChange(Sender: TObject);
begin
  OrderBy := wlcbOrderBy.Value;
  getOrders(generateSearchOptions());
end;

procedure TFViewOrders.getUser();
var
  xdcResponse: TXDataClientResponse;
  userList, user: TJSObject;
  data: TJSArray;
begin
  xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetUsers',
        [JS.toString(AuthService.TokenPayload.Properties['user_name'])]));
  userList :=  TJSObject(xdcResponse.Result);
  data := TJSArray(userList['data']);
  user := TJSObject(data[0]);
end;


class function TFViewOrders.CreateForm(AElementID, Info: string): TWebForm;
var
  localInfo: string;
begin
  localInfo := info;
  Application.CreateForm(TFViewOrders, AElementID, Result,
    procedure(AForm: TObject)
    begin
      with TFViewOrders(AForm) do
      begin
        TFViewOrders(AForm).info := LocalInfo;
      end;
    end
  );
end;


procedure TFViewOrders.ShowAddOrderForm();
var
  newform: TFAddOrder;
begin
  newform := TFAddOrder.CreateNew;

  newform.Caption := 'Select Customer and Order Type';
  newForm.Popup := True;
  newForm.Border := fbDialog;

  // used to manage Back button handling to close subform
  window.location.hash := 'subform';

  newform.ShowModal(
    procedure(AValue: TModalResult)
    begin
      if newform.confirm then
        orderEntry('', newForm.edtID.Text, 'ADD');
    end
  );
end;

procedure TFViewOrders.ShowSearchForm();
var
  newform: TFSearch;
begin
  newform := TFSearch.CreateNew;

  newform.Caption := 'Input Search Options';
  newForm.Popup := True;
  newForm.Border := fbDialog;
  newForm.searchOptions := generateSearchOptions();

  // used to manage Back button handling to close subform
  window.location.hash := 'subform';

  newform.ShowModal(
    procedure(AValue: TModalResult)
    var
      searchOptions: string;
    begin
      if newform.confirm then
      begin
        pageNumber := 1;

        // Status 1
        startDate1 := FormatDateTime('yyyy/mm/dd', newform.dtpStartDate1.Date);
        endDate1 := FormatDateTime('yyyy/mm/dd', newform.dtpEndDate1.Date);
        filterType1 := newform.wcbFilterType1.Text;
        null1 := newform.cbNull1.Checked;

        // Status 2
        startDate2 := FormatDateTime('yyyy/mm/dd', newform.dtpStartDate2.Date);
        endDate2 := FormatDateTime('yyyy/mm/dd', newform.dtpEndDate2.Date);
        filterType2 := newform.wcbFilterType2.Text;
        null2 := newform.cbNull2.Checked;

        jobName := newform.edtJobName.Text;
        orderID := newform.edtOrderID.Text;
        companyID := newform.edtCompanyID.Text;
        orderType := newform.wcbOrderType.Text;

        searchOptions := generateSearchOptions();
        lblSearch.Caption := searchOptions;
        getOrders(searchOptions);
      end;
    end
  );
end;


procedure TFViewOrders.wcbPageSizeChange(Sender: TObject);
begin
  PageSize := StrToInt(wcbPageSize.Text);
  getOrders(generateSearchOptions());
end;

procedure TFViewOrders.GeneratePagination(TotalPages: Integer);
// Generates pagination for the table.
// TotalPages: Total amount of pages generated by the search
var
  PaginationElement, PageItem, PageLink: TJSHTMLElement;
  I, Start, Finish: Integer;
begin
  PaginationElement := TJSHTMLElement(document.getElementById('pagination'));
  PaginationElement.innerHTML := ''; // Clear existing pagination

  // Previous Button
  PageItem := TJSHTMLElement(document.createElement('li'));
  PageItem.className := 'page-item';
  if PageNumber = 1 then
    PageItem.classList.add('disabled');
  PageLink := TJSHTMLElement(document.createElement('a'));
  PageLink.className := 'page-link';
  PageLink.innerText := 'Previous';
  PageLink.setAttribute('href', 'javascript:void(0)');
  PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
  begin
    if PageNumber > 1 then
    begin
      Dec(PageNumber);
      GetOrders(GenerateSearchOptions());
    end;
  end);
  PageItem.appendChild(PageLink);
  PaginationElement.appendChild(PageItem);

  // Page Numbers

  if TotalPages <= 7 then
  begin
    for I := 1  to 7 do
    begin
      if I <= TotalPages then
      begin
        PageItem := TJSHTMLElement(document.createElement('li'));
        PageItem.className := 'page-item';
        if I = PageNumber then
          PageItem.classList.add('selected-number'); // Add the selected-number class
        PageLink := TJSHTMLElement(document.createElement('a'));
        PageLink.className := 'page-link';
        PageLink.innerText := IntToStr(I);
        PageLink.setAttribute('href', 'javascript:void(0)');
        PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
        var
          PageNum: Integer;
        begin
          PageNum := StrToInt((Event.currentTarget as TJSHTMLElement).innerText);
          PageNumber := PageNum;
          GetOrders(GenerateSearchOptions());
        end);
        PageItem.appendChild(PageLink);
        PaginationElement.appendChild(PageItem);
      end;
    end;
  end
  else
  begin
    if PageNumber <= 4 then
    // If page number is low enough no early elipsis needed
    Begin
      Start := 2;
      Finish := 5;
    End
    else if (PageNumber >= (TotalPages - 3)) then
    // If page number is high enough no late elipsis needed
    begin
      Start := TotalPages - 3;
      Finish := TotalPages - 1;
    end
    else
    begin
      Start := PageNumber - 1;
      Finish := PageNumber + 1;
    end;

    PageItem := TJSHTMLElement(document.createElement('li'));
    PageItem.className := 'page-item';
    if 1 = PageNumber then
      PageItem.classList.add('selected-number'); // Add the selected-number class
    PageLink := TJSHTMLElement(document.createElement('a'));
    PageLink.className := 'page-link';
    PageLink.innerText := '1';
    PageLink.setAttribute('href', 'javascript:void(0)');
    PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
    var
      PageNum: Integer;
    begin
      PageNum := StrToInt((Event.currentTarget as TJSHTMLElement).innerText);
      PageNumber := PageNum;
      GetOrders(GenerateSearchOptions());
    end);
    PageItem.appendChild(PageLink);
    PaginationElement.appendChild(PageItem);

    // Adds Elipse to pagination if page number is too big
    if PageNumber > 4 then
    begin
      PageItem := TJSHTMLElement(document.createElement('li'));
      PageItem.className := 'page-item';
      PageItem.classList.add('disabled');
      PageLink := TJSHTMLElement(document.createElement('a'));
      PageLink.className := 'page-link';
      PageLink.innerText := '...';
      PageLink.setAttribute('href', 'javascript:void(0)');
      PageItem.appendChild(PageLink);
      PaginationElement.appendChild(PageItem);
    end;


    // Adds Page, page - 1, and page + 1 to pagination
    for I := Start  to Finish do
    begin
      if ( I > 1) and (I < TotalPages) then
      begin
        PageItem := TJSHTMLElement(document.createElement('li'));
        PageItem.className := 'page-item';
        if I = PageNumber then
          PageItem.classList.add('selected-number'); // Add the selected-number class
        PageLink := TJSHTMLElement(document.createElement('a'));
        PageLink.className := 'page-link';
        PageLink.innerText := IntToStr(I);
        PageLink.setAttribute('href', 'javascript:void(0)');
        PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
        var
          PageNum: Integer;
        begin
          PageNum := StrToInt((Event.currentTarget as TJSHTMLElement).innerText);
          PageNumber := PageNum;
          GetOrders(GenerateSearchOptions());
        end);
        PageItem.appendChild(PageLink);
        PaginationElement.appendChild(PageItem);
      end;
    end;

    // adds ellipse if number is too small
    if PageNumber < TotalPages - 4 then
    begin
      PageItem := TJSHTMLElement(document.createElement('li'));
      PageItem.className := 'page-item';
      PageItem.classList.add('disabled');
      PageLink := TJSHTMLElement(document.createElement('a'));
      PageLink.className := 'page-link';
      PageLink.innerText := '...';
      PageLink.setAttribute('href', 'javascript:void(0)');
      PageItem.appendChild(PageLink);
      PaginationElement.appendChild(PageItem);
    end;

    if TotalPages <> 1 then
    begin
      PageItem := TJSHTMLElement(document.createElement('li'));
      PageItem.className := 'page-item';
      if TotalPages = PageNumber then
            PageItem.classList.add('selected-number');
      PageLink := TJSHTMLElement(document.createElement('a'));
      PageLink.className := 'page-link';
      PageLink.innerText := IntToStr(TotalPages);
      PageLink.setAttribute('href', 'javascript:void(0)');
      PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
      var
        PageNum: Integer;
      begin
        PageNum := StrToInt((Event.currentTarget as TJSHTMLElement).innerText);
        PageNumber := PageNum;
        GetOrders(generateSearchOptions());
      end);
    end;
    PageItem.appendChild(PageLink);
    PaginationElement.appendChild(PageItem);
  end;

  // Next Button
  PageItem := TJSHTMLElement(document.createElement('li'));
  PageItem.className := 'page-item';
  if PageNumber = TotalPages then
    PageItem.classList.add('disabled');
  PageLink := TJSHTMLElement(document.createElement('a'));
  PageLink.className := 'page-link';
  PageLink.innerText := 'Next';
  PageLink.setAttribute('href', 'javascript:void(0)');
  PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
  begin
    if PageNumber < TotalPages then
    begin
      Inc(PageNumber);
      GetOrders(GenerateSearchOptions());
    end;
  end);
  PageItem.appendChild(PageLink);
  PaginationElement.appendChild(PageItem);

end;


procedure TFViewOrders.GetOrders(searchOptions: string);
var
  xdcResponse: TXDataClientResponse;
  orderList: TJSObject;
  orderListLength: integer;
  TotalPages: integer;
begin
  if PageNumber > 0 then
  begin
    asm
      startSpinner();
    end;
    xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetOrders', [searchOptions]));
    orderList := TJSObject(xdcResponse.Result);

    // Load data into the dataset
    xdwdsOrders.Close;
    xdwdsOrders.SetJsonData(orderList['data']);
    xdwdsOrders.Open;

    asm
      endSpinner();
    end;

    orderListLength := integer(orderList['count']);
    TotalPages := ( (orderListLength + PageSize - 1) div PageSize);

    if orderListLength = 0 then
    begin
      lblEntries.Caption := 'No entries found';
    end
    else if (PageNumber * PageSize) < orderListLength then
    begin
      lblEntries.Caption := 'Showing entries ' + IntToStr((PageNumber - 1) * PageSize + 1) +
                            ' - ' + IntToStr(PageNumber * PageSize) +
                             ' of ' + IntToStr(orderListLength);
    end
    else if (PageNumber * PageSize) >= orderListLength then
    begin
       lblEntries.Caption := 'Showing entries ' + IntToStr((PageNumber - 1) * PageSize + 1) +
                            ' - ' + IntToStr(orderListLength) +
                             ' of ' + IntToStr(orderListLength);
    end;

    // Optional: Continue using pagination if needed
    GeneratePagination(TotalPages);
  end;
end;


procedure TFViewOrders.btnAddOrderClick(Sender: TObject);
begin
  ShowAddOrderForm();
end;


procedure TFViewOrders.orderEntry(orderInfo, customerInfo, mode: string);
begin
  FViewMain.ViewOrderEntry(orderInfo, customerInfo, mode);
end;

procedure TFViewOrders.btnCloseNotificationClick(Sender: TObject);
begin
  HideNotification();
end;


procedure TFViewOrders.btnConfirmClick(Sender: TObject);
begin
  //orderEntry('', 'ADD');
end;


procedure TFViewOrders.btnSearchClick(Sender: TObject);
var
filterSection: TJSHTMLElement;
begin
  {if btnFilters.Caption = 'Show Filters' then
  begin
    btnFilters.Caption := 'Hide Filters';
    filterSection := TJSHTMLElement(document.getElementById('filter_info'));
    if Assigned(filterSection) then
      filterSection.style.setProperty('display', 'block');
  end
  else
  begin
    btnFilters.Caption := 'Show Filters';
    filterSection := TJSHTMLElement(document.getElementById('filter_info'));
    if Assigned(filterSection) then
      filterSection.style.setProperty('display', 'none');
  end;}
  ShowSearchForm();
end;


procedure TFViewOrders.Search(searchOptions: string);
// Search method that searches the database for a specific phone number
var
  xdcResponse: TXDataClientResponse;
  callList : TJSObject;
  i: integer;
  data: TJSArray;
  call: TJSObject;
  callListLength: integer;

begin
  if PageNumber > 0 then
  begin
    xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.Search',
        [searchOptions]));
    callList :=  TJSObject(xdcResponse.Result);
    data := TJSArray(callList['data']);
    callListLength := integer(callList['count']);
    ClearTable();
    for i := 0 to data.Length - 1 do
    begin
      call := TJSObject(data[i]);
      {AddRowToTable(string(call['toNumber']), string(call['fromNumber']), string(call['dateCreated']),
      string(call['duration']), string(call['transcription']), string(call['mediaUrl']));}
    end;
    TotalPages := (callListLength + PageSize - 1) div PageSize;
    lblEntries.Caption := 'Showing entries for phone number: ' + searchOptions;
  end;
end;

procedure TFViewOrders.ClearTable();
// clears the table
var
  tbody: TJSHTMLElement;
begin
  tbody := TJSHTMLElement(document.getElementById('tblPhoneGrid').getElementsByTagName('tbody')[0]);
  tbody.innerHTML := '';
end;


function TFViewOrders.GenerateSearchOptions(): string;
// Generates searchOptions for GetOrders.
var
searchOptions: string;
begin
  searchOptions :=  '&pagenumber=' + IntToStr(PageNumber) +
                    '&pagesize=' + IntToStr(PageSize) +
                    '&orderby=' + OrderBy +

                    //Status 1
                    '&filterType1=' + filterType1;
                    if ( (filterType1 <> '') and (filterType1 <> 'NONE') ) then
                    begin
                      searchOptions := searchOptions +
                      '&null1=' + BoolToStr(null1);
                      if (not (null1)) then
                      begin
                        searchOptions := searchOptions +
                        '&startDate1=' + startDate1 +
                        '&endDate1=' + endDate1;
                      end;
                    end;


                    // Status2
                    searchOptions := searchOptions +
                    '&filterType2=' + filterType2;
                    if ( (filterType2 <> '') and (filterType2 <> 'NONE') ) then
                    begin
                      searchOptions := searchOptions + '&null2=' + BoolToStr(null2);
                      if (not (null2)) then
                      begin
                        searchOptions := searchOptions +
                        '&startDate2=' + startDate2 +
                        '&endDate2=' + endDate2;
                      end;
                    end;

                    if ( ( orderType <> '' ) AND ( orderType <> 'ANY' ) ) then
                      searchOptions := searchOptions + '&orderType=' + orderType;

                    if jobName <> '' then
                      searchOptions := searchOptions + '&jobName=' + jobName;

                    if companyID <> '' then
                      searchOptions := searchOptions + '&companyID=' + companyID;

                    if orderID <> '' then
                      searchOptions := searchOptions + '&orderID=' + orderID;

  Result := searchOptions;
end;


procedure TFViewOrders.HideNotification;
begin
  pnlMessage.ElementHandle.hidden := True;
  info := '';
end;


procedure TFViewOrders.ShowNotification(Notification: string);
begin
  if Notification <> '' then
  begin
    lblMessage.Caption := Notification;
    pnlMessage.ElementHandle.hidden := False;
  end;
end;


procedure TFViewOrders.GeneratePDF(OrderID: string);
var
  XDCResponse: TXDataClientResponse;
  PDFBase64: string;
  PDFBlob: TJSUint8Array;
  PDFLink: TJSHTMLElement;
begin
//  XDCResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GenerateOrderPDF', [OrderID]));
//  PDFBase64 := string(XDCResponse.Result);
//
//  // Convert Base64 to binary and create a link to download it
//  PDFBlob := TJSUint8Array.new(TJSBase64.decodeBase64(PDFBase64));
//  PDFLink := TJSHTMLElement(document.createElement('a'));
//  PDFLink.setAttribute('href', 'data:application/pdf;base64,' + PDFBase64);
//  PDFLink.setAttribute('download', 'Order_' + OrderID + '.pdf');
//  PDFLink.click;
end;


end.
