import React, { useRef, useState } from "react";
import {  useFlexLayout , useResizeColumns, useSortBy, useTable, useFilters, useGlobalFilter, useAsyncDebounce, usePagination, useRowSelect, useColumnOrder } from 'react-table'
import matchSorter from 'match-sorter'
import _, { filter } from 'lodash';
import moment from 'moment';
import { useHistory } from "react-router-dom";
import { OverlayPanel } from 'primereact/overlaypanel';
import { InputMask } from 'primereact/inputmask';
import { InputText } from 'primereact/inputtext';
import { Calendar } from 'primereact/calendar';
import { Paginator } from 'primereact/paginator';
import { TriStateCheckbox } from 'primereact/tristatecheckbox';
import { Slider } from 'primereact/slider';
import { Button } from "react-bootstrap";
import { Link } from "react-router-dom";
import { InputNumber } from "primereact/inputnumber";
import { MultiSelect } from 'primereact/multiselect';
import { RadioButton } from 'primereact/radiobutton';
import { useExportData } from "react-table-plugins";
import { ProgressBar } from 'primereact/progressbar';
import {Checkbox} from 'primereact/checkbox';
import { Dropdown } from 'primereact/dropdown';

import "flatpickr/dist/flatpickr.css";
import Flatpickr from "react-flatpickr";
import confirmDatePlugin from "flatpickr/dist/plugins/confirmDate/confirmDate";
import shortcutButtonsPlugin from "shortcut-buttons-flatpickr";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import UtilService from '../../src/services/util.service'
import Papa from "papaparse";
import JsPDF from "jspdf";
import "jspdf-autotable";
import TableUtil from "../utils/table.util";
import Validator from  "../utils/validator"

let tblinstance;
let tableInstanceRef;
let doServersideFilter = false;
let tbldata = [], filteredData = [];
let data = [];
let selectedRows = [];
let isunittest = false;
let showTopTotal = true;
let showGlobalFilter = true;
let showColumnFilter = true;
let allowColumnSelection = true;
let allowRowSelection = false;
let columnclassname = [];
let parentCallbackFunction, parentCBonSelection;
let showCSV = false;
let multiSelectOption = {};
let filterCallback = null;
let clearAllFuncCallback = null;
let tableOptionsState = null;
let tableToolTipsState = {};
let setLoaderFunction = null;
let showFilterOption = null;
let hasFilters = false;
let loadingStatus = false;
let tmpTableData = null;
let currentTableName = null;
let storeFilter = false;
let storage_array = [];
let dragged = null;
let reorder = [];
//let confirmDatePlugin = new confirmDatePlugin();
// Define a default UI for filtering
let fixedColumns = ['Select', 'Action', 'Status Logs', 'View Summary'];

const getItemStyle = ({ isDragging, isDropAnimating }, draggableStyle) => ({
  ...draggableStyle,
  // some basic styles to make the items look a bit nicer
  userSelect: "none",
  cursor: isDragging? 'move': 'move',
  ...(!isDragging && { transform: "translate(0,0)" }),
  ...(isDropAnimating && { transitionDuration: "0.001s" })

  // styles we need to apply on draggables
});

function GlobalFilter({
  preGlobalFilteredRows,
  globalFilter,
  setGlobalFilter,
}) {
  const [value, setValue] = React.useState(globalFilter)
  const onChange = useAsyncDebounce(value => { setGlobalFilter(value || undefined) }, 200)
  return (
    <span style={{ marginLeft: "-10px" }}>
      <input
        value={value || ""}
        onChange={e => {
          setValue(e.target.value);
          onChange(e.target.value);
        }}
      /> {" "}<i className="fa fa-search"></i>
    </span>
  )
}

// Define a default UI for filtering
function DefaultColumnFilter({
  column: { filterValue, preFilteredRows, setFilter, filteredRows, Header },
}) {
  const [value, setValue] = useState('');
  const [filtered, setFiltered] = useState(false);
  React.useEffect(() => {
    if (!filterValue && value) {
      setValue('');     
    }
    if (storeFilter) {
      const filterValue = TableUtil.getFilter(currentTableName, Header);
      if (filterValue) {
          setFiltered(true);
      }
      if(!value){
          setValue(filterValue);
          setFilter(filterValue);
      }
    }
  }, [filterValue, value]); 
  
  // Function to call the server side filtering
  const callServerFilter = (event, isCleared) => {
      hasFilters = true;
      if (isCleared) {
          hasFilters = false;
          if (filtered) {
              _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
              filterCallback(tableOptionsState, setLoaderFunction);
          }
      }   else {
          filterCallback(tableOptionsState, setLoaderFunction);
      }
  }; 
  return (
    <>
        <div className="table-filter" onClick={e => { e.stopPropagation() }} style={{marginRight: '5px'}}>
            <input 
              title={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Enter few characters and press ‘Enter’ key to search"}
              value={value}   //***TO REMOVE - INCOMING CHANGE WAS value={filterValue || ''}
              onChange={e => {
                setValue(e.target.value);
                setFilter(e.target.value || undefined) // Set undefined to remove the filter entirely
                if(storeFilter) {
                  TableUtil.saveFilter(currentTableName, Header, e.target.value);
                }
              }}
              onKeyUp={(e) => {
                if (e.key === "Enter" && doServersideFilter) {
                  setFiltered(true);
                  callServerFilter(e);
                }
              }}
            />
            {value && 
              <i className="table-reset fa fa-times" style={{cursor: 'pointer'}}
                title="Clear the filter"
                onClick={(e) => {
                  setFilter(undefined); setValue(''); setFiltered(false);
                  if (doServersideFilter) {
                    setFilter(undefined); 
                    setValue('');
                    callServerFilter(e, true);
                  }
                  if(storeFilter){
                    TableUtil.saveFilter(currentTableName, Header, '');
                  }
                }} />
            }
        </div>
              
      </>
  )
}

const setStoreData = (id, value) => { 
  debugger
  let localstorage_key = window.location.pathname.split('/')[1];
  let storage =  UtilService.localStore({ type: 'get', key: localstorage_key }); 
  if(storage && storage.length > 0) {
              storage.forEach(function(value, index) {
                if(value.name === id) {
                  value.name =  id
                  value.value = value
                }
              });
              const selected = _.filter(storage, function (filter) {
                if ( filter.name === id) {
                  return true;
                }
              })
              if(selected.length <= 0) {
                storage.push({name: id, value: value})
              }
            } else {
              storage = [{name: id, value: value}]
            }
            UtilService.localStore({ type: 'set', key: localstorage_key, value: storage });
}

/* 
Generate and download csv 
*/
function getExportFileBlob({ columns, data, fileType, fileName }) {
  if (fileType === "csv") {
    // CSV download
    const headerNames = columns.map((col) => col.exportValue);
    // remove actionpath column in csv export
    var index = headerNames.indexOf('actionpath');
    if (index > -1) {
      headerNames.splice(index, 1);
    }
    const csvString = Papa.unparse({ fields: headerNames, data });
    return new Blob([csvString], { type: "text/csv" });
  } //PDF download
  else if (fileType === "pdf") {
    const headerNames = columns.map((column) => column.exportValue);
    const doc = new JsPDF();
    var index = headerNames.indexOf('Action');
    if (index > -1) {
      headerNames.splice(index, 1);
    }
    doc.autoTable({
      head: [headerNames],
      body: data,
    });
    doc.save(`${fileName}.pdf`);
    return false;
  }
}

/**
 * Custom filter UI for selecting a unique option from a list.
 * option values are getting from  callback funtion or from the table data.
 * @param {*} param0 
 * @returns 
 */
function SelectColumnFilter({
  column: { filterValue, setFilter, preFilteredRows, id, Header },
}) {
  const [value, setValue] = useState('');
  const [filtered, setFiltered] = useState(false);
  const [rowData, setRowData] = useState(null);
  React.useEffect(() => {
    if (!filterValue && value) {
      setValue('');
    }
    if (storeFilter) {
      const filterValue = TableUtil.getFilter(currentTableName, Header);
      setValue(filterValue);
      setFilter(filterValue);
    }
  }, [filterValue, value]);

  const options = React.useMemo(() => {
    let options = null;
    if (showFilterOption) {
      options = new Set(showFilterOption(id));
    } 
    if (options === null || options.size === 0) {
      options = new Set();
      if (preFilteredRows || rowData) {
          preFilteredRows = preFilteredRows ? preFilteredRows : rowData;
          setRowData(preFilteredRows);
          preFilteredRows.forEach(row => {
            options.add(row.values[id])
          });
      }
    } 
    return [...options.values()]
  }, [id, preFilteredRows]);

  // Function to call the server side filtering
  const callServerFilter = (event, isCleared) => {
    hasFilters = true;
    _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
    if (isCleared) {
        hasFilters = false;
        //if (filtered) {
            filterCallback(tableOptionsState, setLoaderFunction);
        //}
    }   else {
        tableOptionsState.filters.push({id: Header, value: event.target.value});
        filterCallback(tableOptionsState, setLoaderFunction);
    }
  };

  // Render a multi-select box
  return (
    <div onClick={e => { e.stopPropagation() }}>
      <select
        title={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Select a value from list to search"}
        // className= {columnclassname[0][Header]}
        style={{
          height: '24.2014px',
          border: '1px solid lightgrey',
        }}
        value={value}
        onChange={e => {
          setValue(e.target.value);
          setFilter(e.target.value || undefined);
          if (doServersideFilter) {
            if (e.target.value === '' || e.target.value === 'All') {
              hasFilters = false;
              setFiltered(false);
              setFilter(undefined); 
              setValue('');
              callServerFilter(e, true);
            } else {
              setFiltered(true);
              callServerFilter(e, false);
            }
          }
          if(storeFilter) {
            TableUtil.saveFilter(currentTableName, Header, e.target.value);
          }
        }}
      >
        <option value="">All</option>
        {options.map((option, i) => (
          <option key={i} value={option}>
            {_.startCase(option)}
          </option>
        ))}
      </select>
    </div>
  )
}

// Multi-Select Custom Filter and set unique options value
function MultiSelectColumnFilter({
  column: { filterValue, setFilter, preFilteredRows, id, Header },
}) {
  const [value, setValue] = useState('');
  const [filtered, setFiltered] = useState(false);
  const [filtertype, setFiltertype] = useState('Any');

  React.useEffect(() => {
    if (!filterValue && value) {
      setValue('');
      setFiltertype('Any');
    }
    if (storeFilter) {
      const filterValue = TableUtil.getFilter(currentTableName, Header);
      const filterType = TableUtil.getFilter(currentTableName, 'stationFilterType');
      if(filterValue && !value){
        setValue(filterValue);
        setFilter(filterValue);
        setFiltertype(filterType);
        multiSelectOption[Header] = filterType;
      }
    }
  }, [filterValue, value, filtertype]);

  // Set Any / All Filter type
  const setSelectTypeOption = (option) => {
    setFiltertype(option);
    multiSelectOption[Header] = option
    if (value !== '') {
      if (storeFilter) {
        TableUtil.saveFilter(currentTableName, 'stationFilterType', option);
      }
      setFilter(value);
    }
  };

  /**
   * Trigger server side data fetch in parent component
   * @param {*} e 
   */
  function callSearchFunc(e) {
    callServerFilter(e);
  }

  // Function to call the server side filtering
  const callServerFilter = (event, isCleared) => {
    hasFilters = true;
    tableOptionsState.filters.push({id: 'stationFilterType', value: filtertype});
    if (isCleared) {
        hasFilters = false;
        if (filtered) {
            _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
            filterCallback(tableOptionsState, setLoaderFunction);
        }
    }   else {
        filterCallback(tableOptionsState, setLoaderFunction);
    }
  };

  multiSelectOption[Header] = filtertype;
  const options = React.useMemo(() => {
    let options = new Set();
    if (showFilterOption) {
      return showFilterOption(id);
    } 
    preFilteredRows.forEach(row => {
      row.values[id].split(',').forEach(value => {
        if (value !== '') {
          let hasValue = false;
          options.forEach(option => {
            if (option.name === value) {
              hasValue = true;
            }
          });
          if (!hasValue) {
            let option = { 'name': value, 'value': value };
            options.add(option);
          }
        }
      });
    });
    return [...options.values()]
  }, [id, preFilteredRows]);

  // Render a multi-select box
  return (
    <div onClick={e => { e.stopPropagation() }} >
      <div className="p-field-radiobutton">
        <RadioButton inputId="filtertype1" name="filtertype" value="Any" 
        onChange={(e) => setSelectTypeOption(e.value)} checked={filtertype === '' || filtertype === 'Any'} 
        tooltip= "Search the row if the Station contains at least one of the selected value" />
        <label htmlFor="filtertype1">Any</label>
      </div>
      <div className="p-field-radiobutton">
        <RadioButton inputId="filtertype2" name="filtertype" value="All" 
        onChange={(e) => setSelectTypeOption(e.value)} checked={filtertype === 'All'} 
        tooltip= "Search the row if the Station contains all of the selected value" />
        <label htmlFor="filtertype2">All</label>
      </div>
      <div style={{ position: 'relative', display: 'flex'}} >
        <MultiSelect data-testid="multi-select" id="multi-select" optionLabel="value" optionValue="value" filter={true}
          value={value}
          options={options}
          onChange={e => {
            setValue(e.target.value);
            setFilter(e.target.value || undefined);
            setFiltertype(filtertype);
            setFiltered(true);
            if(storeFilter) {
              if (e.target.value.length > 0) {
                TableUtil.saveFilter(currentTableName, Header, e.target.value);
                TableUtil.saveFilter(currentTableName, `${Header}-FilterOption`, filtertype);
              } else {
                TableUtil.clearColumnFilter(currentTableName, Header);
                TableUtil.clearColumnFilter(currentTableName, `${Header}-FilterOption`);
              }
            }
          }}
          maxSelectedLabels="1"
          selectedItemsLabel="{0} Selected"
          className="multi-select"
          tooltip={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Select one or more value from list to search"}
          style={{width: '95%'}}
        />
        {doServersideFilter &&
            <button  className="p-link" onClick={callSearchFunc} >
              <i className="pi pi-search search-btn" />
            </button>
        }
      </div>
    </div>
  )
}

// Multi-Select Custom Filter and set unique options value
function MultiSelectFilter({
  column: { filterValue, setFilter, preFilteredRows, id, Header },
}) {
  const [value, setValue] = useState('');
  const [filtertype, setFiltertype] = useState('Any');
  const [filtered, setFiltered] = useState(false);

  function callSearchFunc(e) {
    callServerFilter(e);
  }
  
  React.useEffect(() => {
    if (!filterValue && value) {
      setValue('');
      setFiltertype('Any');
    }
    if (storeFilter) {
      const filterValue = TableUtil.getFilter(currentTableName, Header);
      if(filterValue && !value){
        setValue(filterValue);
        setFilter(filterValue);
        setFiltertype(filtertype);
      }
    }
  }, [filterValue, value, filtertype]);

  multiSelectOption[Header] = filtertype;
  const options = React.useMemo(() => {
    let options = new Set();
    if (showFilterOption) {
      return showFilterOption(id);
    } 
    preFilteredRows.forEach(row => {
      row.values[id].split(',').forEach(value => {
        if (value !== '') {
          let hasValue = false;
          options.forEach(option => {
            if (option.name === value) {
              hasValue = true;
            }
          });
          if (!hasValue) {
            let option = { 'name': value, 'value': value };
            options.add(option);
          }
        }
      });
    });
    return [...options.values()]
  }, [id, preFilteredRows]);

    // Function to call the server side filtering
    const callServerFilter = (event, isCleared) => {
      hasFilters = true;
      if (isCleared) {
          hasFilters = false;
          if (filtered) {
              _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
              filterCallback(tableOptionsState, setLoaderFunction);
          }
      }   else {
          filterCallback(tableOptionsState, setLoaderFunction);
      }
  }; 

  // Render a multi-select box
  return (
    <div onClick={e => { e.stopPropagation()}}>
      <div style={{ position: 'relative', display: 'flex'}} >
          <MultiSelect data-testid="multi-select" id="multi-select" optionLabel="name" optionValue="value" filter //={!doServersideFilter}
            value={value}
            options={options}
            onChange={e => {
              setValue(e.target.value);
              setFilter(e.target.value || undefined);
              if(storeFilter) {
                if (e.target.value.length > 0) {
                  TableUtil.saveFilter(currentTableName, Header, e.target.value);
                } else {
                  TableUtil.clearColumnFilter(currentTableName, Header);
                }
              }
              setFiltered(true);
              //callServerFilter(e);
            }}
            maxSelectedLabels="1"
            selectedItemsLabel="{0} Selected"
            className="multi-select"
            tooltip={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Select one or more value from list and click search icon to search"}
            style={{width: '85%'}}
          />
        {doServersideFilter &&
          <div>
              <button  className="p-link" onClick={callSearchFunc} >
                <i className="pi pi-search search-btn" />
              </button>
          </div>
        }
      </div>
    </div>
  )
}

// This is a custom filter UI that uses a
// slider to set the filter value between a column's
// min and max values
function SliderColumnFilter({
  column: { filterValue, setFilter, preFilteredRows, id, Header },
}) {
  // Calculate the min and max
  // using the preFilteredRows
  const [value, setValue] = useState(0);
  
  React.useEffect(() => {
    if (storeFilter) {
      const filterValue = TableUtil.getFilter(currentTableName, Header);
      if (filterValue && !value) {
        setValue(filterValue);
        setFilter(filterValue);
      }
    }
  });

  return (
    <div onClick={e => { e.stopPropagation() }} className="table-slider">
      <Slider value={value} 
        onChange={(e) => { 
          setFilter(e.value); setValue(e.value);
          if (storeFilter) {
            TableUtil.saveFilter(currentTableName, Header, e.value);
          }
        }}
        tooltip={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Select range value to search"}
      />
    </div>
  )
}

// This is a custom filter UI that uses a
// switch to set the value
function BooleanColumnFilter({
  column: { setFilter, filterValue, Header },
}) {
  // Calculate the min and max
  // using the preFilteredRows
  const [value, setValue] = useState(null);
  const [filtered, setFiltered] = useState(false);
  React.useEffect(() => {
    if (!filterValue && value) {
      setValue(null);
    }
    if (storeFilter) {
      const filterValue = TableUtil.getFilter(currentTableName, Header);
      if(filterValue && !value){
        setValue(filterValue);
        setFilter(filterValue);
      }
    }
  }, [filterValue, value]);
  // Function to call the server side filtering
  const callServerFilter = (isCleared) => {
    hasFilters = true;
    _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
    if (isCleared == null) {
        setFiltered(false);
    } else if (isCleared) {
        hasFilters = false;
        tableOptionsState.filters.push({id: Header, value: true});
        setFiltered(true);
        setValue(true);
    } else {
        setFiltered(true);
        setValue(false);
        tableOptionsState.filters.push({id: Header, value: false});
    }
    filterCallback(tableOptionsState, setLoaderFunction);
  };

  return (
    <div onClick={e => { e.stopPropagation() }}>
      <TriStateCheckbox value={value} style={{ 'width': '15px', 'height': '24.2014px' }} on
        onChange={(e) => { 
          setValue(e.target.value);
          setFilter(e.target.value || undefined); 
          setFiltered(true);
          if (storeFilter) {
            TableUtil.saveFilter(currentTableName, Header, e.target.value);
          }
          if (doServersideFilter) {
            callServerFilter(e.value);
          }
        }}
        tooltip={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Select checkbox (True/False/None) to search"}
       />
    </div>
  )
}

// This is a custom filter UI that uses a
// calendar to set the valueCalendar
function ColumnFilter({
  column: { setFilter, filterValue, Header },
}) {
  // Calculate the min and max
  // using the preFilteredRows
  const [value, setValue] = useState('');
  const [filtered, setFiltered] = useState(false);
  React.useEffect(() => {
    if (!filterValue && value) {
      setValue(null);
    }
  }, [filterValue, value]);

  // Function to call the server side filtering
  const callServerFilter = (event, isCleared) => {
    hasFilters = true;
    if (isCleared) {
        hasFilters = false;
        if (filtered) {
            _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
            filterCallback(tableOptionsState, setLoaderFunction);
        }
    }   else {
        filterCallback(tableOptionsState, setLoaderFunction);
    }
};
  return (

    <div className="table-filter" onClick={e => { e.stopPropagation() }}>
      <Calendar value={filterValue} appendTo={document.body} dateFormat="yy-mm-dd" 
      onChange={(e) => {
        const value = moment(e.value).format('YYYY-MM-DD')
        setValue(value);
        setFilter(e.value);
        if (value !== 'Invalid date'  && doServersideFilter) {
          setFiltered(true);
          callServerFilter(e);
        }
      }} 
      showIcon></Calendar>
      {value && <i onClick={(e) => { setFilter(undefined); setValue(''); setFiltered(false);
        if (doServersideFilter) {
          setFilter(undefined); 
          setValue('');
          callServerFilter(e, true);
        } }} className="tb-cal-reset fa fa-times" />}
    </div>
  )
}

// This is a custom filter UI that uses a
// calendar range to set the value
function DateRangeColumnFilter({
  column: { setFilter, filterValue, Header },
}) {
  // Calculate the min and max
  // using the preFilteredRows
  const [value, setValue] = useState('');
  const [filtered, setFiltered] = useState(false);
  React.useEffect(() => {
    if (!filterValue && value) {
      setValue(null);
    }
    
    if (storeFilter) {
      const filter = TableUtil.getFilter(currentTableName, Header);
      const filterValue = _.map(filter, date => {return new Date(date)} )
      if (filterValue[1] &&  !value ){
        setValue(filterValue);
        setFilter(filterValue);
      }
    }
  }, [filterValue, value]);
  // Function to call the server side filtering
  const callServerFilter = (value, isCleared) => {
    hasFilters = true;
    if (isCleared) {
        hasFilters = false;
        if (filtered) {
            _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
            filterCallback(tableOptionsState, setLoaderFunction);
        }
    }   else {
      let filterColumn = _.find(tableOptionsState.filters, {id: Header });
      if(filterColumn) {
        filterColumn.value = value;
        filterCallback(tableOptionsState, setLoaderFunction);
      } else {
        filterCallback(tableOptionsState, setLoaderFunction);
      }
    }
  };
  return (
    <div className="table-filter" onClick={e => { e.stopPropagation() }}>
      <Calendar selectionMode="range" value={filterValue} appendTo={document.body}
        placeholder="Range"
        onChange={(e) => {  
          setValue(e.value);
          setFilter(e.value);
          if(storeFilter) {
            TableUtil.saveFilter(currentTableName, Header, e.target.value);
          }
          if ((value !== '' && value !== 'Invalid date' ) && doServersideFilter) {
            setFiltered(true);
            callServerFilter(e.target.value);
          }
        }} 
        showIcon></Calendar>
      {value && <i onClick={(e) => { 
        setFilter(undefined); setValue([]); setFiltered(false);
        if(storeFilter){
          TableUtil.saveFilter(currentTableName, Header, []  );
        }
        if (doServersideFilter) {
          setFilter(undefined); 
          setValue('');
          callServerFilter(e.target.value, true);
        } }} className="tb-cal-reset fa fa-times" />}
    </div>
  )
}

// This is a custom filter UI that uses a
// flatpickr range calendar to set the value
function FlatpickrRangeColumnFilter({
  column: { setFilter, filterValue, Header },
}) {
    const [value, setValue] = useState('');
    const [filtered, setFiltered] = useState(false);  
    React.useEffect(() => {
      if (!filterValue && value) {
        setValue(null);
      }
      if (storeFilter) {
        const filter = TableUtil.getFilter(currentTableName, Header);
        const filterValue = _.map(filter, date => {return new Date(date)} )
        if (filter === '') {
          TableUtil.saveFilter(currentTableName, Header, []  );
          setFilter(undefined); 
        }
        if (filterValue &&  !value ){
          setValue(filterValue);
          setFilter(filterValue);
        }
      }
  }, [filterValue, value]);
  // Function to call the server side filtering
  const callServerFilter = (value, isCleared) => {
      hasFilters = true;
      if (isCleared) {
          hasFilters = false;
          _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
          filterCallback(tableOptionsState, setLoaderFunction);
      }   else {
          let filterColumn = _.find(tableOptionsState.filters, {id: Header });
          if(filterColumn) {
              filterColumn.value = value;
              filterCallback(tableOptionsState, setLoaderFunction);
          } else if (!filterColumn && value && value.length === 2) {
              // Here the above condition placed because the Start/End time filters is not consistency in tableOptionsState.filters
              filterColumn = {id: Header, value: value}
              tableOptionsState.filters.push(filterColumn);
              filterCallback(tableOptionsState, setLoaderFunction);
          } else {
              filterCallback(tableOptionsState, setLoaderFunction);
          }
    }
  };
  return (
      <div className="table-filter" onClick={e => { e.stopPropagation() }}>
          <Flatpickr data-enable-time data-input className="flatpickr-range-filter"
            options={{  "inlineHideInput": true,
                        "wrap": true,
                        "enableSeconds": true,
                        "time_24hr": true,
                        "minuteIncrement": 1,
                        "allowInput": true,
                        "mode": "range",
                        "defaultHour": 0,
                        "plugins": [new confirmDatePlugin()]
                    }}
            title={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Enter the date & time range to search and press ‘Ok’ button"}
            value={filterValue}
            onClose={newValue => {
              if(newValue) {
                // To apply serverside filter only when the value is changed
                let isValueChanged = false;
                if (value.length !== newValue.length) {
                  isValueChanged = true;
                } else if (value.length === newValue.length) {
                  if (value.length === 1 && !(moment(value[0]).isSame(moment(newValue[0])))) {
                    isValueChanged = true
                  } else if (value.length === 2 &&
                    (!(moment(value[0]).isSame(moment(newValue[0]))) ||
                    !(moment(value[1]).isSame(moment(newValue[1]))))) {
                    isValueChanged = true;
                  }
                }
                setValue(newValue);
                setFilter(newValue);
                if(storeFilter) {
                  TableUtil.saveFilter(currentTableName, Header, newValue);
                }
                if ((newValue !== '' && newValue !== 'Invalid date' ) && isValueChanged  && doServersideFilter) {
                  setFiltered(true);
                  callServerFilter(newValue);
                }
              }
            }}
          >
            <input type="text" data-input className={`p-inputtext p-component calendar-input`}  />
            <button class="p-button p-component p-button-icon-only calendar-button" data-toggle
                    title="Click to select the date range" >
                    <i class="fas fa-calendar"></i>
            </button>
            <button class="p-button p-component p-button-icon-only calendar-reset" 
              onClick={(value) => { 
                setFilter(undefined); setValue([]); setFiltered(false);filterValue = [];
                if(storeFilter){
                    TableUtil.saveFilter(currentTableName, Header, []  );
                }
                if (doServersideFilter) {
                    setFilter(undefined); 
                    setValue('');
                    callServerFilter(value, true);
                }
            }} title="Clear date range" >
                <i class="fa fa-times" style={{color:'white', marginTop:'-2.85px'}} ></i>
            </button>
          </Flatpickr>
      </div>
  )
}

// This is a custom filter UI that uses a
// calendar to set the value
function CalendarColumnFilter({
  column: { setFilter, filterValue, Header },
}) {
  // Calculate the min and max
  // using the preFilteredRows
  const [value, setValue] = useState('');
  const [filtered, setFiltered] = useState(false);
  React.useEffect(() => {
    if (!filterValue && value) {
      setValue(null);
    }
    if (storeFilter) {
      const filterValue = TableUtil.getFilter(currentTableName, Header);
      if(filterValue && !value){
        const valueAsDate = new Date(filterValue)
        setValue(valueAsDate);
        setFilter(valueAsDate);
      }
    }
    
  }, [filterValue, value]);

  // Function to call the server side filtering
  const callServerFilter = (event, isCleared) => {
    hasFilters = true;
    if (isCleared) {
        hasFilters = false;
        if (filtered) {
            _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
            filterCallback(tableOptionsState, setLoaderFunction);
        }
    }   else {
        filterCallback(tableOptionsState, setLoaderFunction);
    }
};
  return (
    <div className="table-filter" onClick={e => { e.stopPropagation() }}>
      <Calendar value={filterValue} appendTo={document.body} dateFormat="yy-mm-dd" 
      onChange={(e) => {
        const value = moment(e.value).format('YYYY-MM-DD')
        setValue(value);
        setFilter(e.value);
        if (value !== 'Invalid date'  && doServersideFilter) {
          setFiltered(true);
          callServerFilter(e);
        }

          if(storeFilter) {
            TableUtil.saveFilter(currentTableName, Header, value);
          }
      }} 
      onClearButtonClick={(e) => {
        if(storeFilter) {
          TableUtil.clearColumnFilter(currentTableName, Header);
        }
      }}
      showIcon></Calendar>
      {value && <i onClick={(e) => { setFilter(undefined); setValue(''); setFiltered(false);
        if (storeFilter) {
          TableUtil.clearColumnFilter(currentTableName, Header);
        }
        if (doServersideFilter) {
          setFilter(undefined); 
          setValue('');
          callServerFilter(e, true);
        } }} className="tb-cal-reset fa fa-times" />}
    </div>
  )
}

// This is a custom filter UI that uses a
// calendar to set the value
function DateTimeColumnFilter({
  column: { setFilter, filterValue, Header },
}) {
  const [value, setValue] = useState('');
  React.useEffect(() => {
    if (!filterValue && value) {
      setValue(null);
    }
    if (storeFilter) {
      const getValue = TableUtil.getFilter(currentTableName, Header);
      if (getValue && !value) {
        const valueAsDate = new Date(getValue)
        setValue(valueAsDate);
        setFilter(valueAsDate);
      }
    }
  }, [filterValue, value]);
  
  // Function to call the server side filtering
  const callServerFilter = (event, isCleared) => {
      hasFilters = true;
      _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
      if (isCleared) {
          hasFilters = false;
          filterCallback(tableOptionsState, setLoaderFunction);
      } else {
          tableOptionsState.filters.push({id: Header, value: moment(event.value, moment.ISO_8601).format('YYYY-MM-DD HH:mm:ss')});
          filterCallback(tableOptionsState, setLoaderFunction);
      }
  };
  return (
    <div className="table-filter" onClick={e => { e.stopPropagation() }}>
      <Calendar value={value} appendTo={document.body} dateFormat="yy/mm/dd"
       onKeyUp={(e) => {
        if (e.key === "Enter" && doServersideFilter) {
          callServerFilter(e);
        }
      }}
      onChange={(e) => {
        const value = moment(e.value, moment.ISO_8601).format('YYYY-MM-DD HH:mm:ss');
        setValue(value); setFilter(value);
        if (value !== 'Invalid date'  && doServersideFilter) {
          callServerFilter(e);
        }
        
        if(storeFilter) {
          TableUtil.saveFilter(currentTableName, Header, value);
        }
      }} 
      showIcon
      // showTime= {true}
      //showSeconds= {true}
      // hourFormat= "24"
      ></Calendar>
      {value && <i onClick={(e) => { 
        setFilter(undefined); setValue('');
        if (doServersideFilter) {
          setFilter(undefined); 
          setValue('');
          callServerFilter(e, true);
        }
        if (storeFilter) {
          TableUtil.clearColumnFilter(currentTableName, Header);
        }
     }} className="tb-cal-reset fa fa-times" />}
    </div>
  )
}

/**
 * Custom function to filter data from date field.
 * @param {Array} rows 
 * @param {String} id 
 * @param {String} filterValue 
 */
function fromDatetimeFilterFn(rows, id, filterValue) {
  const filteredRows = _.filter(rows, function (row) {
    // If cell value is null or empty
    if (!row.values[id]) {
      return false;
    }
    //Remove microsecond if value passed is UTC string in format "YYYY-MM-DDTHH:mm:ss.sssss"
    let rowValue = moment.utc(row.values[id].split('.')[0]);
    if (!rowValue.isValid()) {
      // For cell data in format 'YYYY-MMM-DD'
      rowValue = moment.utc(moment(row.values[id], 'YYYY-MM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
    }
    const start = moment.utc(moment(filterValue, 'YYYY-MM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));

    return (start.isSameOrBefore(rowValue));
  });
  return filteredRows;
}

/**
 * Custom function to filter Multi selection based on filter type (Any/All) .
 * @param {Array} rows 
 * @param {String} id 
 * @param {String} filterValue 
 */
function multiSelectFilterFn(rows, id, filterValue) {
  if (filterValue) {
    const filteredRows = _.filter(rows, function (row) {
      if (filterValue.length === 0) {
        return true;
      }
      // If cell value is null or empty
      if (!row.values[id]) {
        return false;
      }
      let rowValue = row.values[id];
      let hasData = false;
      let columnValues = rowValue.split(',');
      let unfilteredColValues = _.difference(filterValue, columnValues);
      if (multiSelectOption[id] === 'Any') {
          hasData = unfilteredColValues.length < filterValue.length;
      }
      else {
          hasData = unfilteredColValues.length === 0;
      }
      return hasData;
    });
    return filteredRows;
  }
}

/**
 * Custom function to filter data from date field.
 * @param {Array} rows 
 * @param {String} id 
 * @param {String} filterValue 
 */
function toDatetimeFilterFn(rows, id, filterValue) {
  let end = moment.utc(moment(filterValue, 'YYYY-MM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
  end = moment(end, "DD-MM-YYYY").add(1, 'days');
  const filteredRows = _.filter(rows, function (row) {
    // If cell value is null or empty
    if (!row.values[id]) {
      return false;
    }
    //Remove microsecond if value passed is UTC string in format "YYYY-MM-DDTHH:mm:ss.sssss"
    let rowValue = moment.utc(row.values[id].split('.')[0]);
    if (!rowValue.isValid()) {
      // For cell data in format 'YYYY-MMM-DD'
      rowValue = moment.utc(moment(row.values[id], 'YYYY-MM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
    }
    return (end.isSameOrAfter(rowValue));
  });
  return filteredRows;
}

/**
 * Custom function to filter data from date field.
 * @param {Array} rows 
 * @param {String} id 
 * @param {String} filterValue 
 */
function dateFilterFn(rows, id, filterValue) {
  const filteredRows = _.filter(rows, function (row) {
    // If cell value is null or empty
    if (!row.values[id]) {
      return false;
    }
    //Remove microsecond if value passed is UTC string in format "YYYY-MM-DDTHH:mm:ss.sssss"
    let rowValue = moment.utc(row.values[id].split('.')[0]);
    if (!rowValue.isValid()) {
      // For cell data in format 'YYYY-MMM-DD'
      rowValue = moment.utc(moment(row.values[id], 'YYYY-MM-DD').format("YYYY-MM-DDT00:00:00"));
    }
    const start = moment.utc(moment(filterValue, 'YYYY-MM-DD').format("YYYY-MM-DDT00:00:00"));
    const end = moment.utc(moment(filterValue, 'YYYY-MM-DD').format("YYYY-MM-DDT23:59:59"));
    return (start.isSameOrBefore(rowValue) && end.isSameOrAfter(rowValue));
  });
  return filteredRows;
}

/**
 * Custom function to filter data Range from date field.
 * @param {Array} rows 
 * @param {String} id 
 * @param {String} filterValue 
 */
 function dateRangeFilterFn(rows, id, filterValue) {
  const filteredRows = _.filter(rows, function (row) {
    // If cell value is null or empty
    if (!row.values[id]) {
      return true;
    }
    //Remove microsecond if value passed is UTC string in format "YYYY-MM-DDTHH:mm:ss.sssss"
    let rowValue = moment.utc(row.values[id].split('.')[0]);
    if (!rowValue.isValid()) {
      // For cell data in format 'YYYY-MMM-DD'
      rowValue = moment.utc(moment(row.values[id], 'YYYY-MM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
    }
    const start = moment.utc(moment(filterValue[0], 'YYYY-MM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
    const end = moment.utc(moment(filterValue[1], 'YYYY-MM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
    if(moment(end,'YYYY-MM-DDTHH:mm:SS', true).isValid() && moment(start,'YYYY-MM-DDTHH:mm:SS', true).isValid()) {
        return (start.isSameOrBefore(rowValue) && end.isSameOrAfter(rowValue));
    }
    else if(moment(start,'YYYY-MM-DDTHH:mm:SS', true).isValid()) {
      return (start.isSameOrBefore(rowValue));
    }
    else {
      return true;
    }
  });
  return filteredRows;
}

function durationTimeFilterFn(rows, id, filterValue) {
  const filteredRows = _.filter(rows, function (row) {
    // If cell value is null or empty
    if (!row.values[id]) {
      return false;
    }
    //Remove microsecond if value passed is UTC string in format "HH:mm:ss.sssss"
    let rowValue = moment(row.values[id], 'HH:mm:SS');
    if (!rowValue.isValid()) {
      // For cell data in format 'HH:mm:SS'
      rowValue = moment(row.values[id], 'HH:mm:SS');
    }
    const start = moment(filterValue[0], 'HH:mm:SS');
    const end = moment(filterValue[1], 'HH:mm:SS');
    if(moment(end,'HH:mm:SS', true).isValid() && moment(start,'HH:mm:SS', true).isValid()) {
      return (start.isSameOrBefore(rowValue) && end.isSameOrAfter(rowValue));
    }
    else if (!(moment(end,'HH:mm:SS', true).isValid()) && !(moment(start,'HH:mm:SS', true).isValid()) ){
      return true
    }
    else if(!(moment(start,'HH:mm:SS', true).isValid())) {
      return end.isSameOrAfter(rowValue);
    }
    else if(!(moment(end,'HH:mm:SS', true).isValid())) {
      return start.isSameOrBefore(rowValue);
    }
  });
  return filteredRows;
}

// This is a custom UI for our 'between' or number range
// filter. It uses slider to filter between min and max values.
function RangeColumnFilter({
  column: { filterValue = [], preFilteredRows, setFilter, id, Header },
}) {
  let [value, setValue] = useState('');
  let [firstLoad, setFirstLoad] = useState(true);
  const [min, max] = React.useMemo(() => {
    let min = 0;
    let max = 0;
    if (preFilteredRows.length > 0 && preFilteredRows[0].values[id]) {
      min = preFilteredRows[0].values[id];
    }
    preFilteredRows.forEach(row => {
      min = Math.min(row.values[id] ? row.values[id] : 0, min);
      max = Math.max(row.values[id] ? row.values[id] : 0, max);
    });
    if (storeFilter && firstLoad) {
      let storedFilter = TableUtil.getFilter(currentTableName, Header);
      if (storedFilter) {
        setValue(storedFilter);
        setFilter(storedFilter);
        setFirstLoad(false);
      }
    }
    return [min, max];
  }, [id, preFilteredRows]);
  if (filterValue.length === 0) {
    filterValue = [min, max];
  }
  return (
    <>
      <div className="filter-slider-label">
        <span style={{ float: "left" }}>{filterValue[0]}</span>
        <span style={{ float: "right", marginRight: "5px" }}>{min !== max ? filterValue[1] : ""}</span>
      </div>
      <Slider value={filterValue} min={min} max={max} className="filter-slider"
        style={{}}
        onChange={(e) => { 
          setValue(e.value);
          setFilter(e.value); 
            if(storeFilter) {
              TableUtil.saveFilter(currentTableName, Header, e.value);
            }
          }} range />
    </>
  );
}

/**
 * Number range rilter
 * @param {number} param0 : Range value for min and max filters
 * @returns 
 */
function NumberRangeFilter({
  column: { filterValue = [], preFilteredRows, setFilter, id, Header },
}) {
  let [rangeValue, setRangeValue] = useState([0,0]);
  const [value, setValue] = useState('');
  const [filtered, setFiltered] = useState(false);
  React.useEffect(() => {
    if (!filterValue && value) {
      setValue('');     
    }
    if (storeFilter) {
      const filterValue = TableUtil.getFilter(currentTableName, Header);
      if (filterValue) {
          setFiltered(true);
      }
      if(!value){
          setValue(filterValue);
          //setFilter(filterValue);
      }
    }
  }, [filterValue, value]);
  
   // Function to call the server side filtering
   const callServerFilter = (event, isCleared) => {
    hasFilters = true;
    _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
    if (isCleared) {
        hasFilters = false;
        if (filtered) {
            filterCallback(tableOptionsState, setLoaderFunction);
        }
    }   else {
        tableOptionsState.filters.push({id: Header, value: rangeValue});
        filterCallback(tableOptionsState, setLoaderFunction);
    }
  };

  return (
    <div
      style={{
        alignItems: 'center'
      }}
    >
      <InputText
        value={value[0]}
        type="number"
        tooltip="Enter the minimum value to search"
        onKeyUp={(e) => {
          if (e.key === "Enter" && doServersideFilter) {
            TableUtil.saveFilter(currentTableName, Header, rangeValue);
            setFiltered(true);
            callServerFilter(e, false);
          }
        }}
        onChange={e => {
          setFilter(undefined);  setFiltered(false);
          const val = e.target.value;
          let max = rangeValue[1];
          setValue([val,max]);
          setFilter([val,max] || undefined);
          setRangeValue([val,max]);
          filterValue[0] = val;
          if(storeFilter) {
            TableUtil.saveFilter(currentTableName, Header, [val,max]);
            setFilter([val,max]);
          }
        }}
        style={{
          width: '65px',
          height: '25px'
          // marginRight: '0.5rem',
        }}
        tooltip={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Enter Minimum Range value and press ‘Enter’ key to search"}
      />
      
      <InputText
        value={value[1]}
        type="number"
        tooltip="Enter the maximum value to search"
        onKeyUp={(e) => {
          if (e.key === "Enter" && doServersideFilter) {
            setFiltered(true);
            callServerFilter(e, false);
          }
        }}
        onChange={e => {
          const val = e.target.value;
          let min = rangeValue[0];
          setRangeValue([min,val]);
          filterValue[1] = val;
          setValue([min,val]);
          setFilter([min,val] || undefined);
          if(storeFilter) {
            TableUtil.saveFilter(currentTableName, Header, [min,val]);
            setFilter([min,val]);
          }
        }}
         
        style={{
          width: '65px',
          height: '25px'
        }}
        tooltip={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Enter Maximum Range value and press ‘Enter’ key to search"}
      />
    </div>
  )
}

// Priority Rank Range Filter
function RankRangeFilter({
  column: { filterValue = [], preFilteredRows, setFilter, id, Header },
}) {
  let [rangeValue, setRangeValue] = useState([]);
  const [value, setValue] = useState('');
  const [filtered, setFiltered] = useState(false);
  React.useEffect(() => {
    if (!filterValue && value) {
      setValue('');     
      //setRangeValue([])
    }
    if (storeFilter) {
      const filterValue = TableUtil.getFilter(currentTableName, Header);
      if (filterValue) {
          setFiltered(true);
      }
      if(!value){
          setValue(filterValue);
          //setFilter(filterValue);
      }
    }
  }, [filterValue, value]);
  
   // Function to call the server side filtering
   const callServerFilter = (event, isCleared) => {
    hasFilters = true;
    _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
    if (isCleared) {
        hasFilters = false;
        if (filtered) {
            filterCallback(tableOptionsState, setLoaderFunction);
        }
    }   else {
        tableOptionsState.filters.push({id: Header, value: rangeValue});
        filterCallback(tableOptionsState, setLoaderFunction);
    }
  };

  return (
    <div
      style={{
        alignItems: 'center'
      }}
    >
      <input type="decimal"
          title={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Enter Minimum Range value and press ‘Enter’ key to search"}
          max="1"
          min="0"
          className="p-inputtext p-component"
          value={value[0]}
          step="0.0001"
          onKeyUp={(e) => {
              if (e.key === "Enter" && doServersideFilter) {
                  TableUtil.saveFilter(currentTableName, Header, rangeValue);
                  setFiltered(true);
                  callServerFilter(e, false);
              }
          }}
          onChange={e => {
              setFilter(undefined);  setFiltered(false);
              let val = e.target.value;
              val = val.replace(/([^0-9.]+)/, "");
              const match = /(\d{0,1})[^.]*((?:\.\d{0,4})?)/g.exec(val);
              val = match[1] + match[2];
              if (val == '' || (val >= 0 && val <= 1)) {
                  let max = rangeValue[1];
                  setValue([val,max]);
                  setFilter([val,max] || undefined);
                  setRangeValue([val,max]);
                  filterValue[0] = val;
                  if(storeFilter) {
                      //TableUtil.saveFilter(currentTableName, Header, [val,max]);
                      setFilter([val,max]);
                  }
            }   else {
                e.target.value = rangeValue[0];
            }
          }}
          style={{
            minWidth: '48px',
            maxWidth: '85px',
            width:'100%',
            height: '25px'
          }}
      />
       
      <input type="decimal"
          title={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Enter Maximum Range value and press ‘Enter’ key to search"}
          max="1"
          min="0"
          className="p-inputtext p-component"
          value={value[1]}
          step="0.0001"
          onKeyUp={(e) => {
              if (e.key === "Enter" && doServersideFilter) {
                  TableUtil.saveFilter(currentTableName, Header, rangeValue);
                  setFiltered(true);
                  callServerFilter(e, false);
              }
          }}
          onChange={e => {
              setFilter(undefined);  setFiltered(false);
              let val = e.target.value;
              val = val.replace(/([^0-9.]+)/, "");
              const match = /(\d{0,1})[^.]*((?:\.\d{0,4})?)/g.exec(val);
              val = match[1] + match[2];
              if (val == '' || (val >= 0 && val <= 1)) {
                  let min = rangeValue[0];
                  setRangeValue([min,val]);
                  filterValue[1] = val;
                  setValue([min,val]);
                  setFilter([min,val] || undefined);
                  if(storeFilter) {
                    //TableUtil.saveFilter(currentTableName, Header, [min,val]);
                    setFilter([min,val]);
                  }  
              }   else {
                  e.target.value = rangeValue[0];
              }
          }}
          style={{
            minWidth: '48px',
            maxWidth: '85px',
            width:'100%',
            height: '25px'
          }}
      />
    </div>
  )
}

// Duration Range Filter
function DurationRangeFilter({
  column: { filterValue = [], preFilteredRows, setFilter, id, Header },
}) {
  let [rangeValue, setRangeValue] = useState(['','']);
  const [value, setValue] = useState('');
  const [filtered, setFiltered] = useState(false);
  React.useEffect(() => {
    if (!filterValue && value) {
      setValue('');     
    }
    if (storeFilter) {
      const filterValue = TableUtil.getFilter(currentTableName, Header);
      if (filterValue) {
          setFiltered(true);
      }
      if(filterValue && !value){
          setValue(filterValue);
          setFilter(filterValue);
      }
      if(!filterValue && value.length>0){
        setValue([]);
      }
    }
  }, [filterValue, value]);
  
   // Function to call the server side filtering
   const callServerFilter = (event, isCleared) => {
    hasFilters = true;
    _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
    if (isCleared) {
        hasFilters = false;
        if (filtered) {
            filterCallback(tableOptionsState, setLoaderFunction);
        }
    }   else {
        tableOptionsState.filters.push({id: Header, value: rangeValue});
        filterCallback(tableOptionsState, setLoaderFunction);
    }
  };

  return (
    <div
      onKeyPress={(e) => {
        if (e.key === "Enter" && doServersideFilter) {
          TableUtil.saveFilter(currentTableName, Header, rangeValue);
          setFiltered(true);
          callServerFilter(e, false);
        }
        else if(e.key === "Enter" ) {
          setFilter(rangeValue);
        }
      }}
      style={{
        alignItems: 'center'
      }}
    >
      <InputMask mask="99:99:99"
          value={value[0]}
          placeholder="HH:mm:ss"
          tooltip={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Enter Minimum Range value in HH:mm:ss format and press ‘Enter’ key to search"}
          onChange={e => {
            let val = e.target.value;
            if (val.includes(":") && !Validator.isValidHHmmss(val, true)) {
              val = rangeValue[0];
            }
            let max = rangeValue[1];
            setValue([val,max]);
            if(doServersideFilter) {
              setFilter([val,max] || undefined);
            }
            setRangeValue([val,max]);
            filterValue[0] = val;
            if(storeFilter) {
                TableUtil.saveFilter(currentTableName, Header, [val,max]);
            }
          }}
          style={{
            minWidth: '48px',
            maxWidth: '85px',
            width:'100%',
            height: '25px'
          }}
      />
    
    <InputMask mask="99:99:99"
          value={value[1]}
          tooltip={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Enter Maximum Range value in HH:mm:ss format and press ‘Enter’ key to search"}
          placeholder="HH:mm:ss"
          onChange={e => {
            let val = e.target.value;
            if (val.includes(":") && !Validator.isValidHHmmss(val, true)) {
              val = rangeValue[1];
            }
            let min = rangeValue[0];
            setValue([min,val]);
            if(doServersideFilter) {
              setFilter([min,val] || undefined);
            }
            setRangeValue([min,val]);
            filterValue[1] = val;
            if(storeFilter) {
                TableUtil.saveFilter(currentTableName, Header, [min,val]);
            }
          }}
          style={{
            minWidth: '48px',
            maxWidth: '85px',
            width: '100%',
            height: '25px'
          }}
    />
    </div>
     
  )
}

// Duration Range Filter
function DurationRangeFilterWithDays({
  column: { filterValue = [], preFilteredRows, setFilter, id, Header },
}) {
  let [rangeValue, setRangeValue] = useState([0,0]);
  const [value, setValue] = useState('');
  const [filtered, setFiltered] = useState(false);
  const [filterType, setFilterType]  = useState();

  React.useEffect(() => {
    if (!filterValue && value) {
      setValue('');     
    }
    if (storeFilter) {
      const filterValue = TableUtil.getFilter(currentTableName, Header);
      const storedFilterType = TableUtil.getFilter(currentTableName, `${Header}-FilterOption`);
      if (filterValue) {
          setFiltered(true);
          setFilterType('Range');
      } else {
        setFilterType('All');
      }

      if (storedFilterType) {
        //setFiltered(`${Header}-FilterOption`, true);
        setFilterType(storedFilterType);
      }
      if(!value){
          setValue(filterValue);
      }
    }
  }, [filterValue, value]);
  
   // Function to call the server side filtering
   const callServerFilter = (event, isCleared) => {
    hasFilters = true;
    _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
    if (isCleared) {
      hasFilters = false;
      if (filtered) {
          filterCallback(tableOptionsState, setLoaderFunction);
      }
    }   else {
        tableOptionsState.filters.push({id: Header, value: rangeValue});
        filterCallback(tableOptionsState, setLoaderFunction);
    }
  };
  const filterTypeChangeEvent =(e) => {
      setFilterType(e.value);
      if(e.value === null || e.value === 'All') {
        setFiltered(false);
        _.remove(tableOptionsState.filters, function(filter) { return filter.id === 'durationNull' });
        _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
        callServerFilter(e, true);
      } else if( e.value === 'Range') {
        setFiltered(true);
        setRangeValue([0,0]);
        setValue([0,0]);
        _.remove(tableOptionsState.filters, function(filter) { return filter.id === 'durationNull' });
      } else if( e.value === 'Unknown') {
        setFiltered(true);
        _.remove(tableOptionsState.filters, function(filter) { return filter.id === Header });
        tableOptionsState.filters.push({id: 'durationNull', value: true});
        filterCallback(tableOptionsState, setLoaderFunction);
      }

      if (storeFilter) {
        if (e.value) {
          TableUtil.saveFilter(currentTableName, `${Header}-FilterOption`, e.value);
          tableOptionsState.filters.push({id: `${Header}-FilterOption`, value: e.value});
          setFiltered(true);
        } else {
          TableUtil.saveFilter(currentTableName, `${Header}-FilterOption`, null);
        }
      }
  }

  return (
    <div
      onKeyPress={(e) => {
        if (e.key === "Enter" && doServersideFilter) {
          TableUtil.saveFilter(currentTableName, Header, rangeValue);
          setFiltered(true);
          callServerFilter(e, false);
        }
      }}
      style={{
        alignItems: 'center'
      }}
    >
      <div onClick={e => { e.stopPropagation() }} >
          <div >
              <Dropdown optionLabel="name" optionValue="name"
                        tooltip="Select the Duration filter type to search"
                        value={filterType}
                        options={[{name:'All', value: 'All'},{name:'Range', value: 'Range'},{name:'Unknown', value: 'Unknown'}]}
                        onChange={(e) => {filterTypeChangeEvent(e)}}
                        style={{width: '10em'}}
                        showClear={true}
                        />
              { filterType === 'Range' &&
                  <div style={{marginTop: '1em'}}>
                    <InputMask mask="999 99:99:99"
                        value={value[0]}
                        placeholder="DDD HH:mm:ss"
                        tooltip={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Enter Minimum Range value in DDD HH:mm:ss format and press ‘Enter’ key to search"}
                        onChange={e => {
                          setFilter(undefined);  setFiltered(false);
                          let val = e.target.value;
                          if (val.includes(":") && !Validator.isValidDDDHHmmss(val, false)) {
                            val = rangeValue[0];
                          }
                          let max = rangeValue[1];
                          setValue([val,max]);
                          setFilter([val,max] || undefined);
                          setRangeValue([val,max]);
                          filterValue[0] = val;
                          if(storeFilter) {
                              //TableUtil.saveFilter(currentTableName, Header, [val,max]);
                              setFilter([val,max]);
                          }
                        }}
                        style={{
                          width: '115px',
                          height: '25px'
                        }}
                    />
                  
                    <InputMask mask="999 99:99:99"
                          value={value[1]}
                          tooltip={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Enter Maximum Range value in DDD HH:mm:ss format and press ‘Enter’ key to search"}
                          placeholder="DDD HH:mm:ss"
                          onChange={e => {
                            setFilter(undefined);  setFiltered(false);
                            let val = e.target.value;
                            if (val.includes(":") && !Validator.isValidDDDHHmmss(val, false)) {
                              val = rangeValue[1];
                            }
                            let min = rangeValue[0];
                            setValue([min,val]);
                            setFilter([min,val] || undefined);
                            setRangeValue([min,val]);
                            filterValue[1] = val;
                            if(storeFilter) {
                                //TableUtil.saveFilter(currentTableName, Header, [min,val]);
                                setFilter([min,val]);
                            }
                          }}
                          style={{
                            width: '115px',
                            height: '25px'
                          }}
                    />
                  </div>
              }
          </div>
        </div>
    </div>
     
  )
}

// This is a custom UI for our 'between' or number range
// filter. It uses two number boxes and filters rows to
// ones that have values between the two
function NumberRangeColumnFilter({
  column: { filterValue = [], preFilteredRows, setFilter, id, Header },
}) {
  const [errorProps, setErrorProps] = useState({});
  const [maxErr, setMaxErr] = useState(false);
  const [min, max] = React.useMemo(() => {
    let min = preFilteredRows.length ? preFilteredRows[0].values[id] : 0
    let max = preFilteredRows.length ? preFilteredRows[0].values[id] : 0
    preFilteredRows.forEach(row => {
      min = Math.min(row.values[id], min)
      max = Math.max(row.values[id], max)
    })
    return [min, max]
  }, [id, preFilteredRows])

  return (
    <div
      style={{
        //  display: 'flex',
        //  flexdirection:'column',
        alignItems: 'center'
      }}
    >
      <InputText
        value={filterValue[0]}
        type="number"
        onChange={e => {
          const val = e.target.value;
          setFilter((old = []) => [val ? parseFloat(val, 10) : undefined, old[1]]);
        }}
        placeholder={`Min (${min})`}
        style={{
          width: '55px',
          height: '25px'
          // marginRight: '0.5rem',
        }}
        tooltip={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Enter Minimum Range value and press ‘Enter’ key to search"}
      />
      <InputText
        value={filterValue[1] || ''}
        type="number"
        {...errorProps}
        className={maxErr && 'field-error'}
        onChange={e => {
          const val = e.target.value;
          const minVal = filterValue.length && filterValue[0];
          if (minVal && e.target.value < minVal) {
            setMaxErr(true);
            setErrorProps({
              tooltip: "Max value should be greater than Min",
              tooltipOptions: { event: 'hover' }
            });
          } else {
            setMaxErr(false);
            setErrorProps({});
          }
          setFilter((old = []) => [old[0], val ? parseFloat(val, 10) : undefined])
        }}
        placeholder={`Max (${max})`}
        style={{
          width: '55px',
          height: '25px'
          //  marginLeft: '0.5rem',
        }}
        tooltip={(tableToolTipsState[Header])?tableToolTipsState[Header]:"Enter Maximum Range value and press ‘Enter’ key to search"}
      />
    </div>
  )
}


function fuzzyTextFilterFn(rows, id, filterValue) {
  return matchSorter(rows, filterValue, { keys: [row => row.values[id]] });
}

const filterTypes = {
  'select': {
    fn: SelectColumnFilter,
  },
  // This component has Any and All Radio buttons
  'multiselect': {
    fn: MultiSelectColumnFilter,
    type: multiSelectFilterFn
  },
  // This component does not have Any and All Radio buttons
  'multiselect-filter': {
    fn: MultiSelectFilter,
    type: multiSelectFilterFn
  },
  'switch': {
    fn: BooleanColumnFilter
  },
  'slider': {
    fn: SliderColumnFilter
  },  
  
  'date': {
    fn: CalendarColumnFilter,
    type: dateFilterFn
  },
  'dateRange': {
    fn: DateRangeColumnFilter,
    type: dateRangeFilterFn
  },
  'flatpickrDateRange': {
    fn: FlatpickrRangeColumnFilter,
    type: dateRangeFilterFn
  },
  
  'fromdatetime': {
    fn: DateTimeColumnFilter,
    type: fromDatetimeFilterFn
  },
  'todatetime': {
    fn: DateTimeColumnFilter,
    type: toDatetimeFilterFn
  },
  'range': {
    fn: RangeColumnFilter,
    type: 'between'
  },
  'minMax': {
    fn: NumberRangeColumnFilter,
    type: 'between'
  },
  'numberRangeMinMax': {
    fn: NumberRangeFilter,
    type: 'between'
  },
  'rankMinMax': {
    fn: RankRangeFilter,
    type: 'between'
  },
  'durationMinMax': {
    fn: DurationRangeFilter,
    type: durationTimeFilterFn
  },
  'durationWithDaysMinMax': {
    fn: DurationRangeFilterWithDays,
    type: 'between'
  }
};

// Let the table remove the filter if the string is empty
fuzzyTextFilterFn.autoRemove = val => !val

const IndeterminateCheckbox = React.forwardRef(
  ({ indeterminate, ...rest }, ref) => {
    const defaultRef = React.useRef()
    const resolvedRef = ref || defaultRef
    React.useEffect(() => {
      resolvedRef.current.indeterminate = indeterminate
    }, [resolvedRef, indeterminate])
    return <input type="checkbox" ref={resolvedRef} {...rest}/>
  }
);
 
// ViewTable table component
function Table(props) {
  let {fetchData,  pageCount: controlledPageCount, currentPage, dataFetchStatus, columns, data, defaultheader, optionalheader, 
    tablename, defaultSortColumn, defaultpagesize, columnOrders, showAction, toggleBySorting, onColumnToggle, lsKeySortColumn
    , descendingColumn, ignoreSorting } = props;
  ignoreSorting = ignoreSorting ||[];
  ignoreSorting = [...ignoreSorting,'action'];
  descendingColumn = descendingColumn || [];
  const checkDefaultSortColumnEmpty = () => {
    return !defaultSortColumn || !defaultSortColumn[0] || Object.keys(defaultSortColumn[0]).length === 0;
  }
  const checkDescendingColumnExists = (value) => {
    return descendingColumn.includes(value);
  }
  const checkToIgnoreSorting = (value) => {
    return ignoreSorting.includes(value);
  }
  const getFirstVisibleColumn = (selectedColumn, tempAllColumns) => {
    let selected = {};
    let tempColumn = {};
    let totalColumns = undefined;

    if (tempAllColumns && tempAllColumns.length > 0) {
      totalColumns = tempAllColumns;
    }

    if (totalColumns) {
      for (let i = 0; i < totalColumns.length; i++) {
        tempColumn = { ...totalColumns[i] };
        if (tempColumn.Header && typeof tempColumn.Header === "string") {
          if (tempColumn.Header.toLowerCase() === selectedColumn.Header.toLowerCase()) {
            tempColumn.isVisible = selectedColumn.isVisible;
          }
          if (!checkToIgnoreSorting(tempColumn.Header.toLowerCase()) && tempColumn.isVisible) {
            selected = tempColumn;
            break;
          }
        }
      }
    }
    return selected;
  }

  if (checkDefaultSortColumnEmpty()) {
    let tempVisibleColumn = getFirstVisibleColumn({ Header: '' }, columns);
    defaultSortColumn = [{ id: tempVisibleColumn.Header, desc: checkDescendingColumnExists(tempVisibleColumn.Header.toLowerCase()) }];
  }

  const filterTypes = React.useMemo(
    () => ({
      // Add a new fuzzyTextFilterFn filter type.
      fuzzyText: fuzzyTextFilterFn,
      // Or, override the default text filter to use
      // "startWith"
      text: (rows, id, filterValue) => {
        return rows.filter(row => {
          const rowValue = row.values[id]
          return rowValue !== undefined
            ? String(rowValue)
              .toLowerCase()
              .startsWith(String(filterValue).toLowerCase())
            : true
        })
      },
    }),
    []
  )

  const defaultColumn = React.useMemo(
    () => ({
      // Let's set up our default Filter UI
      Filter: DefaultColumnFilter,
      minWidth: 60,
      maxWidth: 250
    }),
    []
  )

  let tableParams = {
    columns,
    data,
    defaultColumn,
    filterTypes,
    initialState: {
      pageIndex: doServersideFilter?currentPage:0,
      pageSize: (defaultpagesize && defaultpagesize > 0) ? defaultpagesize : 10,
      sortBy: defaultSortColumn
    },
    manualPagination: doServersideFilter,
    manualSortBy: doServersideFilter,
    manualFilters: doServersideFilter,
    //autoResetPage: false,
    //autoResetSortBy: false,
    // pageCount: controlledPageCount,
    getExportFileBlob,
  };
  if (doServersideFilter) {
    tableParams.pageCount = controlledPageCount;
  }
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    setAllFilters,
    allColumns,
    getToggleHideAllColumnsProps,
    visibleColumns,
    state,
    page,
    preGlobalFilteredRows,
    setGlobalFilter,
    setHiddenColumns,
    //gotoPage,
   // setPageSize,
    selectedFlatRows,
    setColumnOrder,
    exportData,
    // pageCount,
    gotoPage,
    setPageSize,
    state: {sortBy, pageIndex, pageSize },
  } = tblinstance = useTable(
    {...tableParams},
    useFilters,
    useGlobalFilter,
    useSortBy,
    usePagination,
    useRowSelect,
    useColumnOrder,
    useExportData,
    useFlexLayout,
    useResizeColumns
  );
  const currentColOrder = React.useRef();
  let pageCount = doServersideFilter?controlledPageCount:data.length;
  tmpTableData = data;  
  // while siwtch the task type or Su type, this will set the relavent default sort column
  if (currentTableName && currentTableName !== tablename) {
      state.sortBy = defaultSortColumn;
  }
  currentTableName = props.tablename;
  //if (!tableOptionsState) {
    tableOptionsState = _.cloneDeep(state);
  //}
  // Pass the table's state to the parent function if the parent function has set the callback function for it.
  if (props.setTableState) {
    props.setTableState(state);
  }
  const [loading, setLoading] = React.useState(false);
  setLoaderFunction = setLoading;
  React.useEffect(() => {
    fetchData({ state, setLoading });
    }, [sortBy, fetchData, pageIndex, pageSize,  filterTypes,]);

  React.useEffect(() => {
    setHiddenColumns(
      //  columns.filter(column => !column.isVisible).map(column => column.accessor)
      columns.filter(column => !column.isVisible).map(column => column.id)
    );
    // console.log('columns List', visibleColumns.map((d) => d.id));
    const storedColOrder = UtilService.localStore({ type: 'get', key: tablename+'colOrder'});
    if (storedColOrder) {
      setColumnOrder(storedColOrder)
    }
    else if (columnOrders && columnOrders.length) {
      if (showAction === 'true') {
        setColumnOrder(['Select', 'Action', ...columnOrders]);
        UtilService.localStore({ type: 'set', key: tablename+'colOrder', value: ['Select', 'Action', ...columnOrders]});
      } else {
        setColumnOrder(['Select', ...columnOrders]);
        UtilService.localStore({ type: 'set', key: tablename+'colOrder', value: ['Select', ...columnOrders]});
      }
    }
    setLoading(dataFetchStatus);
  }, [setHiddenColumns, columns]);

  let op = useRef(null);

  const [currentpage, setcurrentPage] = React.useState(0);
  const [selectedClickedRow, setSelectedClickedRow] = React.useState([]);
  const [currentrows, setcurrentRows] = React.useState(defaultpagesize);
  const [custompagevalue, setcustompagevalue] = React.useState();
  
  const onPagination = (e) => {
    loadingStatus = true;
    setLoading(true);
    gotoPage(e.page);
    setcurrentPage(e.first);
    setcurrentRows(e.rows);
    setPageSize(e.rows)
    if ([10, 25, 50, 100].includes(e.rows)) {
      setcustompagevalue();
    }
  };
  const onCustomPage = (e) => {
    loadingStatus = true;
    setLoading(true);
    if (typeof custompagevalue === 'undefined' || custompagevalue == null) return;
    gotoPage(0);
    setcurrentPage(0);
    setcurrentRows(custompagevalue);
    setPageSize(custompagevalue);
  };

  const onChangeCustompagevalue = (e) => {
    setcustompagevalue(e.target.value);
  }

  const onShowAllPage = (e) => {
    loadingStatus = true;
    setLoading(true);
    gotoPage(0);
    setcurrentPage(0);
    setcurrentRows(0);
    setPageSize(pageCount)
    setcustompagevalue();
  };

  const onColumnToggleViewTable = (selectedColumn, sortedColumn) => {
    let visibleColumn = {};
    let viewColumn = {};
    if (selectedColumn && selectedColumn.Header === sortedColumn.Header && !selectedColumn.isVisible) {
      visibleColumn = getFirstVisibleColumn(selectedColumn, allColumns);     
      viewColumn = { Header: visibleColumn.Header, desc: checkDescendingColumnExists(visibleColumn.Header.toLowerCase())};
      let tempdefaultSortColumn = [{ id: viewColumn.Header, desc: viewColumn.desc }];
      if (lsKeySortColumn && lsKeySortColumn.trim().length > 0) {
        localStorage.setItem(lsKeySortColumn, JSON.stringify(tempdefaultSortColumn));
      }
    }
    visibleColumn.Header = visibleColumn.Header || "";
    return viewColumn;
  }

  const onToggleChange = (e) => {
    let lsToggleColumns = [];
    let selectedColumn = null;
    let sortedColumn = {};
    let defaultVisible = false;
    if (e.target.id === '') {
      defaultVisible = e.target.checked;
    } 
    // allColumns.forEach(acolumn => {
    for (const acolumn of allColumns) {
      let jsonobj = {};
      let visible = (acolumn.Header === e.target.id) ? ((acolumn.isVisible) ? false : true) : e.target.id === '' ? defaultVisible : acolumn.isVisible;
      jsonobj['Header'] = acolumn.Header;
      jsonobj['isVisible'] = visible;
      lsToggleColumns.push(jsonobj)
      selectedColumn = (acolumn.Header === e.target.id) ? jsonobj : selectedColumn;
      if (acolumn.isSorted) {
        sortedColumn['Header'] = acolumn.Header;
        sortedColumn['isVisible'] = visible;
      }
      // Remove the column filters stored and clear the column filter, if the column is toogled to 
      if (!visible) {
          if (storeFilter) {
              TableUtil.clearColumnFilter(currentTableName, acolumn.Header);
          }
          _.remove(tableOptionsState.filters, ['id', acolumn.Header]);
          setAllFilters(tableOptionsState.filters);
      }
    }
  // });
    localStorage.setItem(tablename, JSON.stringify(lsToggleColumns));

    if (onColumnToggleViewTable) {
      let columnTobeSorted = onColumnToggleViewTable(selectedColumn, sortedColumn); //onColumnToggle(selectedColumn, sortedColumn);
      columnTobeSorted.Header = columnTobeSorted.Header || "";
      if (columnTobeSorted.Header.trim().length > 0) {
        tblinstance.toggleSortBy(columnTobeSorted.Header, columnTobeSorted.desc);
      }
    }   
  }
  
  filteredData = _.map(rows, 'values');
  if (parentCallbackFunction) {
    parentCallbackFunction(filteredData);
  }

  /** Assign current table instance to variable in parent class - just used for refresh the filter state*/
  if (tableInstanceRef) {
    tableInstanceRef(tblinstance);
  }

  /* Select only rows than can be selected. This is required when ALL is selected */
  selectedRows = _.filter(selectedFlatRows, selectedRow => { return (selectedRow.original.canSelect === undefined || selectedRow.original.canSelect) });
  /* Take only the original values passed to the component */
  selectedRows = _.map(selectedRows, 'original');
  /* Callback the parent function if available to pass the selected records on selection */
  if (parentCBonSelection && selectedRows != selectedClickedRow && selectedRows.length != 0) {
    parentCBonSelection(selectedRows)
  }

  const onSortBy = () => {
    sessionStorage.setItem("sortedData", tbldata);
  }

  /**
   * Clear all filters in table and reload the data
   */
  const clearAllFilter = () => {
      // Call parent function during all clear
      if (clearAllFuncCallback) {
        clearAllFuncCallback();
      }
    hasFilters = false;
    setAllFilters([]);
    tableOptionsState.filters = [];
    if (doServersideFilter) {
      filterCallback(tableOptionsState, setLoaderFunction);
    }
    if (storeFilter) {
        TableUtil.clearTableFilter(currentTableName);
    }
  }
  
  return (
    <>
      <div style={{display:'flex',justifyContent:'space-between',height:'35px'}}>
        <div id="block_container" >
          {allowColumnSelection &&
            <div style={{ textAlign: 'left', marginRight: '30px' }} title='Toggle Columns'>
              <i className="fa fa-columns col-filter-btn" label="Toggle Columns" onClick={(e) => op.current.toggle(e)} />
              {showColumnFilter &&
                <div style={{ position: "relative", top: "-25px", marginLeft: "50px", color: "#005b9f" }} onClick={() => clearAllFilter()} >
                  <i class="fas fa-sync-alt" title="Clear All Filters"></i></div>}
              <OverlayPanel ref={op} id="overlay_panel" showCloseIcon={false} >
                <div>
                  <div style={{ textAlign: 'center' }}>
                    <label>Select column(s) to view</label>
                  </div>
                  <div style={{ float: 'left', backgroundColor: '#d1cdd936', width: '250px', height: '400px', overflow: 'auto', marginBottom: '10px', padding: '5px' }}>
                    <div id="tagleid"  >
                      <div >
                        <div style={{ marginBottom: '5px' }}>
                          <IndeterminateCheckbox {...getToggleHideAllColumnsProps()} onClick={(e) => onToggleChange(e)} /> Select All
                            </div>
                        {allColumns.map(column => (
                          <div key={column.id} style={{ 'display': column.id !== 'actionpath' ? 'block' : 'none' }}>
                            <input type="checkbox" {...column.getToggleHiddenProps()}
                              id={(defaultheader[column.id]) ? defaultheader[column.id] : (optionalheader[column.id] ? optionalheader[column.id] : column.id)}
                              onClick={(e) => onToggleChange(e)}
                            /> {
                              (defaultheader[column.id]) ? defaultheader[column.id] : (optionalheader[column.id] ? optionalheader[column.id] : column.id)}
                          </div>
                        ))}
                        <br />
                      </div>
                    </div>
                  </div>
                </div>
              </OverlayPanel>
            </div>
          }
          <div style={{ textAlign: 'right' }}>
            {tbldata && tbldata.length > 0 && !isunittest && showGlobalFilter &&
              <GlobalFilter
                preGlobalFilteredRows={preGlobalFilteredRows}
                globalFilter={state.globalFilter}
                setGlobalFilter={setGlobalFilter}
              />
            }
          </div>

          {showTopTotal && !hasFilters &&
            <div className="total_records_top_label"> <label >Total records ({pageCount})</label></div>
          }

          {showTopTotal && hasFilters &&
            <div className="total_records_top_label" ><label >Filtered {filteredData.length} from {pageCount}</label></div>}
         
        </div>
        {showCSV &&
          <div className="total_records_top_label" style={{ marginTop: '3px', marginRight: '5px' }} >
            <a href="#" onClick={() => { exportData("csv", false); }} title="Download CSV" style={{ verticalAlign: 'middle' }}>
              <i class="fas fa-file-csv" style={{ color: 'green', fontSize: '20px' }} ></i>
            </a>
          </div>
          /* 
            <div className="total_records_top_label" >
              <a href="#"  onClick={() => {exportData("pdf", false);}} title="Download PDF" style={{verticalAlign: 'middle'}}>
                  <i class="fas fa-file-pdf" style={{color: 'red', fontSize: '20px'}}></i>
              </a>
            </div> */
        }
      </div>

      <div className="tmss-table table_container">
        <table {...getTableProps()} data-testid="viewtable" className="viewtable" >
          <thead>
            {headerGroups.map(headerGroup => (
              <DragDropContext
                onDragStart={() => {
                  currentColOrder.current = allColumns.map(column => column.id);
                }}
                onDragUpdate={(dragUpdateObj, b) => {
                  const colOrder = [...currentColOrder.current];
                  const sIndex = dragUpdateObj.source.index;
                  const dIndex = dragUpdateObj.destination && dragUpdateObj.destination.index;
                  if(typeof sIndex === 'number' && typeof dIndex === "number") {
                    colOrder.splice(sIndex, 1);
                    colOrder.splice(dIndex, 0, dragUpdateObj.draggableId);
                    setColumnOrder(colOrder);
                    UtilService.localStore({ type: 'set', key: tablename+'colOrder', value: colOrder}); 
                  }
                }}
              >
                <Droppable droppableId="droppable" direction="horizontal">
                  {(droppableProvided, snapshot) => (
                    <tr {...headerGroup.getHeaderGroupProps()}
                    ref={droppableProvided.innerRef}>
                      {headerGroup.headers.map((column,index) => (
                        <Draggable
                        key={column.id}
                        draggableId={column.id}
                        index={index}
                        isDragDisabled={_.includes(fixedColumns, column.id)? true: false}>
                          {(provided, snapshot) => {
                            if (column.id !== 'actionpath') {
                            return (
                              <th className={column.id} className={_.includes(fixedColumns, column.id)?'fixed-column-td':''} style={{display: 'flex'}}
                                onClick={() => {
                                  if(!doServersideFilter) {
                                    if(!column.disableSortBy) {
                                      toggleBySorting({ 'id': column.id, desc: (column.isSortedDesc != undefined ? !column.isSortedDesc : false) });
                                    } 
                                  }
                              }}>
                                <div style={{display:'flex'}}>
                                <div style={{display: 'grid',verticalAlign:'bottom'}}>
                                  <div {...column.getHeaderProps(column.getSortByToggleProps())} className={_.includes(fixedColumns, column.id)?'fixed-column':''}>
                                  <div
                                    {...provided.draggableProps}
                                    {...provided.dragHandleProps}
                                    // {...extraProps}
                                    ref={provided.innerRef}
                                    style={{
                                      ...getItemStyle(
                                        snapshot,
                                        provided.draggableProps.style
                                      )
                                      // ...style
                                    }}>
                                    {column.Header !== 'actionpath' && column.render('Header')}
                                    {column.Header !== 'Action' ?
                                      column.isSorted ? (column.isSortedDesc ? <i className="pi pi-sort-down" aria-hidden="true"></i> : <i className="pi pi-sort-up" aria-hidden="true"></i>) : ""
                                      : ""
                                    }
                                  </div>
                                </div>
                                {/* Render the columns filter UI */}
                                {column.Header !== 'actionpath' &&
                                  // <div className={columnclassname[0][column.Header]}>
                                  <div {...column.getHeaderProps(column.getSortByToggleProps())} >
                                    {column.canFilter && column.Header !== 'Action' ? column.render('Filter') : null}
                                  </div>
                                }
                                </div>
                                </div>
                                {_.includes(fixedColumns, column.id)?<></>:
                                <div {...column.getResizerProps()}
                                      className={`resizer ${
                                        column.isResizing ? 'isResizing' : ''
                                      }`}
                                    >
                                </div> 
                                }
                              </th>
                            );
                              } else {
                                return "";
                              }
                          }}
                        </Draggable>
                      ))}
                    </tr>
                  )}
                </Droppable>
              </DragDropContext>
            ))}
            {(doServersideFilter && loading) && 
            <tr style={{height: "5px"}}><td colSpan={columns.length} style={{padding: "0px"}}>
            <div><ProgressBar mode="indeterminate" style={{ height: '5px' }}/></div>
            </td></tr>}
          </thead>
          {/* If want to to clear the existing data while loading, remove the commented line below */}
          {/* {((doServersideFilter && !loading) || !doServersideFilter) &&  */}
          <tbody {...getTableBodyProps()}>
            {page.map((row, i) => {
              prepareRow(row)
              return (
                <tr {...row.getRowProps()}>
                  {row.cells.map(cell => {
                    if (cell.column.id !== 'actionpath') {
                      // return <td {...cell.getCellProps()} className={cell.column.id+'_body'}>
                      return <td className={cell.column.id+'_body'} className={_.includes(fixedColumns, cell.column.id)?'fixed-column-td':''}>
                        {(cell.row.original.links || []).includes(cell.column.id) ? <a href={cell.row.original.linksURL[cell.column.id]}>{cell.render('Cell', cell.getCellProps())}</a> : cell.render('Cell', cell.getCellProps())}
                      </td>
                    }
                    else {
                      return "";
                    }
                  }
                  )}
                </tr>
              );
            })}
            
          </tbody>
          {/* } */}
        </table>
      </div>
      <div>{(doServersideFilter && loading) && <ProgressBar mode="indeterminate" style={{ height: '5px' }}/>}</div>
      <div className="pagination p-grid" >
        {tableOptionsState.filters.length === 0 &&
          <div className="total_records_bottom_label" ><label >Total records ({pageCount})</label></div>
        }
        {tableOptionsState.filters.length > 0 &&
          <div className="total_records_bottom_label" ><label >Filtered {filteredData.length} from {pageCount}</label></div>
        }
        <div>
          <Paginator rowsPerPageOptions={[10, 25, 50, 100]} first={currentpage} rows={currentrows} totalRecords={doServersideFilter?pageCount:rows.length} onPageChange={onPagination}></Paginator>
        </div>
        <div>
          <InputNumber id="custompage" value={custompagevalue} onChange={onChangeCustompagevalue}
            min={0} style={{ width: '100px' }} />
          <label >Records/Page</label>
          <Button onClick={onCustomPage}> Show </Button>
          <Button onClick={onShowAllPage} style={{ marginLeft: "1em" }}> Show All </Button>
        </div>
      </div>
    </>
  )
}


// Define a custom filter filter function!
function filterGreaterThan(rows, id, filterValue) {
  return rows.filter(row => {
    const rowValue = row.values[id]
    return rowValue >= filterValue
  })
}

// This is an autoRemove method on the filter function that
// when given the new filter value and returns true, the filter
// will be automatically removed. Normally this is just an undefined
// check, but here, we want to remove the filter if it's not a number
filterGreaterThan.autoRemove = val => typeof val !== 'number'

function ViewTable(props) {
  const history = useHistory();
  tbldata = JSON.parse(sessionStorage.getItem("sortedData")) || props.data;
  data = tbldata;
  let pageCount = props.totalPage || data.length;
  showCSV = (props.showCSV) ? props.showCSV : false;
  doServersideFilter = (props.callBackFunction)?true:false;
  parentCallbackFunction = props.filterCallback;
  parentCBonSelection = props.onRowSelection;
  isunittest = props.unittest;
  columnclassname = props.columnclassname;
  loadingStatus = props.loadingStatus === undefined ? loadingStatus :  props.loadingStatus;
  showTopTotal = props.showTopTotal === undefined ? true : props.showTopTotal;
  showGlobalFilter = props.showGlobalFilter === undefined ? true : props.showGlobalFilter;
  showColumnFilter = props.showColumnFilter === undefined ? true : props.showColumnFilter;
  allowColumnSelection = props.allowColumnSelection === undefined ? true : props.allowColumnSelection;
  allowRowSelection = props.allowRowSelection === undefined ? false : props.allowRowSelection;
  let pageUpdated = props.pageUpdated === undefined ? true : props.pageUpdated;

  // Default Header to show in table and other columns header will not show until user action on UI
  clearAllFuncCallback = props.clearAllFuncCallback;
  tableInstanceRef = props.tableInstanceRef;
  let defaultheader = props.defaultcolumns;
  let optionalheader = props.optionalcolumns;
  let defaultSortColumn = props.defaultSortColumn;
  storeFilter = props.storeFilter? props.storeFilter : false
  let tablename = (props.tablename) ? props.tablename : window.location.pathname;

  if (!defaultSortColumn) {
    defaultSortColumn = [{}];
  }
  let defaultpagesize = (typeof props.defaultpagesize === 'undefined' || props.defaultpagesize == null) ? 10 : props.defaultpagesize;
  let columns = [];
  let defaultdataheader = Object.keys(defaultheader[0]);
  let optionaldataheader = Object.keys(optionalheader[0]);

  // Get Tooltips for each column if provided and used in filter components
  tableToolTipsState = {};
  for(const headerId of defaultdataheader) {
      if (defaultheader[0][headerId].tooltip) {
          tableToolTipsState[defaultheader[0][headerId].name] = defaultheader[0][headerId].tooltip;
      }
   }
  for(const headerId of optionaldataheader) {
    if (optionalheader[0][headerId].tooltip) {
        tableToolTipsState[optionalheader[0][headerId].name] = optionalheader[0][headerId].tooltip;
    }
  }

  /* If allowRowSelection property is true for the component, add checkbox column as 1st column.
     If the record has property to select, enable the checkbox */
  if (allowRowSelection) {
    columns.push({
      Header: ({ getToggleAllRowsSelectedProps }) => {
        return (
          <div>
            <IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} style={{ width: '15px', height: '15px' }} />
          </div>
        )
      },
      id: 'Select',
      accessor: props.keyaccessor,
      Cell: ({ row }) => {     
        return (
          <div>
            {(row.original.canSelect === undefined || row.original.canSelect) &&
              <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} 
              attr-id={row.original.id}
              style={{ width: '15px', height: '15px' }} />
            }
            {row.original.canSelect === false &&
              <input type="checkbox" checked={false} disabled style={{ width: '15px', height: '15px' }}></input>
            }
          </div>
        )
      },
      disableFilters: true,
      disableSortBy: true,
      isVisible: true,
    });
  }

  if (props.showaction) {
    columns.push({
      Header: 'Action',
      id: 'Action',
      accessor: props.keyaccessor,
      Cell: props => <Link to={{pathname: props.cell.row.values['actionpath']}} className='p-link' onClick={(e) => navigateTo(e, props)} ><i className="fa fa-eye" style={{ cursor: 'pointer' }}></i></Link>,
      disableFilters: true,
      disableSortBy: true,
      //isVisible: defaultdataheader.includes(props.keyaccessor),
      isVisible: true
    })
  }

  const navigateTo = ( cellProps) =>() => {
    if (cellProps.cell.row.values['actionpath']) {
      if (!props.viewInNewWindow) {
        return history.push({
          pathname: cellProps.cell.row.values['actionpath'],
          state: {
            "id": cellProps.value,
          }
        })
      } else {
        window.open(cellProps.cell.row.values['actionpath'], '_blank');
      }
    }
    else {
      props.actionCallback(cellProps.cell.row.values);
    }
  }

  //Default Columns
  defaultdataheader.forEach(header => {
    const isString = typeof defaultheader[0][header] === 'string';
    const disableSortBy = defaultheader[0][header].disableSortBy;
    const disableFilter = defaultheader[0][header].disableFilters;
    const filterFn = (showColumnFilter ? (isString ? (defaultheader[0][header].filter==='none'?"":DefaultColumnFilter) : (filterTypes[defaultheader[0][header].filter] && filterTypes[defaultheader[0][header].filter].fn ? filterTypes[defaultheader[0][header].filter].fn : (defaultheader[0][header].filter==='none'?"":DefaultColumnFilter))) : "");
    const filtertype = (showColumnFilter ? (!isString && filterTypes[defaultheader[0][header].filter] && filterTypes[defaultheader[0][header].filter].type) ? filterTypes[defaultheader[0][header].filter].type : 'fuzzyText' : "");
    columns.push({
      Header: isString ? defaultheader[0][header] : defaultheader[0][header].name,
      id: isString ? defaultheader[0][header] : defaultheader[0][header].name,
      accessor: header,
      filter: filtertype,
      Filter: filterFn,
      disableSortBy: doServersideFilter?(typeof disableSortBy !== 'undefined' ? disableSortBy : true):(disableSortBy || false),
      disableFilters: doServersideFilter?typeof disableFilter !== 'undefined' ? disableFilter : true:false,
      //minResizeWidth: 50,
      //*** TO REMOVE - INCOMING CHANGE */
      // filter: (showColumnFilter?((!isString && defaultheader[0][header].filter=== 'date') ? 'includes' : 'fuzzyText'):""),
      // Filter: (showColumnFilter?(isString ? DefaultColumnFilter : (filterTypes[defaultheader[0][header].filter] ? filterTypes[defaultheader[0][header].filter] : DefaultColumnFilter)):""),
      isVisible: true,
      Cell: props => { return <div style={{...props.style}}> {updatedCellvalue(header, props.value, defaultheader[0][header])} </div>},
    })
  })

  //Optional Columns
  optionaldataheader.forEach(header => {
    const isString = typeof optionalheader[0][header] === 'string';
    const disableSortBy = optionalheader[0][header].disableSortBy;
    const disableFilter = optionalheader[0][header].disableFilters;
    const filterFn = (showColumnFilter ? (isString ? (optionalheader[0][header].filter==='none'?"":DefaultColumnFilter) : (filterTypes[optionalheader[0][header].filter] && filterTypes[optionalheader[0][header].filter].fn ? filterTypes[optionalheader[0][header].filter].fn : (optionalheader[0][header].filter==='none'?"":DefaultColumnFilter))) : "");
    const filtertype = (showColumnFilter ? (!isString && filterTypes[optionalheader[0][header].filter]) ? (filterTypes[optionalheader[0][header].filter].type || filterTypes[optionalheader[0][header].filter]) : 'fuzzyText' : "");
    columns.push({
      Header: isString ? optionalheader[0][header] : optionalheader[0][header].name,
      id: isString ? header : optionalheader[0][header].name,
      accessor: header,
      filter: filtertype,
      Filter: filterFn,
      disableSortBy: doServersideFilter?typeof disableSortBy !== 'undefined' ? disableSortBy : true:false,
      disableFilters: doServersideFilter?typeof disableFilter !== 'undefined' ? disableFilter : true:false,
      isVisible: false,
      Cell: props => <div style={{...props.style}}> {updatedCellvalue(header, props.value, optionalheader[0][header])} </div>,
    })
  });

  let togglecolumns = localStorage.getItem(tablename);
  if (togglecolumns) {
    togglecolumns = JSON.parse(togglecolumns);
    columns.forEach(column => {
      let tcolumn = _.find(togglecolumns, { Header: column.Header });
      column['isVisible'] = (tcolumn) ? tcolumn.isVisible : column.isVisible;
    });
  }

  function updatedCellvalue(key, value, properties) {
    try {
      if (typeof value == "boolean") {
        return value.toString();
      } else if (typeof value == "string") {
        const format = properties ? properties.format : 'YYYY-MM-DD HH:mm:ss';
        const dateval = moment(value, moment.ISO_8601).format(format);
        if (dateval !== 'Invalid date') {
          return dateval;
        }
      }
    } catch (err) {
      console.error('Error', err)
    }
    return value;
  };

  /**
   * To fetch data from server side - Start
   */
  // const [loading, setLoading] = React.useState(false);
  const [currentPage, setCurrentPage] = React.useState(0);
  const fetchData = React.useCallback( ({ state, setLoading }) => {
      loadServerData(state, setLoading, true);
  }, []);
  
  const loadServerData = (state, setLoading, onload) => {
      //setLoading(true);
      loadingStatus = true;
      setCurrentPage(state.pageIndex);
      if(props.callBackFunction) {
        if(storeFilter) {
          if (onload) {
            let filters = UtilService.localStore({ type: 'get', key: tablename });
            UtilService.localStore({ type: 'set', key: tablename, value: filters});    
          } else {
            UtilService.localStore({ type: 'set', key: tablename, value: state.filters});    
          }
        }
          const promises = [props.callBackFunction(state)];
          Promise.all(promises).then(async responses => {
              tbldata = responses[0][0];
              if (tbldata) {
                  //setData(tbldata);
                  //setPageCount(Math.ceil(responses[0][1]));
                  pageCount = await Math.ceil(responses[0][1]);
                  if (setLoading) {
                    setLoading(false);
                  }
                  loadingStatus = false;
              }
          });
      } else {
          if(tbldata) {
              const startRow = state.pageSize * state.pageIndex;
              const endRow = startRow + state.pageSize;
              //setData(tbldata.slice(startRow, endRow));
              //setPageCount(Math.ceil(tbldata.length));
              data = tbldata.slice(startRow, endRow);
              pageCount = Math.ceil(tbldata.length);
              setLoading(false);
              loadingStatus = false;
          }
      }
  }
  // Set the filterCallback function to load on filter changes
  filterCallback = loadServerData;
  // Set the reloadCallback function in the parent if it has passed the callback function.
  if (props.setTableReloadFunction) {
    props.setTableReloadFunction(loadServerData);
  }
  // Callback function to load on option list values
  showFilterOption = props.showFilterOption;
  
  //If page not load with fresh data then set existing data, otherwise it will reset the checkbox selection in table
  if (!pageUpdated) {
      data = tmpTableData;
  }
  return (
    <div>
      <Table fetchData={fetchData} pageCount={pageCount} currentPage={currentPage} dataFetchStatus={loadingStatus} columns={columns}
        data={data} defaultheader={defaultheader[0]} optionalheader={optionalheader[0]} showAction={props.showaction}
        defaultSortColumn={defaultSortColumn} tablename={tablename} defaultpagesize={defaultpagesize} columnOrders={props.columnOrders} 
        toggleBySorting={(sortData) => {if(props.toggleBySorting){props.toggleBySorting(sortData)}}} onColumnToggle={props.onColumnToggle} lsKeySortColumn={props.lsKeySortColumn}
        descendingColumn={props.descendingColumn} ignoreSorting={props.ignoreSorting} setTableState={props.setTableState} />
    </div>
  )
}

export default ViewTable