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

unit View.Items;

interface

uses
  System.SysUtils, System.Classes, Web, WEBLib.Graphics, WEBLib.Forms, WEBLib.Dialogs,
  Vcl.Controls, Vcl.StdCtrls, WEBLib.StdCtrls, WEBLib.Controls, WEBLib.Grids, WebLib.Lists,
  XData.Web.Client, WEBLib.ExtCtrls, DB, XData.Web.JsonDataset,
  XData.Web.Dataset, XData.Web.Connection, Vcl.Forms, DateUtils, WebAudio;

type
  TFViewItems = class(TWebForm)
    XDataWebClient1: TXDataWebClient;
    XDataWebDataSet1: TXDataWebDataSet;
    lblEntries: TWebLabel;
    wcbPageSize: TWebComboBox;
    btnApply: TWebButton;
    edtName: TWebEdit;
    edtDescription: TWebEdit;
    cbStatus: TWebCheckBox;
    procedure WebFormCreate(Sender: TObject);
    procedure btnApplyClick(Sender: TObject);
    procedure wcbPageSizeChange(Sender: TObject);
  private
    FChildForm: TWebForm;
    procedure AddRowToTable(ID, Name, Description, Status: string);
    procedure ClearTable();
    procedure GeneratePagination(TotalPages: Integer);
    function GenerateSearchOptions(): string;
    [async] procedure GetItems(searchOptions: string);
    [async] procedure getUser();
    [async] procedure AddItem(itemOptions: string);
    var
      PageNumber: integer;
      PageSize: integer;
      TotalPages: integer;
      StartDate: string;
      EndDate: string;
      OrderBy: string;
      Caller: string;
  public

  end;

var
  FViewItems: TFViewItems;

implementation

uses
  JS, XData.Model.Classes,
  ConnectionModule, Auth.Service, Utils;

{$R *.dfm}

procedure TFViewItems.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.
begin
  DMConnection.ApiConnection.Connected := True;
  PageNumber := 1;
  TotalPages := 1; // Initial total pages
  wcbPageSize.Text := '10';
  getItems(GenerateSearchOptions());
end;

procedure TFViewItems.getUser();
var
  xdcResponse: TXDataClientResponse;
  userList, user: TJSObject;
  data: TJSArray;
begin

end;


procedure TFViewItems.AddRowToTable(ID, Name, Description, Status: string);
// Adds rows to the table
// ID: item ID
// Name: item name
// Description: item description
// Status: inactive or active
var
  NewRow, Cell, P, Button, Audio: TJSHTMLElement;
begin
  NewRow := TJSHTMLElement(document.createElement('tr'));

  // Item ID Cell
  Cell := TJSHTMLElement(document.createElement('td'));
  Cell.setAttribute('data-label', 'Item ID');
  Cell.innerText := ID;
  NewRow.appendChild(Cell);

  // Name Cell
  Cell := TJSHTMLElement(document.createElement('td'));
  Cell.setAttribute('data-label', 'Name');
  Cell.innerText := Name;
  NewRow.appendChild(Cell);

  // Description Cell
  Cell := TJSHTMLElement(document.createElement('td'));
  Cell.setAttribute('data-label', 'Description');
  Cell.innerText := Description;
  NewRow.appendChild(Cell);

  // Status Cell
  Cell := TJSHTMLElement(document.createElement('td'));
  Cell.setAttribute('data-label', 'Status');
  Cell.innerText := Status;
  NewRow.appendChild(Cell);

  // Appends new rows to the table body
  TJSHTMLElement(document.getElementById('tblPhoneGrid').getElementsByTagName('tbody')[0]).appendChild(NewRow);
end;

procedure TFViewItems.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);
      GetItems(GenerateSearchOptions());
    end;
  end);
  PageItem.appendChild(PageLink);
  PaginationElement.appendChild(PageItem);

  // Page Numbers

  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;
    GetItems(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;
        GetItems(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;
      GetItems(generateSearchOptions());
    end);
  end;
  PageItem.appendChild(PageLink);
  PaginationElement.appendChild(PageItem);

  // 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);
      GetItems(GenerateSearchOptions());
    end;
  end);
  PageItem.appendChild(PageLink);
  PaginationElement.appendChild(PageItem);

end;

procedure TFViewItems.GetItems(searchOptions: string);
// retrieves items from the server.
// searchOptions: info to limit how many items we retrieve from the server.
// probably not needed due to database size.
var
  xdcResponse: TXDataClientResponse;
  itemList : TJSObject;
  i: integer;
  data: TJSArray;
  item: TJSObject;
  itemListLength: integer;
begin
  console.log('correct');
   if PageNumber > 0 then
  begin
    Utils.ShowSpinner('spinner');
    xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetItems',
        [searchOptions]));
    itemList :=  TJSObject(xdcResponse.Result);
    data := TJSArray(itemList['data']);
    itemListLength := integer(itemList['count']);
    ClearTable();
    Utils.HideSpinner('Spinner');
    for i := 0 to data.Length - 1 do
    begin
      item := TJSObject(data[i]);
      AddRowToTable(string(item['ID']), string(item['name']), string(item['description']),
      string(item['status']));
    end;
    TotalPages := (itemListLength + PageSize - 1) div PageSize;
    if (PageNumber * PageSize) < itemListLength then
    begin
      lblEntries.Caption := 'Showing entries ' + IntToStr((PageNumber - 1) * PageSize + 1) +
                            ' - ' + IntToStr(PageNumber * PageSize) +
                             ' of ' + IntToStr(itemListLength);
    end
    else
    begin
       lblEntries.Caption := 'Showing entries ' + IntToStr((PageNumber - 1) * PageSize + 1) +
                            ' - ' + IntToStr(itemListLength) +
                             ' of ' + IntToStr(itemListLength);
    end;
    GeneratePagination(TotalPages);
  end;
end;

procedure TFViewItems.btnApplyClick(Sender: TObject);
// Button that effectively functions as a GetItems() button
var
  itemOptions: string;
begin
  PageNumber := 1;
  PageSize := StrToInt(wcbPageSize.Text);
  itemOptions :=    '&name=' + edtName.Text +
                    '&description=' + edtDescription.Text +
                    '&status=' + BoolToStr(cbStatus.Checked);

  console.log('GetItems');
  AddItem(itemOptions);
end;

procedure TFViewItems.AddItem(itemOptions: string);
// adds an item to the database.
var
  xdcResponse: TXDataClientResponse;
begin
  xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.AddItem',
        [itemOptions]));
  getItems(GenerateSearchOptions());
end;

procedure TFViewItems.wcbPageSizeChange(Sender: TObject);
// gets a new amount of items based when the page size is changed
begin
  PageNumber := 1;
  getItems(GenerateSearchOptions());
end;

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

function TFViewItems.GenerateSearchOptions(): string;
// Generates searchOptions for GetItems.
var
searchOptions: string;
begin
  PageSize := StrToInt(wcbPageSize.Text);
  searchOptions :=  '&pagenumber=' + IntToStr(PageNumber) +
                    '&pagesize=' + IntToStr(PageSize) +
                    '&orderby=' + OrderBy;
  Result := searchOptions;
end;

end.

