/* Minification failed. Returning unminified contents.
(1,15): run-time error CSS1031: Expected selector, found '='
(1,15): run-time error CSS1025: Expected comma or open brace, found '='
(2,16): run-time error CSS1031: Expected selector, found '='
(2,16): run-time error CSS1025: Expected comma or open brace, found '='
(3,22): run-time error CSS1031: Expected selector, found '='
(3,22): run-time error CSS1025: Expected comma or open brace, found '='
(5,1): run-time error CSS1019: Unexpected token, found '$'
(5,2): run-time error CSS1019: Unexpected token, found '('
(5,11): run-time error CSS1031: Expected selector, found ')'
(5,11): run-time error CSS1025: Expected comma or open brace, found ')'
(15,2): run-time error CSS1019: Unexpected token, found ')'
(17,10): run-time error CSS1031: Expected selector, found 'initTooltips('
(17,10): run-time error CSS1025: Expected comma or open brace, found 'initTooltips('
(22,10): run-time error CSS1031: Expected selector, found 'initScrollTop('
(22,10): run-time error CSS1025: Expected comma or open brace, found 'initScrollTop('
(26,10): run-time error CSS1031: Expected selector, found 'showScrollTop('
(26,10): run-time error CSS1025: Expected comma or open brace, found 'showScrollTop('
(42,10): run-time error CSS1031: Expected selector, found 'scrollToTop('
(42,10): run-time error CSS1025: Expected comma or open brace, found 'scrollToTop('
(48,10): run-time error CSS1031: Expected selector, found 'showDashboard('
(48,10): run-time error CSS1025: Expected comma or open brace, found 'showDashboard('
(59,10): run-time error CSS1031: Expected selector, found 'toggleDashboard('
(59,10): run-time error CSS1025: Expected comma or open brace, found 'toggleDashboard('
(66,10): run-time error CSS1031: Expected selector, found 'showDivFromCookieSetting('
(66,10): run-time error CSS1025: Expected comma or open brace, found 'showDivFromCookieSetting('
(83,10): run-time error CSS1031: Expected selector, found 'toggleDivFromCookieSetting('
(83,10): run-time error CSS1025: Expected comma or open brace, found 'toggleDivFromCookieSetting('
(96,10): run-time error CSS1031: Expected selector, found 'setCookie('
(96,10): run-time error CSS1025: Expected comma or open brace, found 'setCookie('
(104,10): run-time error CSS1031: Expected selector, found 'getCookie('
(104,10): run-time error CSS1025: Expected comma or open brace, found 'getCookie('
(123,10): run-time error CSS1031: Expected selector, found 'allowDrop('
(123,10): run-time error CSS1025: Expected comma or open brace, found 'allowDrop('
(127,10): run-time error CSS1031: Expected selector, found 'navigateToPage('
(127,10): run-time error CSS1025: Expected comma or open brace, found 'navigateToPage('
(130,10): run-time error CSS1031: Expected selector, found 'reloadPage('
(130,10): run-time error CSS1025: Expected comma or open brace, found 'reloadPage('
(139,10): run-time error CSS1031: Expected selector, found 'consolelog('
(139,10): run-time error CSS1025: Expected comma or open brace, found 'consolelog('
(186,10): run-time error CSS1031: Expected selector, found 'toInt('
(186,10): run-time error CSS1025: Expected comma or open brace, found 'toInt('
(189,10): run-time error CSS1031: Expected selector, found 'printPage('
(189,10): run-time error CSS1025: Expected comma or open brace, found 'printPage('
(194,10): run-time error CSS1031: Expected selector, found 'toggleDiv('
(194,10): run-time error CSS1025: Expected comma or open brace, found 'toggleDiv('
(198,10): run-time error CSS1031: Expected selector, found 'initPrintOption('
(198,10): run-time error CSS1025: Expected comma or open brace, found 'initPrintOption('
(206,10): run-time error CSS1031: Expected selector, found 'showAddress('
(206,10): run-time error CSS1025: Expected comma or open brace, found 'showAddress('
(213,10): run-time error CSS1031: Expected selector, found '_watchItem('
(213,10): run-time error CSS1025: Expected comma or open brace, found '_watchItem('
(238,10): run-time error CSS1031: Expected selector, found 'unWatchItem('
(238,10): run-time error CSS1025: Expected comma or open brace, found 'unWatchItem('
(253,10): run-time error CSS1031: Expected selector, found 'showItemOnMap('
(253,10): run-time error CSS1025: Expected comma or open brace, found 'showItemOnMap('
(257,10): run-time error CSS1031: Expected selector, found 'addSuffix('
(257,10): run-time error CSS1025: Expected comma or open brace, found 'addSuffix('
(261,10): run-time error CSS1031: Expected selector, found 'displayFrames('
(261,10): run-time error CSS1025: Expected comma or open brace, found 'displayFrames('
(306,10): run-time error CSS1031: Expected selector, found 'logout('
(306,10): run-time error CSS1025: Expected comma or open brace, found 'logout('
(310,10): run-time error CSS1031: Expected selector, found 'showHide('
(310,10): run-time error CSS1025: Expected comma or open brace, found 'showHide('
(317,10): run-time error CSS1031: Expected selector, found 'hasContent('
(317,10): run-time error CSS1025: Expected comma or open brace, found 'hasContent('
(325,10): run-time error CSS1031: Expected selector, found 'toProperId('
(325,10): run-time error CSS1025: Expected comma or open brace, found 'toProperId('
(353,10): run-time error CSS1031: Expected selector, found 'mapUrlParams('
(353,10): run-time error CSS1025: Expected comma or open brace, found 'mapUrlParams('
(368,10): run-time error CSS1031: Expected selector, found 'formatCurrency('
(368,10): run-time error CSS1025: Expected comma or open brace, found 'formatCurrency('
(372,10): run-time error CSS1031: Expected selector, found 'showHidden('
(372,10): run-time error CSS1025: Expected comma or open brace, found 'showHidden('
(376,10): run-time error CSS1031: Expected selector, found 'setClientDebugInfo('
(376,10): run-time error CSS1025: Expected comma or open brace, found 'setClientDebugInfo('
(380,10): run-time error CSS1031: Expected selector, found 'adjustBusinessDays('
(380,10): run-time error CSS1025: Expected comma or open brace, found 'adjustBusinessDays('
(407,10): run-time error CSS1031: Expected selector, found 'scrollToChild('
(407,10): run-time error CSS1025: Expected comma or open brace, found 'scrollToChild('
(418,10): run-time error CSS1031: Expected selector, found 'enableScrollLock('
(418,10): run-time error CSS1025: Expected comma or open brace, found 'enableScrollLock('
(451,10): run-time error CSS1031: Expected selector, found 'showMore('
(451,10): run-time error CSS1025: Expected comma or open brace, found 'showMore('
(457,10): run-time error CSS1031: Expected selector, found '_applyFilters('
(457,10): run-time error CSS1025: Expected comma or open brace, found '_applyFilters('
(463,10): run-time error CSS1031: Expected selector, found '_clearFilters('
(463,10): run-time error CSS1025: Expected comma or open brace, found '_clearFilters('
(469,10): run-time error CSS1031: Expected selector, found '_saveFilters('
(469,10): run-time error CSS1025: Expected comma or open brace, found '_saveFilters('
(477,10): run-time error CSS1031: Expected selector, found '_showFilters('
(477,10): run-time error CSS1025: Expected comma or open brace, found '_showFilters('
(482,10): run-time error CSS1031: Expected selector, found '_showLoading('
(482,10): run-time error CSS1025: Expected comma or open brace, found '_showLoading('
(486,10): run-time error CSS1031: Expected selector, found '_hideLoading('
(486,10): run-time error CSS1025: Expected comma or open brace, found '_hideLoading('
(490,10): run-time error CSS1031: Expected selector, found '_callFailed('
(490,10): run-time error CSS1025: Expected comma or open brace, found '_callFailed('
(494,9): run-time error CSS1031: Expected selector, found '='
(494,9): run-time error CSS1025: Expected comma or open brace, found '='
(495,19): run-time error CSS1031: Expected selector, found '='
(495,19): run-time error CSS1025: Expected comma or open brace, found '='
(496,23): run-time error CSS1031: Expected selector, found '='
(496,23): run-time error CSS1025: Expected comma or open brace, found '='
(497,26): run-time error CSS1031: Expected selector, found '='
(497,26): run-time error CSS1025: Expected comma or open brace, found '='
(498,24): run-time error CSS1031: Expected selector, found '='
(498,24): run-time error CSS1025: Expected comma or open brace, found '='
(499,22): run-time error CSS1031: Expected selector, found '='
(499,22): run-time error CSS1025: Expected comma or open brace, found '='
(500,24): run-time error CSS1031: Expected selector, found '='
(500,24): run-time error CSS1025: Expected comma or open brace, found '='
(501,25): run-time error CSS1031: Expected selector, found '='
(501,25): run-time error CSS1025: Expected comma or open brace, found '='
(502,17): run-time error CSS1031: Expected selector, found '='
(502,17): run-time error CSS1025: Expected comma or open brace, found '='
(503,24): run-time error CSS1031: Expected selector, found '='
(503,24): run-time error CSS1025: Expected comma or open brace, found '='
(504,19): run-time error CSS1031: Expected selector, found '='
(504,19): run-time error CSS1025: Expected comma or open brace, found '='
(505,26): run-time error CSS1031: Expected selector, found '='
(505,26): run-time error CSS1025: Expected comma or open brace, found '='
(506,20): run-time error CSS1031: Expected selector, found '='
(506,20): run-time error CSS1025: Expected comma or open brace, found '='
(509,10): run-time error CSS1031: Expected selector, found 'initTable('
(509,10): run-time error CSS1025: Expected comma or open brace, found 'initTable('
(625,10): run-time error CSS1031: Expected selector, found 'initTableSort('
(625,10): run-time error CSS1025: Expected comma or open brace, found 'initTableSort('
(632,10): run-time error CSS1031: Expected selector, found 'firstVisibleRowId('
(632,10): run-time error CSS1025: Expected comma or open brace, found 'firstVisibleRowId('
(646,10): run-time error CSS1031: Expected selector, found 'sortTable('
(646,10): run-time error CSS1025: Expected comma or open brace, found 'sortTable('
(681,10): run-time error CSS1031: Expected selector, found 'moveRowsToTheTop('
(681,10): run-time error CSS1025: Expected comma or open brace, found 'moveRowsToTheTop('
(692,10): run-time error CSS1031: Expected selector, found 'moveRowsToTheBottom('
(692,10): run-time error CSS1025: Expected comma or open brace, found 'moveRowsToTheBottom('
(703,10): run-time error CSS1031: Expected selector, found 'applyTableSort('
(703,10): run-time error CSS1025: Expected comma or open brace, found 'applyTableSort('
(717,10): run-time error CSS1031: Expected selector, found 'initTableRowClick('
(717,10): run-time error CSS1025: Expected comma or open brace, found 'initTableRowClick('
(740,10): run-time error CSS1031: Expected selector, found 'initTableFilterSearch('
(740,10): run-time error CSS1025: Expected comma or open brace, found 'initTableFilterSearch('
(747,10): run-time error CSS1031: Expected selector, found 'rowContainsFilter('
(747,10): run-time error CSS1025: Expected comma or open brace, found 'rowContainsFilter('
(764,10): run-time error CSS1031: Expected selector, found 'filterTable('
(764,10): run-time error CSS1025: Expected comma or open brace, found 'filterTable('
(768,10): run-time error CSS1031: Expected selector, found 'countTableRows('
(768,10): run-time error CSS1025: Expected comma or open brace, found 'countTableRows('
(801,10): run-time error CSS1031: Expected selector, found 'setTableLegendFromCookie('
(801,10): run-time error CSS1025: Expected comma or open brace, found 'setTableLegendFromCookie('
(808,10): run-time error CSS1031: Expected selector, found 'resetLegend('
(808,10): run-time error CSS1025: Expected comma or open brace, found 'resetLegend('
(813,10): run-time error CSS1031: Expected selector, found 'toggleLegend('
(813,10): run-time error CSS1025: Expected comma or open brace, found 'toggleLegend('
(826,10): run-time error CSS1031: Expected selector, found 'sort('
(826,10): run-time error CSS1025: Expected comma or open brace, found 'sort('
(833,10): run-time error CSS1031: Expected selector, found 'onHrefRowClick('
(833,10): run-time error CSS1025: Expected comma or open brace, found 'onHrefRowClick('
(848,10): run-time error CSS1031: Expected selector, found 'tableSortComparer('
(848,10): run-time error CSS1025: Expected comma or open brace, found 'tableSortComparer('
(854,10): run-time error CSS1031: Expected selector, found 'getSortValue('
(854,10): run-time error CSS1025: Expected comma or open brace, found 'getSortValue('
(858,10): run-time error CSS1031: Expected selector, found 'highlightSelectedTableRowWithId('
(858,10): run-time error CSS1025: Expected comma or open brace, found 'highlightSelectedTableRowWithId('
(866,10): run-time error CSS1031: Expected selector, found 'highlightSelectedTableRowWithItemTypeIdItemId('
(866,10): run-time error CSS1025: Expected comma or open brace, found 'highlightSelectedTableRowWithItemTypeIdItemId('
(874,10): run-time error CSS1031: Expected selector, found 'rowData('
(874,10): run-time error CSS1025: Expected comma or open brace, found 'rowData('
(879,10): run-time error CSS1031: Expected selector, found 'initRowSelect('
(879,10): run-time error CSS1025: Expected comma or open brace, found 'initRowSelect('
(883,10): run-time error CSS1031: Expected selector, found 'rowSelectChanged('
(883,10): run-time error CSS1025: Expected comma or open brace, found 'rowSelectChanged('
(899,10): run-time error CSS1031: Expected selector, found 'rowsSelectChanged('
(899,10): run-time error CSS1025: Expected comma or open brace, found 'rowsSelectChanged('
(906,10): run-time error CSS1031: Expected selector, found 'getSelectedRows('
(906,10): run-time error CSS1025: Expected comma or open brace, found 'getSelectedRows('
(929,10): run-time error CSS1031: Expected selector, found 'toggleLegendLock('
(929,10): run-time error CSS1025: Expected comma or open brace, found 'toggleLegendLock('
(941,10): run-time error CSS1031: Expected selector, found 'displayLegendLock('
(941,10): run-time error CSS1025: Expected comma or open brace, found 'displayLegendLock('
(954,10): run-time error CSS1031: Expected selector, found 'initContextMenu('
(954,10): run-time error CSS1025: Expected comma or open brace, found 'initContextMenu('
(1019,10): run-time error CSS1031: Expected selector, found 'setRowItemValues('
(1019,10): run-time error CSS1025: Expected comma or open brace, found 'setRowItemValues('
(1041,10): run-time error CSS1031: Expected selector, found 'scrollRowToTop('
(1041,10): run-time error CSS1025: Expected comma or open brace, found 'scrollRowToTop('
(1047,20): run-time error CSS1031: Expected selector, found ';'
(1047,20): run-time error CSS1025: Expected comma or open brace, found ';'
(1048,14): run-time error CSS1031: Expected selector, found '='
(1048,14): run-time error CSS1025: Expected comma or open brace, found '='
(1050,4): run-time error CSS1031: Expected selector, found '('
(1050,4): run-time error CSS1025: Expected comma or open brace, found '('
(1077,10): run-time error CSS1031: Expected selector, found 'toggleMenu('
(1077,10): run-time error CSS1025: Expected comma or open brace, found 'toggleMenu('
(1109,10): run-time error CSS1031: Expected selector, found 'showAlert('
(1109,10): run-time error CSS1025: Expected comma or open brace, found 'showAlert('
(1126,10): run-time error CSS1031: Expected selector, found 'showConfirm('
(1126,10): run-time error CSS1025: Expected comma or open brace, found 'showConfirm('
(1145,10): run-time error CSS1031: Expected selector, found 'modalShow('
(1145,10): run-time error CSS1025: Expected comma or open brace, found 'modalShow('
(1167,10): run-time error CSS1031: Expected selector, found 'modalHide('
(1167,10): run-time error CSS1025: Expected comma or open brace, found 'modalHide('
(1170,10): run-time error CSS1031: Expected selector, found 'showModal('
(1170,10): run-time error CSS1025: Expected comma or open brace, found 'showModal('
(1195,10): run-time error CSS1031: Expected selector, found 'resizeModal('
(1195,10): run-time error CSS1025: Expected comma or open brace, found 'resizeModal('
(1204,10): run-time error CSS1031: Expected selector, found 'showAddModal('
(1204,10): run-time error CSS1025: Expected comma or open brace, found 'showAddModal('
(1238,10): run-time error CSS1031: Expected selector, found 'showEditModal('
(1238,10): run-time error CSS1025: Expected comma or open brace, found 'showEditModal('
(1295,10): run-time error CSS1031: Expected selector, found 'showViewEditModal('
(1295,10): run-time error CSS1025: Expected comma or open brace, found 'showViewEditModal('
(1376,10): run-time error CSS1031: Expected selector, found 'pageViewEditModal_EditMode('
(1376,10): run-time error CSS1025: Expected comma or open brace, found 'pageViewEditModal_EditMode('
(1391,10): run-time error CSS1031: Expected selector, found 'pageViewEditModal_ViewMode('
(1391,10): run-time error CSS1025: Expected comma or open brace, found 'pageViewEditModal_ViewMode('
(1406,10): run-time error CSS1031: Expected selector, found '_enableAddModal('
(1406,10): run-time error CSS1025: Expected comma or open brace, found '_enableAddModal('
(1410,10): run-time error CSS1031: Expected selector, found 'setPageModalError('
(1410,10): run-time error CSS1025: Expected comma or open brace, found 'setPageModalError('
(1413,10): run-time error CSS1031: Expected selector, found 'setPageModalSuccess('
(1413,10): run-time error CSS1025: Expected comma or open brace, found 'setPageModalSuccess('
(1416,10): run-time error CSS1031: Expected selector, found 'setPageAddModalSystemError('
(1416,10): run-time error CSS1025: Expected comma or open brace, found 'setPageAddModalSystemError('
(1420,10): run-time error CSS1031: Expected selector, found 'setPageAddModalError('
(1420,10): run-time error CSS1025: Expected comma or open brace, found 'setPageAddModalError('
(1424,10): run-time error CSS1031: Expected selector, found 'setPageAddModalSuccess('
(1424,10): run-time error CSS1025: Expected comma or open brace, found 'setPageAddModalSuccess('
(1427,10): run-time error CSS1031: Expected selector, found 'setPageEditModalSystemError('
(1427,10): run-time error CSS1025: Expected comma or open brace, found 'setPageEditModalSystemError('
(1430,10): run-time error CSS1031: Expected selector, found 'setPageEditModalError('
(1430,10): run-time error CSS1025: Expected comma or open brace, found 'setPageEditModalError('
(1433,10): run-time error CSS1031: Expected selector, found 'setPageEditModalSuccess('
(1433,10): run-time error CSS1025: Expected comma or open brace, found 'setPageEditModalSuccess('
(1436,10): run-time error CSS1031: Expected selector, found 'setPageEditModalConfirm('
(1436,10): run-time error CSS1025: Expected comma or open brace, found 'setPageEditModalConfirm('
(1439,10): run-time error CSS1031: Expected selector, found 'setPageViewEditModalSystemError('
(1439,10): run-time error CSS1025: Expected comma or open brace, found 'setPageViewEditModalSystemError('
(1442,10): run-time error CSS1031: Expected selector, found 'setPageViewEditModalError('
(1442,10): run-time error CSS1025: Expected comma or open brace, found 'setPageViewEditModalError('
(1445,10): run-time error CSS1031: Expected selector, found 'setPageViewEditModalConfirm('
(1445,10): run-time error CSS1025: Expected comma or open brace, found 'setPageViewEditModalConfirm('
(1448,10): run-time error CSS1031: Expected selector, found 'setPageViewEditModalSuccess('
(1448,10): run-time error CSS1025: Expected comma or open brace, found 'setPageViewEditModalSuccess('
(1451,10): run-time error CSS1031: Expected selector, found 'setModalError('
(1451,10): run-time error CSS1025: Expected comma or open brace, found 'setModalError('
(1456,10): run-time error CSS1031: Expected selector, found 'setModalConfirm('
(1456,10): run-time error CSS1025: Expected comma or open brace, found 'setModalConfirm('
(1461,10): run-time error CSS1031: Expected selector, found 'setModalSuccess('
(1461,10): run-time error CSS1025: Expected comma or open brace, found 'setModalSuccess('
(1467,10): run-time error CSS1031: Expected selector, found 'dismissPageModal('
(1467,10): run-time error CSS1025: Expected comma or open brace, found 'dismissPageModal('
(1471,10): run-time error CSS1031: Expected selector, found 'dismissPageAddModal('
(1471,10): run-time error CSS1025: Expected comma or open brace, found 'dismissPageAddModal('
(1474,10): run-time error CSS1031: Expected selector, found 'dismissPageEditModal('
(1474,10): run-time error CSS1025: Expected comma or open brace, found 'dismissPageEditModal('
(1477,10): run-time error CSS1031: Expected selector, found 'dismissPageViewEditModal('
(1477,10): run-time error CSS1025: Expected comma or open brace, found 'dismissPageViewEditModal('
(1482,10): run-time error CSS1031: Expected selector, found 'isCommonContext('
(1482,10): run-time error CSS1025: Expected comma or open brace, found 'isCommonContext('
(1496,10): run-time error CSS1031: Expected selector, found '_loadCommonChildContent('
(1496,10): run-time error CSS1025: Expected comma or open brace, found '_loadCommonChildContent('
(1528,10): run-time error CSS1031: Expected selector, found '_loadNotes('
(1528,10): run-time error CSS1025: Expected comma or open brace, found '_loadNotes('
(1539,10): run-time error CSS1031: Expected selector, found '_showModalNotes('
(1539,10): run-time error CSS1025: Expected comma or open brace, found '_showModalNotes('
(1558,10): run-time error CSS1031: Expected selector, found '_showAddNote('
(1558,10): run-time error CSS1025: Expected comma or open brace, found '_showAddNote('
(1577,10): run-time error CSS1031: Expected selector, found '_showViewEditNote('
(1577,10): run-time error CSS1025: Expected comma or open brace, found '_showViewEditNote('
(1596,10): run-time error CSS1031: Expected selector, found '_loadAttachments('
(1596,10): run-time error CSS1025: Expected comma or open brace, found '_loadAttachments('
(1607,10): run-time error CSS1031: Expected selector, found '_showModalAttachments('
(1607,10): run-time error CSS1025: Expected comma or open brace, found '_showModalAttachments('
(1626,10): run-time error CSS1031: Expected selector, found '_showAddAttachment('
(1626,10): run-time error CSS1025: Expected comma or open brace, found '_showAddAttachment('
(1645,10): run-time error CSS1031: Expected selector, found '_showAddLogo('
(1645,10): run-time error CSS1025: Expected comma or open brace, found '_showAddLogo('
(1663,10): run-time error CSS1031: Expected selector, found '_loadAppointments('
(1663,10): run-time error CSS1025: Expected comma or open brace, found '_loadAppointments('
(1674,10): run-time error CSS1031: Expected selector, found '_showModalAppointments('
(1674,10): run-time error CSS1025: Expected comma or open brace, found '_showModalAppointments('
(1693,10): run-time error CSS1031: Expected selector, found '_showAddAppointment('
(1693,10): run-time error CSS1025: Expected comma or open brace, found '_showAddAppointment('
(1715,10): run-time error CSS1031: Expected selector, found '_showViewEditAppointment('
(1715,10): run-time error CSS1025: Expected comma or open brace, found '_showViewEditAppointment('
(1734,10): run-time error CSS1031: Expected selector, found '_loadTasks('
(1734,10): run-time error CSS1025: Expected comma or open brace, found '_loadTasks('
(1745,10): run-time error CSS1031: Expected selector, found '_showAddTask('
(1745,10): run-time error CSS1025: Expected comma or open brace, found '_showAddTask('
(1764,10): run-time error CSS1031: Expected selector, found '_showEditTask('
(1764,10): run-time error CSS1025: Expected comma or open brace, found '_showEditTask('
(1790,10): run-time error CSS1031: Expected selector, found '_nudgeTask('
(1790,10): run-time error CSS1025: Expected comma or open brace, found '_nudgeTask('
(1797,10): run-time error CSS1031: Expected selector, found 'showAddReferenceData('
(1797,10): run-time error CSS1025: Expected comma or open brace, found 'showAddReferenceData('
(1812,10): run-time error CSS1031: Expected selector, found '_showChangeStatus('
(1812,10): run-time error CSS1025: Expected comma or open brace, found '_showChangeStatus('
(1833,10): run-time error CSS1031: Expected selector, found 'showCustomerEmail('
(1833,10): run-time error CSS1025: Expected comma or open brace, found 'showCustomerEmail('
(1849,10): run-time error CSS1031: Expected selector, found '_loadPayments('
(1849,10): run-time error CSS1025: Expected comma or open brace, found '_loadPayments('
(1860,10): run-time error CSS1031: Expected selector, found '_showAddOmitPayment('
(1860,10): run-time error CSS1025: Expected comma or open brace, found '_showAddOmitPayment('
(1880,10): run-time error CSS1031: Expected selector, found '_showAddPayment('
(1880,10): run-time error CSS1025: Expected comma or open brace, found '_showAddPayment('
(1900,10): run-time error CSS1031: Expected selector, found '_showAddBalanceCorrection('
(1900,10): run-time error CSS1025: Expected comma or open brace, found '_showAddBalanceCorrection('
(1920,10): run-time error CSS1031: Expected selector, found '_showViewEditPayment('
(1920,10): run-time error CSS1025: Expected comma or open brace, found '_showViewEditPayment('
(1956,10): run-time error CSS1031: Expected selector, found '_loadProducts('
(1956,10): run-time error CSS1025: Expected comma or open brace, found '_loadProducts('
(1967,10): run-time error CSS1031: Expected selector, found '_showAddProduct('
(1967,10): run-time error CSS1025: Expected comma or open brace, found '_showAddProduct('
(1986,10): run-time error CSS1031: Expected selector, found 'showViewEditProduct('
(1986,10): run-time error CSS1025: Expected comma or open brace, found 'showViewEditProduct('
(2001,10): run-time error CSS1031: Expected selector, found '_loadPartOrders('
(2001,10): run-time error CSS1025: Expected comma or open brace, found '_loadPartOrders('
(2012,10): run-time error CSS1031: Expected selector, found '_showAddPartOrder('
(2012,10): run-time error CSS1025: Expected comma or open brace, found '_showAddPartOrder('
(2032,10): run-time error CSS1031: Expected selector, found 'showViewEditPartOrder('
(2032,10): run-time error CSS1025: Expected comma or open brace, found 'showViewEditPartOrder('
(2047,10): run-time error CSS1031: Expected selector, found '_loadItemLinks('
(2047,10): run-time error CSS1025: Expected comma or open brace, found '_loadItemLinks('
(2058,10): run-time error CSS1031: Expected selector, found '_showShareItem('
(2058,10): run-time error CSS1025: Expected comma or open brace, found '_showShareItem('
(2081,10): run-time error CSS1031: Expected selector, found '_onSuccessAdd('
(2081,10): run-time error CSS1025: Expected comma or open brace, found '_onSuccessAdd('
(2135,10): run-time error CSS1031: Expected selector, found '_onSuccessEdit('
(2135,10): run-time error CSS1025: Expected comma or open brace, found '_onSuccessEdit('
(2166,10): run-time error CSS1031: Expected selector, found '_onSuccessViewEdit('
(2166,10): run-time error CSS1025: Expected comma or open brace, found '_onSuccessViewEdit('
(2186,10): run-time error CSS1031: Expected selector, found '_onErrorAdd('
(2186,10): run-time error CSS1025: Expected comma or open brace, found '_onErrorAdd('
(2201,10): run-time error CSS1031: Expected selector, found '_onErrorEdit('
(2201,10): run-time error CSS1025: Expected comma or open brace, found '_onErrorEdit('
(2215,10): run-time error CSS1031: Expected selector, found '_onErrorViewEdit('
(2215,10): run-time error CSS1025: Expected comma or open brace, found '_onErrorViewEdit('
(2230,10): run-time error CSS1031: Expected selector, found 'getErrorMsg('
(2230,10): run-time error CSS1025: Expected comma or open brace, found 'getErrorMsg('
(2242,10): run-time error CSS1031: Expected selector, found 'displayAddModalMessage('
(2242,10): run-time error CSS1025: Expected comma or open brace, found 'displayAddModalMessage('
(2245,10): run-time error CSS1031: Expected selector, found 'displayEditModalMessage('
(2245,10): run-time error CSS1025: Expected comma or open brace, found 'displayEditModalMessage('
(2248,10): run-time error CSS1031: Expected selector, found 'displayVewEditModalMessage('
(2248,10): run-time error CSS1025: Expected comma or open brace, found 'displayVewEditModalMessage('
(2251,10): run-time error CSS1031: Expected selector, found 'displayModalMessage('
(2251,10): run-time error CSS1025: Expected comma or open brace, found 'displayModalMessage('
(2264,10): run-time error CSS1031: Expected selector, found '_formSave('
(2264,10): run-time error CSS1025: Expected comma or open brace, found '_formSave('
(2274,10): run-time error CSS1031: Expected selector, found 'initTextSelect('
(2274,10): run-time error CSS1025: Expected comma or open brace, found 'initTextSelect('
(2279,10): run-time error CSS1031: Expected selector, found 'initDatePicker('
(2279,10): run-time error CSS1025: Expected comma or open brace, found 'initDatePicker('
(2285,10): run-time error CSS1031: Expected selector, found 'applyMultiselects('
(2285,10): run-time error CSS1025: Expected comma or open brace, found 'applyMultiselects('
(2293,10): run-time error CSS1031: Expected selector, found 'applyMultiselect('
(2293,10): run-time error CSS1025: Expected comma or open brace, found 'applyMultiselect('
(2305,10): run-time error CSS1031: Expected selector, found 'setMultiselectData('
(2305,10): run-time error CSS1025: Expected comma or open brace, found 'setMultiselectData('
(2310,10): run-time error CSS1031: Expected selector, found 'onConfirmOk('
(2310,10): run-time error CSS1025: Expected comma or open brace, found 'onConfirmOk('
(2317,10): run-time error CSS1031: Expected selector, found 'enableInput('
(2317,10): run-time error CSS1025: Expected comma or open brace, found 'enableInput('
(2322,10): run-time error CSS1031: Expected selector, found 'disableInput('
(2322,10): run-time error CSS1025: Expected comma or open brace, found 'disableInput('
(2326,10): run-time error CSS1031: Expected selector, found 'enableDisableInput('
(2326,10): run-time error CSS1025: Expected comma or open brace, found 'enableDisableInput('
(2332,10): run-time error CSS1031: Expected selector, found 'isInputChecked('
(2332,10): run-time error CSS1025: Expected comma or open brace, found 'isInputChecked('
(2336,10): run-time error CSS1031: Expected selector, found 'setInputChecked('
(2336,10): run-time error CSS1025: Expected comma or open brace, found 'setInputChecked('
(2341,10): run-time error CSS1031: Expected selector, found 'setInputDateType('
(2341,10): run-time error CSS1025: Expected comma or open brace, found 'setInputDateType('
(2348,10): run-time error CSS1031: Expected selector, found 'convertDateTime('
(2348,10): run-time error CSS1025: Expected comma or open brace, found 'convertDateTime('
(2362,10): run-time error CSS1031: Expected selector, found 'populateFramesDropdown('
(2362,10): run-time error CSS1025: Expected comma or open brace, found 'populateFramesDropdown('
(2376,10): run-time error CSS1031: Expected selector, found 'restrictFutureDates('
(2376,10): run-time error CSS1025: Expected comma or open brace, found 'restrictFutureDates('
(2384,10): run-time error CSS1031: Expected selector, found 'selectFirstOptionIfValueMissing('
(2384,10): run-time error CSS1025: Expected comma or open brace, found 'selectFirstOptionIfValueMissing('
(2394,10): run-time error CSS1031: Expected selector, found 'setDropdownValue('
(2394,10): run-time error CSS1025: Expected comma or open brace, found 'setDropdownValue('
(2409,16): run-time error CSS1031: Expected selector, found '='
(2409,16): run-time error CSS1025: Expected comma or open brace, found '='
(2411,10): run-time error CSS1031: Expected selector, found 'ajaxPostJsonAddData('
(2411,10): run-time error CSS1025: Expected comma or open brace, found 'ajaxPostJsonAddData('
(2420,10): run-time error CSS1031: Expected selector, found 'ajaxPostJsonEditData('
(2420,10): run-time error CSS1025: Expected comma or open brace, found 'ajaxPostJsonEditData('
(2429,10): run-time error CSS1031: Expected selector, found 'ajaxPostJsonViewEditData('
(2429,10): run-time error CSS1025: Expected comma or open brace, found 'ajaxPostJsonViewEditData('
(2438,10): run-time error CSS1031: Expected selector, found 'ajaxPostJsonData('
(2438,10): run-time error CSS1025: Expected comma or open brace, found 'ajaxPostJsonData('
(2465,10): run-time error CSS1031: Expected selector, found 'ajaxPostFormAddData('
(2465,10): run-time error CSS1025: Expected comma or open brace, found 'ajaxPostFormAddData('
(2469,10): run-time error CSS1031: Expected selector, found 'ajaxPostFormData('
(2469,10): run-time error CSS1025: Expected comma or open brace, found 'ajaxPostFormData('
(2497,10): run-time error CSS1031: Expected selector, found 'loadUrl('
(2497,10): run-time error CSS1025: Expected comma or open brace, found 'loadUrl('
(2508,10): run-time error CSS1031: Expected selector, found 'loadDiv('
(2508,10): run-time error CSS1025: Expected comma or open brace, found 'loadDiv('
(2525,10): run-time error CSS1031: Expected selector, found 'loadPostUrl('
(2525,10): run-time error CSS1025: Expected comma or open brace, found 'loadPostUrl('
(2548,10): run-time error CSS1031: Expected selector, found 'loadFormPostUrl('
(2548,10): run-time error CSS1025: Expected comma or open brace, found 'loadFormPostUrl('
(2572,10): run-time error CSS1031: Expected selector, found 'getData('
(2572,10): run-time error CSS1025: Expected comma or open brace, found 'getData('
(2625,10): run-time error CSS1031: Expected selector, found 'initDropdown('
(2625,10): run-time error CSS1025: Expected comma or open brace, found 'initDropdown('
(2634,10): run-time error CSS1031: Expected selector, found 'populateDropdown('
(2634,10): run-time error CSS1025: Expected comma or open brace, found 'populateDropdown('
(2669,10): run-time error CSS1031: Expected selector, found 'displayErrors('
(2669,10): run-time error CSS1025: Expected comma or open brace, found 'displayErrors('
(2695,32): run-time error CSS1031: Expected selector, found '='
(2695,32): run-time error CSS1025: Expected comma or open brace, found '='
(2696,23): run-time error CSS1031: Expected selector, found '='
(2696,23): run-time error CSS1025: Expected comma or open brace, found '='
(2697,22): run-time error CSS1031: Expected selector, found '='
(2697,22): run-time error CSS1025: Expected comma or open brace, found '='
(2699,10): run-time error CSS1031: Expected selector, found 'validateAddModalFrm('
(2699,10): run-time error CSS1025: Expected comma or open brace, found 'validateAddModalFrm('
(2703,10): run-time error CSS1031: Expected selector, found 'validateEditModalFrm('
(2703,10): run-time error CSS1025: Expected comma or open brace, found 'validateEditModalFrm('
(2707,10): run-time error CSS1031: Expected selector, found 'validateViewEditModalFrm('
(2707,10): run-time error CSS1025: Expected comma or open brace, found 'validateViewEditModalFrm('
(2711,10): run-time error CSS1031: Expected selector, found 'validateModalFrm('
(2711,10): run-time error CSS1025: Expected comma or open brace, found 'validateModalFrm('
(2719,10): run-time error CSS1031: Expected selector, found 'validateAddFrm('
(2719,10): run-time error CSS1025: Expected comma or open brace, found 'validateAddFrm('
(2722,10): run-time error CSS1031: Expected selector, found 'validateEditFrm('
(2722,10): run-time error CSS1025: Expected comma or open brace, found 'validateEditFrm('
(2725,10): run-time error CSS1031: Expected selector, found 'validateViewEditFrm('
(2725,10): run-time error CSS1025: Expected comma or open brace, found 'validateViewEditFrm('
(2728,10): run-time error CSS1031: Expected selector, found 'validateFrm('
(2728,10): run-time error CSS1025: Expected comma or open brace, found 'validateFrm('
(2779,10): run-time error CSS1031: Expected selector, found 'validateAddFld('
(2779,10): run-time error CSS1025: Expected comma or open brace, found 'validateAddFld('
(2782,10): run-time error CSS1031: Expected selector, found 'validateEditFld('
(2782,10): run-time error CSS1025: Expected comma or open brace, found 'validateEditFld('
(2785,10): run-time error CSS1031: Expected selector, found 'validateViewEditFld('
(2785,10): run-time error CSS1025: Expected comma or open brace, found 'validateViewEditFld('
(2788,10): run-time error CSS1031: Expected selector, found 'validateFld('
(2788,10): run-time error CSS1025: Expected comma or open brace, found 'validateFld('
(2874,10): run-time error CSS1031: Expected selector, found 'clearInvalid('
(2874,10): run-time error CSS1025: Expected comma or open brace, found 'clearInvalid('
(2894,10): run-time error CSS1031: Expected selector, found 'setInvalid('
(2894,10): run-time error CSS1025: Expected comma or open brace, found 'setInvalid('
(2931,10): run-time error CSS1031: Expected selector, found 'setRequired('
(2931,10): run-time error CSS1025: Expected comma or open brace, found 'setRequired('
(2937,10): run-time error CSS1031: Expected selector, found 'validationLog('
(2937,10): run-time error CSS1025: Expected comma or open brace, found 'validationLog('
(2942,10): run-time error CSS1031: Expected selector, found 'addValidationError('
(2942,10): run-time error CSS1025: Expected comma or open brace, found 'addValidationError('
(2947,10): run-time error CSS1031: Expected selector, found 'isRequired('
(2947,10): run-time error CSS1025: Expected comma or open brace, found 'isRequired('
 */
let gProperId = '';
let gDebugMode = false;
let _rowClickEnabled = true;

$(document).ready(function () {
    initTableSort();
    initTableRowClick();
    initTableFilterSearch();
    initTooltips();

    initDatePicker();
    initPrintOption();
    initContextMenu();
    initTextSelect();
});

function initTooltips() {
    consolelog('initTooltips');
    $('[data-toggle="tooltip"]').tooltip();
}

function initScrollTop(divId, reposition) {
    consolelog('initScrollTop: ' + divId);
    $("#" + divId).on("scroll", function () { showScrollTop(divId, reposition) });
}
function showScrollTop(divId, reposition) {
    if ($("#btnScrollTop") && $('#' + divId)) {
        if ($('#'+divId).scrollTop() > 20) {
            $("#btnScrollTop").data('target', divId);
            if (reposition) {
                var calcLeft = $('#' + divId).position().left + $('#' + divId).outerWidth() - 100;
                var calcBottom = $('#' + divId).position().top + $('#' + divId).outerHeight() - 100;
                $("#btnScrollTop").css('left', calcLeft).css('top', calcBottom);
            }

            $("#btnScrollTop").show();
        } else {
            $("#btnScrollTop").hide();
        }
    }
}
function scrollToTop() {
    var myButton = $("#btnScrollTop");
    var target = $(myButton).data('target');
    $("#" + target).scrollTop(0);
}

function showDashboard(key, dashboardUrl) {
    consolelog('showDashboard: ' + dashboardUrl);
    if (dashboardUrl && dashboardUrl.length > 0) {
        showDivFromCookieSetting('dashboard', key, dashboardUrl);
    } else {
        $('#dashboard').hide();
    }

    //$('#subContentScroll').removeClass('dashboard');
    //if ($('#dashboard').css('display') !== 'none') $('#subContentScroll').addClass('dashboard')
}
function toggleDashboard(key, dashboardUrl) {
    consolelog('toggleDashboard: ' + dashboardUrl);
    toggleDivFromCookieSetting('dashboard', key, dashboardUrl);
    //$('#subContentScroll').removeClass('dashboard');
    //if ($('#dashboard').css('display') !== 'none') $('#subContentScroll').addClass('dashboard')
}

function showDivFromCookieSetting(divId, key, loadUrl) {
    consolelog('showDivFromCookieSetting: ' + divId + ' with url: ' + loadUrl);
    if (!divId || divId == '' || !loadUrl || loadUrl == '') return;

    var show = getCookie(divId+key);
    if (!show || show == '') {
        consolelog('showDivFromCookieSetting: hide');
        $('#' + divId).hide();
    }
    else {
        consolelog('showDivFromCookieSetting: show');
        if (loadUrl && loadUrl.length > 0)
            $('#' + divId).load(loadUrl);

        $('#' + divId).show();
    }
}
function toggleDivFromCookieSetting(divId, key, loadUrl) {
    consolelog('toggleDivFromCookieSetting: ' + divId + ' with url: ' + loadUrl);
    if (!divId || divId == '' || !loadUrl || loadUrl == '') return;

    var show = getCookie(divId+key);
    if (!show || show == '')
        setCookie(divId+key, 'true', 100);
    else
        setCookie(divId+key, '', 1);

    showDivFromCookieSetting(divId, key, loadUrl);
}

function setCookie(cname, cvalue, exdays) {
    //consolelog('setCookie', [cname, cvalue, exdays]);
    if (cvalue) cvalue = cvalue.replaceAll(';', '|');
    const d = new Date();
    d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
    let expires = "expires=" + d.toUTCString();
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
function getCookie(cname, defaultVal) {
    let name = cname + "=";
    let ca = document.cookie.split(';');
    var cval;
    for (let i = 0; i < ca.length; i++) {
        let c = ca[i];
        while (c.charAt(0) == ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) == 0) {
            cval = c.substring(name.length, c.length);
        }
    }

    if (!cval) cval = defaultVal;
    if (cval) cval = cval.replaceAll('|', ';');
    return cval;
}

function allowDrop(ev) {
    ev.preventDefault();
}

function navigateToPage(url) {
    window.location.href = url;
}
function reloadPage(pathOnly) {
    consolelog('reloadPage', pathOnly);
    if (pathOnly) {
        window.location.href = location.origin + location.pathname;
    } else {
        window.location.reload();
    }
}

function consolelog(text, value, isError) {
    var message = '';
    var logTable = false;
    var logObject = false;

    if (value === null) {
        message = 'null';

    } else if (Array.isArray(value)) {
        if (value.length === 0) {
            message = '[empty array]';
        } else {
            logTable = true;
        }

    } else if (typeof value === 'object') {
        if (Object.keys(value).length === 0) {
            message = '{} (empty object)';
        } else {
            logObject = true;
        }

    } else {
        message = value;
    }

    if (logTable) {
        console.table(text, value);
    } else if (logObject) {
        console.log(text, JSON.stringify(value, null, 2));
    } else {
        console.log(text, message);
    }
    
    const debugContent = $('#clientDebugInfo'); // Select the div using jQuery
    message = '<b>' + text + '</b>: ' + message;
    var colour = isError ? 'f00' : '000';
    message = '<div style="color:#' + colour + ';">' + message + '</div>';

    if (isError) {
        var errCount = toInt($('#debugInfoErrorCount').html()) + 1;
        $('#debugInfoErrorCount').html(errCount);
    }

    debugContent.append(message); // Append new content
    debugContent.scrollTop(debugContent.prop("scrollHeight")); // Scroll to the bottom
}
function toInt(text) {
    return parseInt(text||0);
}
function printPage(content = 'subContentScroll') {
    var myFrame = $("#printFrame").contents().find('body');
    myFrame.html($('#' + content).html());
    document.getElementById("printFrame").contentWindow.print();
}
function toggleDiv(id) {
    $('#' + id).toggle();
}

function initPrintOption() {
    $('.print-option').hover(function () {
        $('#subContentScroll').css("box-shadow", "0 0 2px #f00 inset;");
    }, function () {
        $('#subContentScroll').css("box-shadow", "none");
    });
}

function showAddress(rowItemAddress) {
    var address = rowItemAddress;
    if (!rowItemAddress) address = rowMenuItemAddress;

    if (!address) return;
    window.open('https://www.google.com/maps/search/' + address);
}
function _watchItem(css, itemId, itemTypeId, itemReference) {
    consolelog('_watchItem', [itemId, itemTypeId, itemReference]);
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;

    var postUrl = '/App/Watch';

    var data = {
        WatchItemId: itemId,
        WatchItemTypeId: itemTypeId,
        WatchItemReference: itemReference
    };

    var successCallback = function () {
        showAlert('Watch', 'You are now watching this record', css);
    };

    var errorCallback = function () {
        showAlert('Watch - Error', 'Unable to watch this record', css);
    };

    ajaxPostJsonData(postUrl, data, successCallback, errorCallback);
}
function unWatchItem(itemTypeId, itemId, css) {
    consolelog('unWatchItem', [itemTypeId, itemId]);

    var confirmCallback = function () {
        var postUrl = '/App/UnWatch';
        var data = {
            WatchItemTypeId: itemTypeId,
            WatchItemId: itemId,
        };
        ajaxPostJsonData(postUrl, data, unWatchSuccess);
    };

    showConfirm('Watch', 'Are you sure you no longer want to watch this record?', 'watch', confirmCallback, css);
}

function showItemOnMap() {
    consolelog('showItemOnMap', [rowMenuItemAddress]);
    showAddress(rowMenuItemAddress);
}
function addSuffix(name, suffix) {
    if (!suffix || suffix == '') return name;
    return name + ' (' + suffix + ')';
}
function displayFrames(toDisplay) {
    consolelog('displayFrames: ' + toDisplay);

    setCookie('displayFrames', toDisplay);

    $('.frameDisplay').hide();
    $('.frameTypeDisplay').removeClass('activeFrameType');
    if (!toDisplay || toDisplay == '') toDisplay = 't';

    if (toDisplay == 't') {
        $('.frameDisplay.framesCount').show();
        $('.frameTypeDisplay.frameTypeQ').addClass('activeFrameType');
        $('#legendText').html('Displaying - Frame Quantities');
    }
    if (toDisplay == 'c') {
        $('.frameDisplay.framesCalledOff').show();
        $('.frameTypeDisplay.frameTypeC').addClass('activeFrameType');
        $('#legendText').html('Displaying - Frames Called Off');
    }
    if (toDisplay == 'o') {
        $('.frameDisplay.framesOrdered').show();
        $('.frameTypeDisplay.frameTypeO').addClass('activeFrameType');
        $('#legendText').html('Displaying - Frames Ordered');
    }
    if (toDisplay == 'd') {
        $('.frameDisplay.framesDelivered').show();
        $('.frameTypeDisplay.frameTypeD').addClass('activeFrameType');
        $('#legendText').html('Displaying - Frames Delivered');
    }
    if (toDisplay == 'i') {
        $('.frameDisplay.framesInstalled').show();
        $('.frameTypeDisplay.frameTypeI').addClass('activeFrameType');
        $('#legendText').html('Displaying - Frames Installed');
    }
    if (toDisplay == 'w') {
        $('.frameDisplay.framesWip').show();
        $('.frameTypeDisplay.frameTypeW').addClass('activeFrameType');
        $('#legendText').html('Displaying - Frames WIP');
    }
    if (toDisplay == 'r') {
        $('.frameDisplay.framesRem').show();
        $('.frameTypeDisplay.frameTypeR').addClass('activeFrameType');
        $('#legendText').html('Displaying - Frames Remaining');
    }
}
function logout() {
    showConfirm('Logout', 'Are you sure you want to logout?', 'logout');
}

function showHide(id, show) {
    //consolelog('showHide: ' + id + ', ' + show);
    if (toProperId(id).fails) return;

    show ? $(gProperId).show() : $(gProperId).hide();
}

function hasContent(value, match) {
    const has = typeof value === 'string' && value.trim().length > 0;
    if (has && typeof match === 'string')
        return value == match;

    return has;
}

function toProperId(id, setGlobal, debug) {
    if (debug) consolelog('toProperId...', [id, setGlobal, debug]);
    if (setGlobal ==  null || setGlobal == 'undefined') setGlobal = true;
    if (setGlobal) gProperId = '';

    if (typeof id !== 'string') {
        if (debug) consolelog('id is not a string');
        return { fails: true, value: '' };
    }

    const trimmed = id.trim();
    if (!trimmed) {
        if (debug) consolelog('id (trimmed) is empty');
        return { fails: true, exists: false, value: '' };
    }

    const formatted = trimmed.startsWith('#') ? trimmed : `#${trimmed}`;
    if (setGlobal) gProperId = formatted;

    const element = document.querySelector(formatted);
    const exists = element !== null && element !== undefined;

    const result = { fails: false, exists: exists, value: formatted };
    if (debug) consolelog('result', result);

    return result;
}

function mapUrlParams(url, params) {
    if (!hasContent(url)) return;
    if (!params || params.length == 0) return url;
    //consolelog('mapUrlParams', [url + '...']);

    let localUrl = url;
    for (var i = 1; i <= params.length; i++) {
        var token = '{' + i + '}';
        localUrl = localUrl.replace(token, params[i-1]);
    }
    localUrl = localUrl.replaceAll(/&amp;/g, '&');

    return localUrl;
}

function formatCurrency(value) {
    return Number(value).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,");
}

function showHidden() {
    $("input:hidden").attr("type", "text");
}

function setClientDebugInfo(msg) {
    $('#clientDebugInfo').html(msg);
}

function adjustBusinessDays(inputDate, targetDays, backwards, isoWeekday) {
    let date = moment(inputDate); // Start from the input date
    let adjustedDays = 0;

    // Determine the step (1 for forward, -1 for backward)
    const step = backwards === true ? -1 : 1;

    // Add or remove business days
    while (adjustedDays < targetDays) {
        date = date.add(step, 'days'); // Increment or decrement the date by 1 day

        // Check if it's a weekday (Monday-Friday)
        if (date.isoWeekday() < 6) {
            adjustedDays++; // Count only weekdays
        }
    }

    // Adjust the resulting date to the next or previous specified ISO weekday
    if (isoWeekday > 0 && isoWeekday < 8) {
        while (date.isoWeekday() !== isoWeekday) {
            date = date.add(step, 'days'); // Move to the next or previous specified ISO weekday
        }
    }

    return date.format('YYYY-MM-DD'); // Return the final date in the desired format
}

function scrollToChild(childName) {
    const childId = '#content_' + childName;
    if (!toProperId(childId, false).exists) return;

    consolelog('scrollToChild', childId);

    var scrollTo = $(childId);
    if (scrollTo.length)
        scrollTo[0].scrollIntoView({ behavior: 'smooth', block: 'start' });
}

function enableScrollLock(scrollableDivId, containerDivId) {
    var container = document.getElementById(containerDivId);
    var div = document.getElementById(scrollableDivId);

    container.addEventListener("wheel", function (event) {
        var containerRect = container.getBoundingClientRect();
        var divRect = div.getBoundingClientRect();

        // Allow normal page scrolling when the container is still in view
        if (containerRect.top >= 0) {
            document.body.style.overflow = "auto";
            div.style.overflowY = "hidden";
            return;
        }

        // Lock scrolling inside the div once it reaches the top of its container
        if (divRect.top <= containerRect.top) {
            if (div.scrollTop === 0 && event.deltaY < 0) {
                // At the top of the div, allow page scrolling
                document.body.style.overflow = "auto";
            } else if (div.scrollTop + div.clientHeight >= div.scrollHeight && event.deltaY > 0) {
                // At the bottom of the div, allow page scrolling
                document.body.style.overflow = "auto";
            } else {
                // Inside the div, lock scrolling here
                document.body.style.overflow = "hidden";
                div.style.overflowY = "scroll";
            }
        }
    });
}


function showMore() {
    var more = $('.moreDiv:visible').length > 0;
    more ? $('.lessDiv').show() : $('.lessDiv').hide();
    more ? $('.moreDiv').hide() : $('.moreDiv').show();
}

function _applyFilters(itemTypeId, filtersId) {
    if (toInt(itemTypeId) <= 0 || toInt(filtersId) <= 0) return;

    consolelog('_applyFilters', [itemTypeId, filtersId]);
    ajaxPostJsonData('/App/FiltersApply', { itemType: itemTypeId, filterId: filtersId }, reloadPage);
}
function _clearFilters(itemTypeId) {
    if (toInt(itemTypeId) <= 0) return;

    consolelog('_clearFilters', itemTypeId);
    ajaxPostJsonData('/App/FiltersClear', { itemType: itemTypeId }, reloadPage);
}
function _saveFilters(url) {
    if (!url || url.length == 0 || typeof getFiltersData !== 'function') return;

    consolelog('_saveFilters');

    const filterData = getFiltersData();
    ajaxPostJsonData(url, filterData, reloadPage);
}
function _showFilters(title, showUrl, saveUrl, css) {
    consolelog('_showFilters', [title, showUrl, saveUrl, css]);
    showAddModal('Enquiry Filters', showUrl, function () { _saveFilters(saveUrl); }, css);
}

function _showLoading() {
    $('#loadingOverlay').show();
}

function _hideLoading() {
    $('#loadingOverlay').hide();
}

function _callFailed(name) {
    consolelog('Call Failed', name);
    return false;
}
let tab = '';
let rowMenuItemId = 0;
let rowMenuItemTypeId = 0;
let rowMenuItemReference = '';
let rowMenuItemAddress = '';
let rowMenuItemEmail = '';
let rowMenuItemDeleted = '';
let rowMenuItemStatusId = 0;
let rowMenuHref = '';
let rowMenuSelectedRow = null;
let rowMenuSiteId = null;
let rowMenuCallOffTypeId = null;
let rowMenuVisitId = null;

/*Table Functions */
function initTable(name, showMore) {
    consolelog('initTable', [name, showMore]);
    var tableName = name + 'Table';
    var table = $("#" + tableName);
    if (!table) {
        //consolelog('Can not find table:' + tableName)
        return;
    }

    var filter = $('#' + name + 'Filter').val();
    var rows = $('#' + tableName + ' > tbody tr');
    var found = false;

    $("#" + tableName).hide();

    //filter rows
    for (i = 0; i < rows.length; i++) {
        found = rowContainsFilter(rows[i], filter);
        rows[i].style.display = found ? "table-row" : "none";
        rows[i].style.visibility = found ? "visible" : "hidden";
    }

    //display legend
    var legendNames = $('#legendNames' + name).val();
    var legendDisplay = $('#legendDisplay' + name);
    var smallLegend = $('#hiddenLegendSmall' + name).val() == 'true';

    if (legendNames && legendNames.length > 0) {
        setTableLegendFromCookie(name);

        var hiddenLegendNames = $('#hiddenLegendNames' + name).val();
        var arrLegendNames = legendNames.split(";");
        var legendHtml = '';
        for (var x = 0; x < arrLegendNames.length; x++) {
            var legendCss = arrLegendNames[x].split(":")[0];
            if (legendCss && legendCss.length > 0) {
                var legendName = arrLegendNames[x].split(":")[1];
                var legendHidden = hiddenLegendNames && hiddenLegendNames.length > 0 && hiddenLegendNames.split(";").includes(legendCss);

                if (legendHidden) {
                    $("#" + name + "Table > tbody tr[data-legend-css='" + legendCss + "']").hide();
                    $("#" + name + "Table > tbody tr." + legendCss).hide();
                } 

                var rowCount = 0;
                if (legendHidden) {
                    //consolelog(legendCss + ' is hidden');
                    rows = $('#' + name + 'Table > tbody tr.' + legendCss);
                    if (rows.length == 0) {
                        rows = $('#' + name + 'Table > tbody tr[data-legend-css="' + legendCss + '"]');
                    }

                    for (i = 0; i < rows.length; i++) {
                        if (rowContainsFilter(rows[i], filter)) rowCount += 1;
                    }
                } else {
                    //consolelog(legendCss + ' is not hidden');
                    //rowCount = $("#" + name + "Table > tbody tr." + legendCss + ':visible').length;
                    var rowCount = $("#" + name + "Table > tbody tr." + legendCss).filter(function () {
                        return $(this).css('display') !== 'none';
                    }).length;

                    if (rowCount == 0) {
                        var rowCount = $('#' + name + 'Table > tbody tr[data-legend-css="' + legendCss + '"]').filter(function () {
                            return $(this).css('display') !== 'none';
                        }).length;
                    }
                }

                //consolelog('Counting rows for ' + legendCss + ' - ' + rowCount + ' found');

                if (rowCount > 0) {
                    var legendText = legendName + " (" + rowCount + ")";
                    if (smallLegend) legendText = rowCount;
                    if (legendHidden) legendText += " - Off";
                    legendHtml += "<span class='badge " + legendCss + "' data-legend-context='"  + name + "' data-legend='" + legendCss + "' title='Click to show/hide " + legendName + " rows'>" + legendText + "</span>"
                }
            }
        }

        legendDisplay.html(legendHtml);
        $("span.badge[data-legend-context=" + name + "]").off('click').click(function () { toggleLegend($(this).data('legend'), name); });
    } else {
        //consolelog('no legend names');
        legendDisplay.html("");
    }

    countTableRows(name);

    //var visibleRowCount = $("#" + tableName + " > tbody tr:visible").length;
    var visibleRowCount = $("#" + tableName + " > tbody tr").filter(function () {
        return $(this).css('display') !== 'none';
    }).length;

    //consolelog('Visible Rows', [visibleRowCount]);
    visibleRowCount > 0 ? $("#" + tableName).show() : $("#" + tableName).hide();

    //consolelog('Deciding to show message', ["#noRowsFound" + name]);
    visibleRowCount > 0 ? $("#noRowsFound" + name).css('display', 'none') : $("#noRowsFound" + name).css('display', 'block');

    applyTableSort(name);

    if (showMore && showMore == 'True') $('[id^=more]').trigger('click');

    if (typeof displaySummaryValue == 'function') {
        var sumValue = 0;
        $("#" + tableName + " > tbody tr").filter(function () {
            if ($(this).css('display') !== 'none') {
                var value = $(this).attr('data-summary-value');
                if (value) sumValue += Number(value);
            }
        });

        displaySummaryValue(sumValue);
    }
}
function initTableSort() {
    $('th[data-sortable]').off('click').click(function () {
        //consolelog('Sort Click', [this]);
        sortTable(this);
    });
}

function firstVisibleRowId(name) {
    var firstRowId = null;
    var rows = $('#' + name + 'Table > tbody tr').filter(function () {
        return $(this).css('display') !== 'none';
    });

    let itemId = 0;
    let altItemId = 0;
    if (rows[0]) {
        itemId = toInt($(rows[0]).data('itemid'));
        altItemId = toInt($(rows[0]).data('altitemid'));
    }
    return { itemId: itemId, altItemId: altItemId };
}
function sortTable(thElem, sortOrder, tId) {
    var table = $(thElem).parents('table').eq(0)
    var tableId = table.attr('id');
    //consolelog('sortTable', [thElem, sortOrder, tId]);

    if (table.length > 0) {
        var colIndex = $(thElem).index();

        var rows = table.find('tr:gt(0)').toArray().sort(tableSortComparer($(thElem).index()))
        thElem.asc = !thElem.asc
        $(table).find('th > i').removeClass('fa-sort').removeClass('fa-sort-asc').removeClass('fa-sort-desc');
        $(table).find('th > i').addClass('fa-sort')
        $(thElem).children('i').eq(0).removeClass('fa-sort');

        if (sortOrder == 'desc' || !thElem.asc) {
            sortOrder = 'desc';
            $(thElem).children('i').eq(0).addClass('fa-sort-desc');
            rows = rows.reverse();
        } else {
            sortOrder = 'asc';
            $(thElem).children('i').eq(0).addClass('fa-sort-asc');
        }

        for (var i = 0; i < rows.length; i++) { table.append(rows[i]) }
    } else {
        tableId = tId + 'Table';
    }

    moveRowsToTheTop(tableId);

    moveRowsToTheBottom(tableId);

    setCookie(tableId + 'sort', JSON.stringify({tableId: tableId, colIndex: colIndex, sortOrder: sortOrder}), 100);
}

function moveRowsToTheTop(tableId) {
    var selector = '#' + tableId + " tr.rowTop";
    var rowsToMove = $(selector);

    //consolelog('moveRowsToTheTop', [selector, rowsToMove.length]);

    rowsToMove.each(function () {
        $(this).prependTo($(this).closest("tbody"));
    });
}

function moveRowsToTheBottom(tableId) {
    var selector = '#' + tableId + " tr.rowBottom";
    var rowsToMove = $(selector);

    //consolelog('moveRowsToTheBottom', [selector, rowsToMove.length]);

    rowsToMove.each(function () {
        $(this).appendTo($(this).closest("tbody"));
    });
}

function applyTableSort(tableId) {
    //consolelog('Getting table sort cookie', tableId);
    let data = $('#' + tableId + 'Table').data('apply-sort');
    if (data == false) return;

    let cookieValue = getCookie(tableId + 'Tablesort', '');
    if (!hasContent(cookieValue)) return;

    let sortValues = JSON.parse(cookieValue);
    //consolelog('applyTableSort', [sortValues.tableId, sortValues.colIndex, sortValues.sortOrder]);

    sortTable($('#' + sortValues.tableId).find("th").eq(sortValues.colIndex), sortValues.sortOrder, tableId);
}

function initTableRowClick(tableName, rowSelector, override) {
    if (!_rowClickEnabled && !override) return;

    var selector = rowSelector && rowSelector.length > 0
        ? "tr[" + rowSelector + "]" : "tr[data-href]";

    var element = tableName && tableName.length > 0
        ? $('#' + tableName + 'Table') : $(document.body);

    $(element).on("click", selector, function (evt) {
        //consolelog('row is clicked with href');

        if ($(evt.target).is("div.badge") || $(evt.target).is("a") || $(evt.target).is("i") || $(evt.target).is("input")) {
            return;
        }

        if (typeof onHrefRowClick === 'function') {
            var href = this.dataset.href;
            onHrefRowClick(href);
        }
    });
}

function initTableFilterSearch() {
    consolelog('initTableFilterSearch');
    $('.tableFilterInput').on('search', function () {
        var name = $(this).data('filter-name');
        filterTable(name);
    });
}
function rowContainsFilter(row, filter) {
    if (!row) return false;
    if (!filter || filter.length == 0) return true;

    cells = row.getElementsByTagName("td");
    for (j = 0; j < cells.length; j++) {
        td = cells[j];
        if (td) {
            txtValue = td.innerText; //td.textContent ||
            if (txtValue.toUpperCase().indexOf(filter.toUpperCase()) > -1) {
                //consolelog("found: " + txtValue);
                return true;
            }
        }
    }
    return false;
}
function filterTable(name) {
    consolelog('filterTable', name);
    initTable(name);
}
function countTableRows(name) {
    consolelog('countTableRows', name);
    if (!name || name.length == 0) return;

    var smallLegend = $('#hiddenLegendSmall' + name).val() == 'true';
    var rowCount = $("#" + name + "Table > tbody tr").length;

    if (rowCount > 0) {
        //var visibleRowCount = $("#" + name + "Table > tbody tr:visible").length;
        var visibleRowCount = $("#" + name + "Table > tbody tr").filter(function () {
            return $(this).css('display') !== 'none';
        }).length;

        var rowCountText = smallLegend ? rowCount : rowCount + ' Records Displayed';
        $('#legendCount' + name).removeClass('text-danger').removeClass('text-info').attr('title', '');
        $('#legendCount' + name).off('click');

        if (rowCount >= 1000) $('#legendCount' + name).addClass('text-danger');

        if (rowCount > visibleRowCount) {
            rowCountText = smallLegend ? visibleRowCount + '/' + rowCount : visibleRowCount + '/' + rowCount + ' Records Displayed';
            if (rowCount < 1000) $('#legendCount' + name).addClass('text-info')
            $('#legendCount' + name).attr('title', 'Click to show ALL rows');
            $('#legendCount' + name).on('click', function () {
                resetLegend(name);
            });
        }

        $('#legendCount' + name).text(rowCountText);
    } else {
        $('#legendCount' + name).text("No Records Found");
    }
}
function setTableLegendFromCookie(name) {
    consolelog('setTableLegendFromCookie', name);

    var cname = 'hiddenLegendNames' + name;
    var cvalue = getCookie(cname, '?');
    if (cvalue.length > 0 && cvalue !== '?') $('#' + cname).val(cvalue);
}
function resetLegend(tableName) {
    $('#hiddenLegendNames' + tableName).val('');
    setCookie('hiddenLegendNames' + tableName, '', 100)
    initTable(tableName);
}
function toggleLegend(cssName, tableName) {
    consolelog('toggleLegend', [cssName, tableName]);
    var hiddenNames = $('#hiddenLegendNames' + tableName).val();
    if (hiddenNames && hiddenNames.length > 0 && hiddenNames.split(";").includes(cssName)) {
        hiddenNames = hiddenNames.replace(cssName + ';', '');
    } else {
        hiddenNames = hiddenNames ? hiddenNames + cssName + ";" : cssName + ";";
    }

    $('#hiddenLegendNames' + tableName).val(hiddenNames);
    setCookie('hiddenLegendNames' + tableName, hiddenNames, 100)
    initTable(tableName);
}
function sort(table, column, direction) {
    var filter = '';
    if (table && table.length > 0) {
        filter = $('#' + table + 'Filter').val();
    }
    window.location.href = window.location.pathname + "?" + $.param({ 'sort': column, 'dir': direction, 'flt': filter });
}
function onHrefRowClick(url) {
    consolelog('onHrefRowClick', url);

    if (!url || url == '') return;

    if (url.indexOf('script:', 0) == 0) {
        window[url.replace('script:', '')]();
    }
    else if (window.location.href == url || window.location.href.endsWith(url)) {
        location.reload();
    }
    else {
        window.location.href = url;
    }
}
function tableSortComparer(index) {
    return function (a, b) {
        var valA = getSortValue(a, index), valB = getSortValue(b, index);
        return $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.toString().localeCompare(valB);
    }
}
function getSortValue(row, index) {
    var sortValue = $(row).children('td').eq(index).data('sort-value');
    return sortValue;
}
function highlightSelectedTableRowWithId(name, rowId, moveToRow) {
    consolelog('highlightSelectedTableRowWithId', [name, rowId, moveToRow]);
    $("#" + name + "Table > tbody tr").removeClass('sel');
    var headerClass = $('#headerClass').val();
    var selectedClass = 'sel ' + headerClass ?? "" ;
    $("tr#row" + rowId).removeClass().addClass(selectedClass);
    if (moveToRow) scrollRowToTop('', rowId);
}
function highlightSelectedTableRowWithItemTypeIdItemId(name, itemTypeId, subItemTypeId, itemId) {
    consolelog('highlightSelectedTableRowWithItemTypeIdItemId', [name, itemTypeId, itemId]);
    $("#" + name + "Table > tbody tr").removeClass('sel');
    var headerClass = $('#headerClass').val();
    var selectedClass = 'sel ' + headerClass ?? "";
    var row = $('tr#row' + itemId + '[data-itemtypeid="' + itemTypeId + '"][data-subitemtypeid="' + subItemTypeId + '"]');
    row.removeClass().addClass(selectedClass);
}
function rowData(name, rowIndex, dataName) {
    var rows = $('#' + name + 'Table > tbody tr');
    var data = $(rows[rowIndex]).data(dataName);
    return data ? data : 0;
}
function initRowSelect(context) {
    //consolelog('initRowSelect: ' + context);
    $('[data-role="rowSelect"][data-context= "' + context+ '"]').prop('checked', false).change();
}
function rowSelectChanged(chkbox) {
    var rowId = $(chkbox).data('itemid');
    var context = $(chkbox).data('context');
    var isChecked = $(chkbox).is(':checked');
    //consolelog('rowSelectChanged: ' + rowId + ', ' + context + ', ' + isChecked);

    var row = $('#row' + rowId + '[data-context="' + context + '"]');
    $(row).removeClass("table-dark");

    $('[data-role="rowInput"][data-itemid="' + rowId + '"][data-context= "' + context + '"]').prop('disabled', !isChecked);
    $('[data-role="all"][data-itemid="' + rowId + '"][data-context= "' + context + '"]').prop('disabled', !isChecked);

    if (isChecked) $(row).addClass('table-dark');

    if (typeof rowSelected !== 'undefined' && typeof rowSelected === 'function') rowSelected(rowId, context, isChecked);
}
function rowsSelectChanged(chkbox) {
    var context = $(chkbox).data('context');
    var isChecked = $(chkbox).is(':checked');
    //consolelog('rowsSelectChanged: ' + context + ', ' + isChecked);

    $('[data-role="rowSelect"][data-context= "' + context + '"]').prop('checked', isChecked).change();
}
function getSelectedRows(ctx, title, css) {
    var selectedValues = [];
    var selector = "tr[data-context='" + ctx + "']";
    var matchedRows = $(selector);
    matchedRows.each(function () {
        var row = $(this);
        var isSelected = row.find('input[data-role="rowSelect"]').is(':checked');

        if (isSelected) {
            var itemid = row.find('input[data-role="rowSelect"]').data('itemid');
            selectedValues.push({
                Id: itemid,
            });
        }
    });

    if (selectedValues.length === 0 && title && title.length > 0) {
        showAlert(title, 'Please select at least one row.', css);
    }

    return selectedValues;
}

function toggleLegendLock(name) {
    var cookieName = 'legendLock' + name;
    consolelog('toggleLegendLock', cookieName);

    if (getCookie(cookieName, '0') == '1') {
        setCookie(cookieName, '0', 0);
    } else {
        setCookie(cookieName, '1', 100);
    }

    displayLegendLock(name);
}
function displayLegendLock(name) {
    consolelog('displayLegendLock', name);

    var cookieName = 'legendLock' + name;
    var addClassName = 'on';
    var removeClassName = 'off';
    if (getCookie(cookieName, '0') == '1') {
        addClassName = 'on';
        removeClassName = 'off';
    }

    $('#legendLockIcon' + name).addClass('fa-toggle-' + addClassName).removeClass('fa-toggle-' + removeClassName);
}
function initContextMenu() {
    consolelog("initContextMenu");
    $("tr").on('contextmenu', function (e) {
        e.preventDefault(); // Prevent the default context menu

        let ctxMenuName = $(this).data('menuname');
        if (!hasContent(ctxMenuName)) 
            return _callFailed('initContextMenu: row does not contain a data-menuname property');

        const altMenuIndex = toInt($(this).data('altmenu-index'));
        if (altMenuIndex > 0) ctxMenuName += '-alt' + altMenuIndex;

        const properId = toProperId('#rowmenu' + ctxMenuName);
        if (!properId.exists) return _callFailed('initContextMenu: context menu ' + properId.value + ' not found');

        setRowItemValues(this);

        const ctxMenu = $('#rowmenu' + ctxMenuName);

        ctxMenu.css({
            position: 'absolute',
            top: e.clientY + 'px',
            left: e.clientX + 'px',
            display: 'block'
        });

        // Check if the menu goes off the page vertically
        const menuHeight = ctxMenu.outerHeight();
        const windowHeight = $(window).height();
        if (e.clientY + menuHeight > windowHeight) {
            ctxMenu.css('top', e.clientY - menuHeight + 'px');
        }

        // Check if the menu goes off the page horizontally
        const menuWidth = ctxMenu.outerWidth();
        const windowWidth = $(window).width();
        if (e.clientX + menuWidth > windowWidth) {
            ctxMenu.css('left', e.clientX - menuWidth + 'px');
        }

        ctxMenu.mouseleave(function () {
            setTimeout(function () {
                ctxMenu.css("display", "none");
            }, 200);
        });

        return false; //blocks default Webbrowser right click menu
    });

    $("body").on("click", function () {
        if ($("#ctxmenu").css('display') == 'block') {
            $(" #ctxmenu ").hide();
        }
    });

    $("#ctxmenu a").on("click", function () {
        $(this).parent().hide();
    });

    $("table").on("click", ".row-menu [data-toggle='dropdown']", function (e) {
        const row = $(this).closest("tr")[0];
        setRowItemValues(row);
    });
}

function setRowItemValues(row) {
    rowMenuItemTypeId = $(row).data('itemtypeid');
    rowMenuItemId = $(row).data('itemid');

    if (!rowMenuItemId) {
        consolelog("No data-itemid found");
        return;
    }

    rowMenuSelectedRow = row;
    rowMenuItemReference = $(row).data('itemref');
    rowMenuItemAddress = $(row).data('itemaddress');
    rowMenuItemEmail = $(row).data('itememail');
    rowMenuItemStatusId = $(row).data('itemstatusid');
    rowMenuHref = $(row).data('href');
    rowMenuSiteId = $(row).data('siteid');
    rowMenuCallOffTypeId = $(row).data('callofftypeid');
    rowMenuVisitId = $(row).data('visitid');
    rowMenuItemDeleted = $(row).data('itemdeleted');
}


function scrollRowToTop(container, rowId) {
    consolelog('scrollRowToTop', [container, rowId]);
    var row = $("tr#row" + rowId)[0];
    if (row) row.scrollIntoView();
}
/* Loop through all dropdown buttons to toggle between hiding and showing its dropdown content - This allows the user to have multiple dropdowns without any conflict */
var dropdownList, i;
dropdownList = document.getElementsByClassName("dropdown-btn");

if (dropdownList) {
    var showSM = getCookie('showSideMenu');
    for (i = 0; i < dropdownList.length; i++) {
        var ddl = dropdownList[i];
        var ddm = ddl.nextElementSibling;

        if (showSM == 'true') {
            ddl.classList.add("active");
            ddm.style.display = "block";
        }

        ddl.addEventListener("click", function () {
            consolelog('Menu Click');
            var dropdownMenu = this.nextElementSibling;
            if (dropdownMenu.style.display === "block") {
                this.classList.remove("active");
                dropdownMenu.style.display = "none";
            } else {
                this.classList.add("active");
                dropdownMenu.style.display = "block";
                var href = $(this).data('href');
                if (href) navigateToPage(href);
            }
        });
    }
}

function toggleMenu() {
    var dropdownList, i;
    dropdownList = document.getElementsByClassName("dropdown-btn");

    if (dropdownList) {
        var open = false, closed = false;
        for (i = 0; i < dropdownList.length; i++) {
            var dropdownContent = dropdownList[i].nextElementSibling;
            if (dropdownContent.style.display === "block") {
                open = true;
            } else {
                closed = true;
            }
        }
        for (i = 0; i < dropdownList.length; i++) {
            dropdownContent = dropdownList[i].nextElementSibling;
            if ((open && closed) || closed) {
                dropdownList[i].classList.add("active");
                dropdownContent.style.display = "block";
            } else {
                dropdownList[i].classList.remove("active");
                dropdownContent.style.display = "none";
            }
        }

        if ((open && closed) || closed) {
            setCookie('showSideMenu', 'true', 100);
        } else {
            setCookie('showSideMenu', 'false', 100);
        }
    }
}
function showAlert(title, message, css) {
    if (!hasContent(message)) return _callFailed('showAlert');
    if (!hasContent(title)) title = 'Contor';
    if (!hasContent(css)) css = 'ctr';

    consolelog('showAlert', [title, message, css]);

    $('#pageAlertTitle').html(title);
    $('#pageAlertContent').html(message);

    var options = {
        "backdrop": "static",
        "keyboard": false
    }

    modalShow('#pageAlert', true, css);
}
function showConfirm(title, message, context, onConfirmCallback, css) {
    if (!title || title.length == 0) title = 'Contor';
    if (!message || message.length == 0) return;
    consolelog('showConfirm', [title, message, context]);

    $('#pageConfirmOkButton').off('click');
    $('#pageConfirmTitle').html(title);
    $('#pageConfirmContent').html(message);
    $('#pageConfirmContext').val(context);

    var onConfirm = function () {
        onConfirmCallback ? onConfirmCallback(context) : onConfirmOk(context);
    };

    $('#pageConfirmOkButton').click(onConfirm);

    modalShow('#pageConfirm', true, css);
}

function modalShow(id, onTop, css) {
    if (!css || css == '') css = 'ctr';
    consolelog('modalShow', [id, onTop, css]);

    if (onTop) $(id).css('zIndex', 99999);
    $(id).modal({
        backdrop: 'static',
        keyboard: false
    });

    $(id).draggable({
        handle: ".modal-header",
    });

    $(".modal-backdrop.in").css({ opacity: 0.1 });
    $(".modal-header").css({
        cursor: 'move',
    });

    $('.modal-header').addClass(css);
}

function modalHide(id) {
    $(id).modal("hide")
}
function showModal(title, url, viewUrl, viewName, css, size, onShowModal) {
    consolelog('showModal', [title, url, viewUrl, css]);
    if (!url || url.length == 0) return;

    $('#pageModalViewButton').hide();
    $('#pageModalMessage').hide();

    $('#pageModalTitle').html(title);
    loadUrl('#pageModalContent', url, function () {
        $('.modal .formHelp').hide();
        $('.modal .pageHelp').hide();
        if (typeof onShowModal == 'function') onShowModal();
    });

    if (viewUrl && viewUrl.length > 0) {
        $('#pageModalViewButton').prop('href', viewUrl);
        $('#pageModalViewButton').html(viewName && viewName.length > 0 ? 'View ' + viewName : 'View');
        $('#pageModalViewButton').show();
    }

    resizeModal('pageModalDialog', size);

    modalShow('#pageModal', false, css);
}

function resizeModal(id, size) {
    if (!hasContent(size)) size = 'xl';

    if (size && (size == 'sm' || size == 'md' || size == 'lg' || size == 'xl')) {
        $('#'+id).removeClass('modal-sm').removeClass('modal-md').removeClass('modal-lg').removeClass('modal-xl');
        $('#'+id).addClass('modal-' + size);
    }
}

function showAddModal(title, url, saveCallback, css, size, saveButtonText, onShowAddModal) {
    consolelog('showAddModal', [title, url, css]);
    if (!url || url.length == 0) return;

    if (!css || css == '') css = 'ctr';
    if (!saveButtonText || saveButtonText == '') saveButtonText = 'Save';
    $('#pageAddModalHeader').removeClass().addClass('modal-header').addClass('ui-gragable-handle');
    $('#pageAddModalHeader').addClass(css);

    $('#pageAddModalMessage').html('').hide();
    $('#pageAddModalAlert').html('').hide();
    $('#pageAddModalSaveButton').off('click');
    $('#pageAddModalSaveButton').html(saveButtonText);
    $('#pageAddModalSaveButton').prop('disabled', false);

    $('#pageAddModalTitle').html(title);
    if (saveCallback) {
        $('#pageAddModalSaveButton').click(saveCallback);
    }
    else {
        setPageAddModalSystemError('Save button not bound');
    }
    debugger;
    loadUrl('#pageAddModalContent', url, function () {
        validateModalFrm('pageAddModalContent');
        $('.modal .formHelp').hide();
        $('.modal .pageHelp').hide();
        if (typeof onShowAddModal == 'function') onShowAddModal();
    });

    resizeModal('pageAddModalDialog', size);

    modalShow('#pageAddModal', null, css);
}
function showEditModal(title, url, saveCallback, deleteCallback, isDeleted, css, deleteButtonText, size) {
    consolelog('showEditModal', [title, url, css]);
    if (!url || url.length == 0) return;

    if (!css || css == '') css = 'ctr';
    $('#pageEditModalHeader').removeClass().addClass('modal-header').addClass('ui-gragable-handle');
    $('#pageEditModalHeader').addClass(css);

    $('#pageEditModalSaveButton').off('click');
    $('#pageEditModalDeleteButton').off('click').hide();
    $('#pageEditModalConfirmButton').off('click').hide();
    $('#pageEditModalMessage').html('').hide();
    $('#pageEditModalAlert').html('').hide();
    $('#pageEditModalSaveButton').prop('disabled', false);

    $('#pageEditModalTitle').html(title);
    $('#pageEditModalSaveButton').show();
    if (saveCallback) {
        $('#pageEditModalSaveButton').click(saveCallback);
    }
    else {
        setPageEditModalSystemError('Save button not bound');
    }

    if (deleteCallback) {
        if (!deleteButtonText || deleteButtonText.length == 0) deleteButtonText = 'Delete';
        $('#pageEditModalDeleteButton').show();

        if (isDeleted && (isDeleted.toLowerCase() == 'true' || toInt(isDeleted) == 1)) {
            $('#pageEditModalTitle').html(title + ' <span class="text-danger">[DELETED]</span>');
            $('#pageEditModalDeleteButton').html('Recover').removeClass('btn-danger').addClass('btn-primary');
            $('#pageEditModalDeleteButton').click(deleteCallback);
            $('#pageEditModalSaveButton').prop('disabled', true);
            setPageEditModalError('You will need to recover this record to save any changes');
        }
        else {
            $('#pageEditModalDeleteButton').html(deleteButtonText).removeClass('btn-primary').addClass('btn-danger');
            $('#pageEditModalConfirmButton').click(deleteCallback);
            $('#pageEditModalDeleteButton').click(function () {
                setPageEditModalConfirm('Are you sure you want to ' + deleteButtonText.toLowerCase() + ' this data?');
                $('#pageEditModalDeleteButton').hide();
                $('#pageEditModalSaveButton').hide();
                $('#pageEditModalConfirmButton').show();
            });
        }
    }

    loadUrl('#pageEditModalContent', url, function () {
        validateModalFrm('pageEditModalContent');
        $('.modal .formHelp').hide();
        $('.modal .pageHelp').hide();
    });

    resizeModal('pageEditModalDialog', size);

    modalShow('#pageEditModal', null, css);
}
function showViewEditModal(title, viewUrl, editUrl, saveCallback, deleteCallback, recoverCallback, isDeleted, confirm, css, size) {
    consolelog('showViewEditModal: ' + title + '; ' + viewUrl + ', ' + editUrl + '; ' + css);
    if ((!viewUrl || viewUrl.length == 0 || !editUrl || editUrl.length == 0)) return;

    if (!css || css == '') css = 'ctr';
    $('#pageViewEditModalHeader').removeClass().addClass('modal-header').addClass('ui-gragable-handle');
    $('#pageViewEditModalHeader').addClass(css);

    $('#pageViewEditModalContent').html('');
    $('#pageViewEditModalCancelButton').off('click').hide();
    $('#pageViewEditModalEditButton').off('click').hide();
    $('#pageViewEditModalSaveButton').off('click').hide();
    $('#pageViewEditModalDeleteButton').off('click').hide();
    $('#pageViewEditModalConfirmButton').off('click').hide();
    $('#pageViewEditModalMessage').html('').hide();
    $('#pageViewEditModalAlert').html('').hide();

    $('#pageViewEditModalTitle').html(title);
    if (isDeleted) {
        $('#pageViewEditModalTitle').html(title + ' <span class="text-danger">[DELETED]</span>');
    }

    var showDelete = !isDeleted && deleteCallback != null;
    var showRecover = isDeleted && recoverCallback != null;

    var view = function () {
        pageViewEditModal_ViewMode(showRecover);
        loadUrl('#pageViewEditModalContent', viewUrl, function () {
            $('#pageViewEditModalMessage').html('').hide();
            $('#pageViewEditModalAlert').html('').hide();
            $('.modal .formHelp').hide();
            $('.modal .pageHelp').hide();
        });
    };
    var edit = function () {
        pageViewEditModal_EditMode(viewUrl, showDelete);
        loadUrl('#pageViewEditModalContent', editUrl, function () {
            validateModalFrm('pageViewEditModalContent');
            $('#pageViewEditModalMessage').html('').hide();
            $('#pageViewEditModalAlert').html('').hide();
            $('.modal .formHelp').hide();
            $('.modal .pageHelp').hide();
        });
    };

    if (saveCallback) {
        $('#pageViewEditModalSaveButton').click(saveCallback);
    }
    else {
        setPageViewEditModalSystemError('Save button not bound');
    }

    if (showRecover) {
        $('#pageViewEditModalDeleteButton').click(recoverCallback);
        $('#pageViewEditModalDeleteButton').html('Recover').removeClass('btn-danger').addClass('btn-primary');
    }

    if (showDelete) {
        $('#pageViewEditModalDeleteButton').html('Delete').removeClass('btn-primary').addClass('btn-danger');
        if (confirm) {
            $('#pageViewEditModalConfirmButton').click(deleteCallback);
            $('#pageViewEditModalDeleteButton').click(function () {
                setPageViewEditModalConfirm('Are you sure you want to delete this data?');
                $('#pageViewEditModalDeleteButton').hide();
                $('#pageViewEditModalSaveButton').hide();
                $('#pageViewEditModalConfirmButton').show();
            });
        } else {
            $('#pageViewEditModalDeleteButton').click(deleteCallback);
        }
    }

    $('#pageViewEditModalCancelButton').click(view);
    $('#pageViewEditModalEditButton').click(edit);

    if (viewUrl && viewUrl.length > 0) view(); else edit();

    resizeModal('pageViewEditModalDialog', size);

    modalShow('#pageViewEditModal', null, css);
}
function pageViewEditModal_EditMode(viewUrl, showDelete) {
    if (viewUrl && viewUrl.length > 0) {
        $('#pageViewEditModalCloseButton').hide();
        $('#pageViewEditModalCancelButton').show();
    } else {
        $('#pageViewEditModalCloseButton').show();
        $('#pageViewEditModalCancelButton').hide();
    }

    $('#pageViewEditModalEditButton').hide();
    $('#pageViewEditModalSaveButton').show();
    $('#pageViewEditModalMessage').hide();

    if (showDelete) $('#pageViewEditModalDeleteButton').show();
}
function pageViewEditModal_ViewMode(showRecover) {
    $('#pageViewEditModalSaveButton').hide();
    $('#pageViewEditModalCancelButton').hide();
    $('#pageViewEditModalConfirmButton').hide();
    $('#pageViewEditModalDeleteButton').hide();
    $('#pageViewEditModalEditButton').show();
    $('#pageViewEditModalCloseButton').show();
    $('#pageViewEditModalMessage').hide();

    if (showRecover) {
        $('#pageViewEditModalDeleteButton').show();
        $('#pageViewEditModalEditButton').hide();
    }
}

function _enableAddModal(enable) {
    $('#pageAddModalSaveButton').prop('disabled', !enable);
}

function setPageModalError(msg) {
    setModalError('pageModalMessage', msg);
};
function setPageModalSuccess(msg) {
    setModalSuccess('pageModalMessage', msg);
};
function setPageAddModalSystemError(msg) {
    consolelog('setPageAddModalError: ' + msg);
    setModalError('pageAddModalMessage', '**SYSTEM**' + msg);
};
function setPageAddModalError(msg) {
    consolelog('setPageAddModalError: ' + msg);
    setModalError('pageAddModalMessage', msg);
};
function setPageAddModalSuccess(msg) {
    setModalSuccess('pageAddModalMessage', msg);
};
function setPageEditModalSystemError(msg) {
    setModalError('pageEditModalMessage', '**SYSTEM**'+msg);
};
function setPageEditModalError(msg) {
    setModalError('pageEditModalMessage', msg);
};
function setPageEditModalSuccess(msg) {
    setModalSuccess('pageEditModalMessage', msg);
};
function setPageEditModalConfirm(msg) {
    setModalConfirm('pageEditModalMessage', msg);
};
function setPageViewEditModalSystemError(msg) {
    setModalError('pageViewEditModalMessage', '**SYSTEM**'+msg);
};
function setPageViewEditModalError(msg) {
    setModalError('pageViewEditModalMessage', msg);
};
function setPageViewEditModalConfirm(msg) {
    setModalConfirm('pageViewEditModalMessage', msg);
};
function setPageViewEditModalSuccess(msg) {
    setModalSuccess('pageViewEditModalMessage', msg);
};
function setModalError(id, msg) {
    consolelog('setModalError: ' + id + '; ' + msg);
    $('#' + id).removeClass('text-success').removeClass('text-info').addClass('text-danger').html(msg);
    $('#' + id).show();
};
function setModalConfirm(id, msg) {
    consolelog('setModalConfirm', [id,msg]);
    $('#' + id).removeClass('text-success').removeClass('text-danger').html(msg).addClass('text-info').html(msg);
    $('#' + id).show();
};
function setModalSuccess(id, msg) {
    consolelog('setModalSuccess: ' + id + '; ' + msg);
    $('#' + id).removeClass('text-danger').removeClass('text-info').addClass('text-success').html(msg);
    $('#' + id).show();
};

function dismissPageModal() {
    consolelog('dismissPageModal');
    modalHide('#pageModal');
};
function dismissPageAddModal() {
    modalHide('#pageAddModal');
};
function dismissPageEditModal() {
    modalHide('#pageEditModal');
};
function dismissPageViewEditModal() {
    modalHide('#pageViewEditModal');
};

//COMMON
function isCommonContext(ctx) {
    if (!hasContent(ctx)) return false;
    ctx = ctx.toLowerCase();

    if (ctx == 'notes') return true;
    if (ctx == 'tasks') return true;
    if (ctx == 'partorders') return true;
    if (ctx == 'payments') return true;
    if (ctx == 'products') return true;
    if (ctx == 'appointments') return true;
    if (ctx == 'attachments') return true;

    return false;
}
function _loadCommonChildContent(childName, itemTypeId, itemId) {
    if (!hasContent(childName) || toInt(itemTypeId) <= 0 || toInt(itemId) <= 0)
        return _callFailed('_loadCommonChildContent');

    const contentId = 'content_' + childName;
    if (!toProperId(contentId, false).exists) return false;

    let loaded = true;

    if (childName == 'notes')
        _loadNotes(contentId, itemTypeId, itemId);
    else if (childName == 'tasks')
        _loadTasks(contentId, itemTypeId, itemId);
    else if (childName == 'payments')
        _loadPayments(contentId, itemTypeId, itemId);
    else if (childName == 'appointments')
        _loadAppointments(contentId, itemTypeId, itemId);
    else if (childName == 'attachments')
        _loadAttachments(contentId, itemTypeId, itemId);
    else if (childName == 'products')
        _loadProducts(contentId, itemTypeId, itemId);
    else if (childName == 'partorders')
        _loadPartOrders(contentId, itemTypeId, itemId);
    else if (childName == 'itemlinks')
        _loadItemLinks(contentId, itemTypeId, itemId);
    else
        loaded = false;

    return loaded;
}

//NOTES
function _loadNotes(contentId, itemTypeId, itemId) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;
    if (!toProperId(contentId).exists) return;
    contentId = gProperId;

    const url = '/App/Notes/?itemType=' + itemTypeId + '&itemId=' + itemId;

    loadUrl(contentId, url);
}
function _showModalNotes(itemTypeId, itemId, itemReference, itemCss, itemName, itemViewUrl) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;

    consolelog('_showModalNotes', [itemTypeId, itemId, itemReference]);

    const url = '/App/ModalNotes/?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference;
    const title = 'Notes' + (hasContent(itemReference) ? ' for ' + itemReference : '');
    if (!itemViewUrl) itemViewUrl = '';
    if (!itemName) itemName = '';

    if (hasContent(itemName) && !hasContent(itemViewUrl)) {
        itemViewUrl = '/App/ItemRedirect/?itemType=' + itemTypeId + '&itemId=' + itemId;
    }

    showModal(title, url, itemViewUrl, itemName, itemCss);
}
function _showAddNote(titleSuffix, itemTypeId, itemId, itemReference, itemCss) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;

    const getUrl = '/App/NoteAdd?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference;
    const postUrl = '/App/NoteAdd';
    consolelog('_showAddNote' [getUrl, titleSuffix]);

    const saveCallback = function () {
        if (validateAddModalFrm()) {
            const data = getNoteAddModalData();
            ajaxPostJsonAddData(postUrl, data, 'notes');
        }
    };

    showAddModal(addSuffix("Add Note", titleSuffix), getUrl, saveCallback, itemCss);
}
function _showViewEditNote(titleSuffix, noteId, itemCss) {
    if (toInt(noteId) <= 0) return;

    const viewUrl = '/App/Note?noteId=' + noteId;
    const getUrl = '/App/NoteEdit?noteId=' + noteId;
    const postUrl = '/App/NoteEdit';
    consolelog('showViewEditNote', [getUrl, titleSuffix]);

    const saveCallback = function () {
        if (!validateViewEditModalFrm()) return;

        const data = getNoteEditModalData();
        ajaxPostJsonViewEditData(postUrl, data, 'notes');
    };

    showViewEditModal(addSuffix("View Note", titleSuffix), viewUrl, getUrl, saveCallback, null, null, false, false, itemCss);
}

//ATTACHMENTS
function _loadAttachments(contentId, itemTypeId, itemId) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;
    if (!toProperId(contentId).exists) return;
    contentId = gProperId;

    const url = '/App/Attachments/?itemType=' + itemTypeId + '&itemId=' + itemId;

    loadUrl(contentId, url);
}
function _showModalAttachments(itemTypeId, itemId, itemReference, itemCss, itemName, itemViewUrl) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;

    consolelog('_showModalAttachments', [itemTypeId, itemId, itemReference]);

    const url = '/App/ModalAttachments/?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference;
    const title = 'Attachments' + (hasContent(itemReference) ? ' for ' + itemReference : '');
    if (!itemViewUrl) itemViewUrl = '';
    if (!itemName) itemName = '';

    if (hasContent(itemName) && !hasContent(itemViewUrl)) {
        itemViewUrl = '/App/ItemRedirect/?itemType=' + itemTypeId + '&itemId=' + itemId;
    }

    showModal(title, url, itemViewUrl, itemName, itemCss);
}
function _showAddAttachment(titleSuffix, itemTypeId, itemId, itemReference, itemCss) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;

    const getUrl = '/App/AttachmentAdd/?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference;
    const postUrl = '/App/AttachmentAdd';
    consolelog('showAddAttachment', [getUrl, titleSuffix]);

    const saveCallback = function () {
        if (validateAddModalFrm()) {
            const data = getAttachmentAddModalData();
            ajaxPostFormAddData(postUrl, data, 'attachments');
        }
    };

    showAddModal(addSuffix("Add Attachment", titleSuffix), getUrl, saveCallback, itemCss);
}
function _showAddLogo(itemTypeId, itemId) {
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;

    const getUrl = '/App/AttachmentAdd/?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=';
    const postUrl = '/App/LogoAdd';
    consolelog('showAddAttachment', [getUrl]);

    const saveCallback = function () {
        if (validateAddModalFrm()) {
            const data = getAttachmentAddModalData();
            ajaxPostFormAddData(postUrl, data, 'attachments');
        }
    };

    showAddModal("Select an Image", getUrl, saveCallback, '', 'md');
}

//APPOINTMENTS
function _loadAppointments(contentId, itemTypeId, itemId) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;
    if (!toProperId(contentId).exists) return;
    contentId = gProperId;

    const url = '/App/Appointments/?itemType=' + itemTypeId + '&itemId=' + itemId;

    loadUrl(contentId, url);
}
function _showModalAppointments(itemTypeId, itemId, itemReference, itemCss, itemName, itemViewUrl) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;

    consolelog('_showModalAppointments', [itemTypeId, itemId, itemReference]);

    const url = '/App/ModalAppointments/?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference;
    const title = 'Appointments' + (hasContent(itemReference) ? ' for ' + itemReference : '');
    if (!itemViewUrl) itemViewUrl = '';
    if (!itemName) itemName = '';

    if (hasContent(itemName) && !hasContent(itemViewUrl)) {
        itemViewUrl = '/App/ItemRedirect/?itemType=' + itemTypeId + '&itemId=' + itemId;
    }

    showModal(title, url, itemViewUrl, itemName, itemCss);
}
function _showAddAppointment(titleSuffix, appointmentTypeId, itemTypeId, itemId, itemReference, itemCss) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;

    //Item Id and Item Type are allowed to be zero 
    //because the modal implenets the find item control
    //if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;

    const getUrl = '/App/AppointmentAdd?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference + '&appointmentType=' + appointmentTypeId;
    const postUrl = '/App/AppointmentAdd';
    consolelog('showAddAppointment'[getUrl, titleSuffix]);

    const saveCallback = function () {
        if (validateAddModalFrm()) {
            const data = getAppointmentAddModalData();
            ajaxPostJsonAddData(postUrl, data, 'appointments');
        }
    };

    showAddModal(addSuffix("Add Appointment", titleSuffix), getUrl, saveCallback, itemCss, 'lg');
}
function _showViewEditAppointment(titleSuffix, appointmentId, isDeleted, confirm, css) {
    if (toInt(appointmentId) <= 0) return;

    const viewUrl = '/App/Appointment?appointmentId=' + appointmentId;
    const getUrl = '/App/AppointmentEdit?appointmentId=' + appointmentId;
    const postUrl = '/App/AppointmentEdit';
    consolelog('_showViewEditAppointment', [getUrl, titleSuffix]);

    const saveCallback = function () {
        if (!validateViewEditModalFrm()) return;

        const data = getAppointmentEditModalData();
        ajaxPostJsonViewEditData(postUrl, data, 'appointments');
    };

    showViewEditModal(addSuffix("View Appointment", titleSuffix), viewUrl, getUrl, saveCallback, null, null, isDeleted, confirm, css, 'lg');
}

//TASKS
function _loadTasks(contentId, itemTypeId, itemId) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;
    if (!toProperId(contentId).exists) return;
    contentId = gProperId;

    const url = '/App/Tasks/?itemType=' + itemTypeId + '&itemId=' + itemId;

    loadUrl(contentId, url);
}
function _showAddTask(titleSuffix, itemTypeId, itemId, itemReference, css) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;

    var getUrl = '/App/TaskAdd?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference;
    var postUrl = '/App/TaskAdd';
    consolelog('showAddTask'[getUrl, titleSuffix]);

    var saveCallback = function () {
        if (validateAddModalFrm()) {
            var data = getTaskAddModalData();
            ajaxPostJsonAddData(postUrl, data, 'tasks');
        }
    };

    showAddModal(addSuffix("Add Task", titleSuffix), getUrl, saveCallback, css, 'lg');
}
function _showEditTask(titleSuffix, itemId, canDelete, css) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemId) <= 0) return;

    var getUrl = '/App/TaskEdit?taskId=' + itemId;
    var postUrl = '/App/TaskEdit';
    var deleteUrl = '/App/TaskDelete';
    consolelog('showEditTask', [getUrl, titleSuffix, canDelete, css]);

    var saveCallback = function () {
        if (validateEditModalFrm()) {
            var data = getTaskEditModalData();
            ajaxPostJsonAddData(postUrl, data, 'tasks');
        }
    };

    var deleteCallBack;
    if (canDelete && canDelete == 'true') {
        deleteCallBack = function () {
            var data = getTaskDeleteModalData();
            ajaxPostJsonData(deleteUrl, data, 'tasks');
        };
    }

    showEditModal(addSuffix("Edit Task", titleSuffix), getUrl, saveCallback, deleteCallBack, false, css, null, 'lg');
}
function _nudgeTask(taskId, onSuccess) {
    const data = { TaskId: taskId };
    const url = '/App/TaskNudge';
    ajaxPostJsonData(url, data, onSuccess, null, '', '');
}


function showAddReferenceData(titleSuffix, itemType, css, tag) {
    var getUrl = '/App/ReferenceDataAdd?itemType=' + itemType;
    if (tag && tag != '') getUrl += '&tag=' + tag;
    var postUrl = '/App/ReferenceDataAdd';
    consolelog('showAddReferenceData'[getUrl, titleSuffix]);

    var saveCallback = function () {
        if (validateAddModalFrm()) {
            var data = getReferenceDataAddModalData();
            ajaxPostJsonAddData(postUrl, data, 'refdata');
        }
    };

    showAddModal(addSuffix("Add", titleSuffix), getUrl, saveCallback, css, 'md');
}
function _showChangeStatus(titleSuffix, currentStatus, itemTypeId, itemId, itemReference, itemCss) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(currentStatus) <= 0) currentStatus = rowMenuItemStatusId;

    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;

    const getUrl = '/App/ChangeStatus?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference + '&statusId=' + currentStatus;
    const postUrl = '/App/ChangeStatus';
    consolelog('_showChangeStatus', [getUrl, titleSuffix]);

    const saveCallback = function () {
        if (validateAddModalFrm()) {
            var data = getChangeStatusData();
            ajaxPostJsonAddData(postUrl, data, 'changestatus');
        }
    };

    showAddModal(addSuffix("Change Status", titleSuffix), getUrl, saveCallback, itemCss, 'md');
}
function showCustomerEmail(itemType, itemId) {
    var getUrl = '/App/EmailCustomer?itemType=' + itemType + '&itemId=' + itemId;
    var postUrl = '/App/EmailCustomer';
    consolelog('showCustomerEmail' + [getUrl, postUrl]);

    var saveCallback = function () {
        if (!validateFrm(null, 'pageAddModalContent')) return;

        var data = getCustomerEmailModalData();
        ajaxPostJsonAddData(postUrl, data, 'customeremail');
    };

    showAddModal("Customer Email", getUrl, saveCallback);
}

//PAYMENTS
function _loadPayments(contentId, itemTypeId, itemId) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;
    if (!toProperId(contentId).exists) return;
    contentId = gProperId;

    const url = '/App/Payments/?itemType=' + itemTypeId + '&itemId=' + itemId;

    loadUrl(contentId, url);
}
function _showAddOmitPayment(itemTypeId, itemId, itemReference, css) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return _callFailed('_showAddOmitPayment');

    var getUrl = '/App/PaymentAddOmitAdd/?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference;
    var postUrl = '/App/PaymentAdd';

    consolelog('_showAddOmitPayment', [getUrl, itemReference]);

    var saveCallback = function () {
        if (validateAddModalFrm()) {
            var data = getPaymentAddOmitAddModalData();
            ajaxPostJsonAddData(postUrl, data, 'payments');
        }
    };

    showAddModal(addSuffix("Add - Add/Omit Transaction", itemReference), getUrl, saveCallback, css, 'lg');
}
function _showAddPayment(itemTypeId, itemId, itemReference, css) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return _callFailed('_showAddPayment');

    var getUrl = '/App/PaymentAdd/?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference;
    var postUrl = '/App/PaymentAdd';

    consolelog('_showAddPayment', [getUrl, itemReference]);

    var saveCallback = function () {
        if (validateAddModalFrm()) {
            var data = getPaymentAddModalData();
            ajaxPostJsonAddData(postUrl, data, 'payments');
        }
    };

    showAddModal(addSuffix("Add - Payment Transaction", itemReference), getUrl, saveCallback, css, 'lg');
}
function _showAddBalanceCorrection(itemTypeId, itemId, itemReference, css) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return _callFailed('_showAddBalanceCorrection');

    var getUrl = '/App/PaymentBalanceCorrectionAdd/?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference;
    var postUrl = '/App/PaymentAdd';

    consolelog('_showAddBalanceCorrection', [getUrl, itemReference]);

    var saveCallback = function () {
        if (validateAddModalFrm()) {
            var data = getPaymentBalanceCorrectionAddModalData();
            ajaxPostJsonAddData(postUrl, data, 'payments');
        }
    };

    showAddModal(addSuffix("Add - Balance Correction", itemReference), getUrl, saveCallback, css, 'md');
}
function _showViewEditPayment(paymentId, itemTypeId, itemReference, css, deleted) {
    if (toInt(paymentId) <= 0) paymentId = rowMenuItemId;
    if (toInt(paymentId) <= 0) return;

    consolelog('_showViewEditPayment', [paymentId, itemReference]);

    let viewUrl = '/App/Payment?paymentId=' + paymentId;
    let editUrl = '/App/PaymentEdit?paymentId=' + paymentId;
    let postUrl = '/App/PaymentEdit';

    let saveCallback = function () {
        if (!validateFrm(null, 'pageViewEditModalContent')) return;

        var data = getPaymentEditModalData();
        ajaxPostJsonViewEditData(postUrl, data, 'payments');
    };

    //0: cant delete, 1: not deleted, 2; deleted
    if (toInt(deleted) < 0) deleted = 0;
    if (toInt(deleted) > 2) deleted = 0;

    let deleteCallBack = null;
    if (deleted > 0) {
        deleteCallBack = function () {
            let deleteUrl = '/App/PaymentDelete';
            let data = { paymentId: paymentId, itemTypeId: itemTypeId };
            ajaxPostJsonViewEditData(deleteUrl, data, 'payments');
        };
    }

    const isDeleted = deleted == 2;
    showViewEditModal(addSuffix("View Payment", itemReference), viewUrl, editUrl, saveCallback, deleteCallBack, deleteCallBack, isDeleted, true, css, 'lg');
    //function showViewEditModal(title, viewUrl, editUrl, saveCallback, deleteCallback, recoverCallback, isDeleted, confirm, css, size) {

}

function _loadProducts(contentId, itemTypeId, itemId) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;
    if (!toProperId(contentId).exists) return;
    contentId = gProperId;

    const url = '/App/Products/?itemType=' + itemTypeId + '&itemId=' + itemId;

    loadUrl(contentId, url);
}
function _showAddProduct(titleSuffix, itemTypeId, itemId, itemReference, css) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return _callFailed('_showAddProduct');

    var getUrl = '/App/ProductAdd/?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference;
    var postUrl = '/App/ProductAdd';
    consolelog('showAddProduct', [getUrl, titleSuffix]);

    var saveCallback = function () {
        if (validateAddModalFrm()) {
            var data = getProductAddModalData();
            ajaxPostJsonAddData(postUrl, data, 'products');
        }
    };

    showAddModal(addSuffix("Add Product", titleSuffix), getUrl, saveCallback, css);
}
function showViewEditProduct(titleSuffix, id) {
    var viewUrl = '/App/Product?productId=' + id;
    var getUrl = '/App/ProductEdit?productId=' + id;
    var postUrl = '/App/ProductEdit';
    consolelog('showViewEditProduct', [getUrl, titleSuffix]);

    var saveCallback = function () {
        if (!validateFrm(null, 'pageViewEditModalContent')) return;

        var data = getProductEditModalData();
        ajaxPostJsonViewEditData(postUrl, data, 'products');
    };
    showViewEditModal(addSuffix("View Product", titleSuffix), viewUrl, getUrl, saveCallback);
}

function _loadPartOrders(contentId, itemTypeId, itemId) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;
    if (!toProperId(contentId).exists) return;
    contentId = gProperId;

    const url = '/App/PartOrders/?itemType=' + itemTypeId + '&itemId=' + itemId;

    loadUrl(contentId, url);
}
function _showAddPartOrder(titleSuffix, itemTypeId, itemId, itemReference, css) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return _callFailed('_showAddPartOrder');


    var getUrl = '/PartOrders/PartOrderAdd/?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference;
    var postUrl = '/PartOrders/PartOrderAdd';
    consolelog('_showAddPartOrder', [getUrl, titleSuffix]);

    var saveCallback = function () {
        if (validateAddModalFrm()) {
            var data = getPartOrderAddModalData();
            ajaxPostJsonAddData(postUrl, data, 'partorders');
        }
    };

    showAddModal(addSuffix("Add Part Order", titleSuffix), getUrl, saveCallback, css);
}
function showViewEditPartOrder(titleSuffix, id) {
    var viewUrl = '/PartOrders/PartOrder?partOrderId=' + id;
    var getUrl = '/PartOrders/PartOrderEdit?partOrderId=' + id;
    var postUrl = '/PartOrders/PartOrderEdit';
    consolelog('showViewEditPartOrder', [getUrl, titleSuffix]);

    var saveCallback = function () {
        if (!validateFrm(null, 'pageViewEditModalContent')) return;

        var data = getPartOrderEditModalData();
        ajaxPostJsonViewEditData(postUrl, data, 'partorders');
    };
    showViewEditModal(addSuffix("View Part Order", titleSuffix), viewUrl, getUrl, saveCallback);
}

function _loadItemLinks(contentId, itemTypeId, itemId) {
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;
    if (!toProperId(contentId).exists) return;
    contentId = gProperId;

    const url = '/App/ItemLinks/?itemType=' + itemTypeId + '&itemId=' + itemId;

    loadUrl(contentId, url);
}
function _showShareItem(css, itemId, itemTypeId, itemReference) {
    consolelog('_showShareItem', [itemId, itemTypeId, itemReference]);
    if (toInt(itemId) <= 0) itemId = rowMenuItemId;
    if (toInt(itemTypeId) <= 0) itemTypeId = rowMenuItemTypeId;
    if (!hasContent(itemReference)) itemReference = rowMenuItemReference;
    if (toInt(itemId) <= 0 || toInt(itemTypeId) <= 0) return;

    var getUrl = '/App/Share?itemType=' + itemTypeId + '&itemId=' + itemId + '&itemRef=' + itemReference;
    var postUrl = '/App/Share';
    consolelog('showShare', [getUrl]);

    var saveCallback = function () {
        if (!validateFrm(null, 'pageAddModalContent')) return;

        var data = getShareModalData();
        ajaxPostJsonAddData(postUrl, data, 'share');
    };

    showAddModal("Share Link", getUrl, saveCallback, css, 'md');
}

//GENERIC FUNCTIONS - WILL CALL LOCAL FUNCTIONS IF CTX NOT HANDLED

function _onSuccessAdd(data, ctx) {
    consolelog('_onSuccessAdd', [ctx]);
    dismissPageAddModal();

    if (!ctx) ctx = '';

    //SHARE SUCCESS
    if (ctx.toLowerCase() == 'share') {
        showAlert('Share', 'Record shared successfuly');

    //REF DATA SUCCESS
    } else if (ctx.toLowerCase() == 'refdata') {
        if (data && toInt(data.Id) > 0 && data.Tag && data.Tag != '' && toInt(data.ItemType) > 0) {
            var url = '/App/ReferenceDataList?itemType=' + data.ItemType;
            populateDropdown(url, data.Tag, data.Id);
        }

    //CUSTOMER EMAIL SUCCESS
    } else if (ctx.toLowerCase() == 'customeremail') {
        var data = getCustomerEmailModalData();
        var url = "mailto:" + data.EmailAddress + "?subject=" + data.EmailSubject + "&body=" + data.EmailText;
        window.location.href = url;

    //ADDRESS DETAIL SUCCESS
    } else if (ctx.toLowerCase() == 'addressdetail') {
        consolelog('_onSuccessAdd', ['Calling _onSuccessAddAddressDetail']);
        _onSuccessAddAddressDetail(data, ctx);

    //GENERAl ITEM ADDED
    } else if (isCommonContext(ctx)) {
        if (typeof loadHeader === 'function') {
            loadHeader();
            if (typeof loadChild === 'function') loadChild(ctx);
        }
        else if (typeof loadParent === 'function')
            loadParent();
        else
            reloadPage();
    }

    //ON SUCCESS ADD AVAILABLE
    else if (typeof onSuccessAdd === 'function') {
        consolelog('_onSuccessAdd', ['Calling onSuccessAdd']);
        onSuccessAdd(data, ctx);
    }

    //CATCH ALL
    else {
        if (typeof loadChild === 'function')
            loadChild();
        else
            reloadPage();
    }
}
function _onSuccessEdit(data, ctx) {
    consolelog('_onSuccessEdit', [ctx]);
    dismissPageEditModal();

    if (!ctx) ctx = '';

    if (ctx.toLowerCase() == '?') {
    } else if (ctx.toLowerCase() == 'property') {
        consolelog('_onSuccessEdit', ['Calling _onSuccessEditProperty']);
        _onSuccessEditProperty(data, ctx);
    } else if (ctx.toLowerCase() == 'address') {
        consolelog('_onSuccessEdit', ['Calling _onSuccessEditAddress']);
        _onSuccessEditAddress(data, ctx);
    } else if (typeof onSuccessEdit === 'function') {
        consolelog('_onSuccessEdit', ['Calling onSuccessEdit', ctx]);
        onSuccessEdit(data, ctx);
    } else {
        if (isCommonContext(ctx)) {
            if (typeof loadParent === 'function')
                loadParent();
            else
                reloadPage();
        }
        else {
            if (typeof loadChild === 'function')
                loadChild();
            else
                reloadPage();   
        }
    }
}
function _onSuccessViewEdit(data, ctx) {
    consolelog('_onSuccessViewEdit', [ctx]);
    dismissPageViewEditModal();

    if (!ctx) ctx = '';

    if (ctx.toLowerCase() == '?') {
    } else if (typeof onSuccessViewEdit === 'function') {
        onSuccessViewEdit(data, ctx);
    } else {
        if (isCommonContext(ctx)) {
            if (typeof loadParent === 'function')
                loadParent();
            else
                reloadPage();
        }
        else
            if (typeof loadChild === 'function') loadChild();
    }
}
function _onErrorAdd(errData, ctx) {
    consolelog('_onErrorAdd', [ctx]);

    if (!ctx) ctx = '';

    let errMsg = getErrorMsg(errData);

    if (ctx.toLowerCase() == 'share') {
        showAlert('Share', errMsg);
    } else if (typeof onErrorAdd === 'function') {
        onErrorAdd(errMsg, ctx);
    } else {
        setPageAddModalError(errMsg);
    }
}
function _onErrorEdit(errData, ctx) {
    consolelog('_onErrorEdit', [ctx]);

    if (!ctx) ctx = '';
    debugger;
    let errMsg = getErrorMsg(errData);

    if (ctx.toLowerCase() == '?') {
    } else if (typeof onErrorEdit === 'function') {
        onErrorEdit(errMsg, ctx);
    } else {
        setPageEditModalError(errMsg);
    }
}
function _onErrorViewEdit(errData, ctx) {
    consolelog('_onErrorViewEdit', [ctx]);

    if (!ctx) ctx = '';

    let errMsg = getErrorMsg(errData);

    if (ctx.toLowerCase() == '?') {
    } else if (typeof onErrorViewEdit === 'function') {
        onErrorViewEdit(errMsg, ctx);
    } else {
        setPageViewEditModalError(errMsg);
    }
}

function getErrorMsg(errData) {
    let errMsg = 'Unexpexted Error';
    if (errData != null && typeof errData === 'object') {
        errMsg += ': ' + errData.ResponseText;
        //errMsg += ': ' + errData.ErrorDetail;
    } else if (hasContent(errData)) {
        errMsg += ': ' + errData;
    }

    return errMsg;
}

function displayAddModalMessage(msg, level) {
    displayModalMessage(msg, 'pageAddModalAlert', level);
}
function displayEditModalMessage(msg, level) {
    displayModalMessage(msg, 'pageEditModalAlert', level);
}
function displayVewEditModalMessage(msg, level) {
    displayModalMessage(msg, 'pageVewEditModalAlert', level);
}
function displayModalMessage(msg, alertId, level) {
    if (!msg || msg.length == 0 || !alertId || alertId.length == 0) return;

    alertId = alertId.startsWith('#') ? alertId : '#' + alertId;
    level = level < 1 ? 1 : level > 3 ? 3 : level;

    var cssClass = level == 1 ? 'alert-info' : level == 2 ? 'alert-warning' : 'alert-danger';
    $(alertId).removeClass('alert-danger').removeClass('alert-warning')
        .removeClass('alert-info').addClass(cssClass);

    $(alertId).append(msg + '<br/>').show();
}

function _formSave(formId, validationErrorsContainerId, formSaveContext) {
    consolelog('_formSave', [formId, validationErrorsContainerId, formSaveContext]);

    if (validateFrm(null, formId, validationErrorsContainerId)) {
        if (typeof formSave === 'function') formSave(formSaveContext);
    } else {
        consolelog('_formSave', ['invalid']);
    }
}

function initTextSelect() {
    $("input").on("click", function () {
        $(this).select();
    });
}
function initDatePicker() {
    $('input[type="date"]').on("click", function (evt) {
        //this.showPicker();
    });
}

function applyMultiselects() {
    consolelog('applyMultiselects');
    $('.select2').each(function () {
        $(this).select2({
            width: '100%'
        });
    })
}
function applyMultiselect(id, selectedData) {
    consolelog('applyMultiselect: ' + id + ', ' + selectedData);
    var listId = '#' + id;

    $(listId).select2({
        width: '100%'
    });

    if (selectedData) {
        setMultiselectData(listId, selectedData.split(','));
    }
}
function setMultiselectData(id, data) {
    $(id).val(data);
    $(id).trigger('change');
}

function onConfirmOk(context) {
    consolelog('onConfirmOk: ' + context);
    if (context == 'logout') {
        navigateToPage('/App/Logout');
    }
}

function enableInput(inputId, value, hdnField) {
    $('#' + inputId).prop('disabled', false);
    if (value) $('#' + inputId).val(value);
    if (hdnField) $('#' + hdnField).val(1);
}
function disableInput(inputId, value) {
    $('#'+inputId).prop('disabled', true);
    if (value) $('#' + inputId).val(value);
}
function enableDisableInput(inputId, enabled) {
    const id = toProperId(inputId, false).value;
    consolelog('enableDisableInput', [id, enabled]);
    $(id).prop('disabled', !enabled);
}

function isInputChecked(inputId) {
    const id = toProperId(inputId, false).value;
    return $(id).is(':checked');
}
function setInputChecked(inputId, checked) {
    const id = toProperId(inputId, false).value;
    return $(id).prop('checked', checked);
}

function setInputDateType(inputId, isDateOnly) {
    var inputType = isDateOnly ? 'date' : 'datetime-local';
    var currentVal = $('#' + inputId).val();
    $('#' + inputId).attr("type", inputType);

    $('#' + inputId).val(convertDateTime(isDateOnly, currentVal));
}
function convertDateTime(isDateOnly, value) {
    if (isDateOnly && value.indexOf('T') > 0) {
        consolelog('convertDateTime: removing time from ' + value);
        return value.substring(0, value.indexOf('T'));
    }

    if (!isDateOnly && value.indexOf('T') <= 0) {
        consolelog('convertDateTime: adding time to ' + value);
        return value+'T00:01';
    }

    return value;
}

function populateFramesDropdown(value, id) {
    if (!id || id.length == 0) return;
    var dropdown = $('#' + id);
    if (dropdown == undefined) return;

    dropdown.html('');

    for(var i = 0; i <= value; i++) {
        dropdown.append($("<option />").val(i).text(i));
    };

    dropdown.prop('disabled', value == 0);
}

function restrictFutureDates(selector) {
    const properId = toProperId(selector, false);
    if (!properId.exists) return;

    var today = new Date().toISOString().split('T')[0]; // Get today's date in YYYY-MM-DD format
    $(properId.value).attr('max', today);
}

function selectFirstOptionIfValueMissing(id, value) {
    let $select = $("#" + id);
    if ($select.find("option[value='" + value + "']").length == 0) {
        $select.val($select.find("option:first").val());
        return true;
    }

    return false;
}

function setDropdownValue(dropdownId, value) {
    var dropdown = $('#' + dropdownId);

    // Check if the value exists
    if (dropdown.find("option[value='" + value + "']").length === 0) {
        // If it doesn't exist, select the first option
        dropdown.val(dropdown.find("option:first").val());
    } else {
        // If it exists, set the value
        dropdown.val(value);
    }
}



let loadingGif = '<img style="margin:20px;" src="/images/loading.gif" width="40px" height="40px" /> Loading...';

function ajaxPostJsonAddData(url, jsonData, ctx, successCallback, errorCallback, alertElement) {
    consolelog('ajaxPostJsonAddData', [url, ctx]);
    var localSuccessCallback = _onSuccessAdd;
    var localErrorCallback = _onErrorAdd;
    if (!alertElement) alertElement = 'pageAddModalAlert';
    if (successCallback) localSuccessCallback = successCallback;
    if (errorCallback) localErrorCallback = errorCallback;
    ajaxPostJsonData(url, jsonData, localSuccessCallback, localErrorCallback, ctx, 'pageAddModalAlert');
}
function ajaxPostJsonEditData(url, jsonData, ctx, successCallback, errorCallback, alertElement) {
    consolelog('ajaxPostJsonEditData', [url, ctx]);
    var localSuccessCallback = _onSuccessEdit;
    var localErrorCallback = _onErrorEdit;
    if (!alertElement) alertElement = 'pageEditModalAlert';
    if (successCallback) localSuccessCallback = successCallback;
    if (errorCallback) localErrorCallback = errorCallback;
    ajaxPostJsonData(url, jsonData, localSuccessCallback, localErrorCallback, ctx, alertElement);
}
function ajaxPostJsonViewEditData(url, jsonData, ctx, successCallback, errorCallback, alertElement) {
    consolelog('ajaxPostJsonViewEditData', [url, ctx]);
    var localSuccessCallback = _onSuccessViewEdit;
    var localErrorCallback = _onErrorViewEdit;
    if (!alertElement) alertElement = 'pageViewEditModalAlert';
    if (successCallback) localSuccessCallback = successCallback;
    if (errorCallback) localErrorCallback = errorCallback;
    ajaxPostJsonData(url, jsonData, localSuccessCallback, localErrorCallback, ctx, 'pageViewEditModalAlert');
}
function ajaxPostJsonData(url, jsonData, onSuccessCallback, onErrorCallback, ctx, alertElement) {
    consolelog('ajaxPostJsonData', [url, ctx]);
    $.ajax({
        url: encodeURI(url),
        type: 'POST',
        data: JSON.stringify(jsonData),
        contentType: 'application/json; charset=utf-8',
        success: function (data) {
            if (data.Success) {
                if (hasContent(data.RedirectUrl)) {
                    navigateToPage(data.RedirectUrl);
                } else if (typeof onSuccessCallback === 'function') {
                    onSuccessCallback(data, ctx);
                }
            } else {
                consolelog(data.ResponseText);
                displayErrors(data, alertElement);
                if (typeof onErrorCallback === 'function')
                    onErrorCallback(data, ctx);
            }
        },
        error: function (xhr, status, error) {
            showAlert('Contor Error', xhr.responseText);
        }
    });
}

function ajaxPostFormAddData(url, fileData, ctx) {
    consolelog('ajaxPostFormData', [url, ctx]);
    ajaxPostFormData(url, fileData, _onSuccessAdd, _onErrorAdd, ctx, 'pageAddModalAlert');
}
function ajaxPostFormData(url, fileData, onSuccessCallback, onErrorCallback, ctx, alertElement) {
    consolelog('ajaxPostFormData', [url, ctx]);
    $.ajax({
        url: encodeURI(url),
        type: 'POST',
        contentType: false,
        processData: false,
        data: fileData,
        success: function (data) {
            if (data.Success) {
                if (hasContent(data.RedirectUrl)) {
                    navigateToPage(data.RedirectUrl);
                } else if (typeof onSuccessCallback === 'function') {
                    onSuccessCallback(data, ctx);
                }
            } else {
                consolelog(data.ResponseText);
                displayErrors(data, alertElement);
                if (typeof onErrorCallback === 'function')
                    onErrorCallback(data);
            }
        },
        error: function (xhr, status, error) {
            showAlert('Contor Error', xhr.responseText);
        }
    });
}

function loadUrl(divId, url, callBack) {
    const properId = toProperId(divId, false);
    if (!properId.exists || !hasContent(url)) return;

    url = url.replace('&amp;', '&');
    consolelog('loadUrl', [divId, url]);

    var div = $(properId.value);

    loadDiv(div, url, callBack);
}
function loadDiv(div, url, callBack) {
    if (!div || div.length == 0) return;

    consolelog('loadDiv', url);
    div.html(loadingGif);

    setTimeout(function () {
        div.load(encodeURI(url), function (response, status, xhr) {
            if (status == "error") {
                throw new Error(`Failed to load content: ${url} ${xhr.status} ${xhr.statusText}`);
            } else {
                $('.formHelp').hide();
                if (typeof callBack === 'function') callBack();
            }
        });
    }, 0); // Schedule on next tick
}
function loadPostUrl(divId, url, requestData) {
    if (!divId || divId.length == 0) return;

    url = url.replace('&amp;', '&');
    consolelog('loadPostUrl', [url]);

    divId = divId.startsWith('#') ? divId : '#' + divId;
    $(divId).html(loadingGif);
    var jsonData = JSON.stringify(requestData);
    $.ajax({
        url: encodeURI(url),
        type: 'POST',
        async: false,
        data: jsonData,
        contentType: 'application/json; charset=utf-8',
        success: function (data) {
            $(divId).html(data);
        },
        error: function (err) {
            showAlert('', err.statusText);
        }
    });
}
function loadFormPostUrl(divId, url, requestData) {
    if (!divId || divId.length == 0) return;

    url = url.replace('&amp;', '&');
    consolelog('loadPostUrl', [url]);

    divId = divId.startsWith('#') ? divId : '#' + divId;
    $(divId).html(loadingGif);

    $.ajax({
        url: encodeURI(url),
        type: 'POST',
        data: requestData,
        contentType: false,
        processData: false,
        success: function (data) {
            $(divId).html(data);
        },
        error: function (xhr, status, error) {
            showAlert('Contor Error', xhr.responseText);
        }
    });
}

function getData(url, requestData, forcePost) {
    consolelog('getData: ' + url);
    debugger;
    let returnData;
    _showLoading();

    if (requestData || forcePost) {
        var jsonData = JSON.stringify(requestData);
        $.ajax({
            url: encodeURI(url),
            type: 'POST',
            async: false,
            data: jsonData,
            contentType: 'application/json; charset=utf-8',
            success: function (data) {
                _hideLoading();
                if (data.Success) {
                    returnData = data.Data;
                } else {
                    consolelog(data.ResponseText);
                }
            },
            error: function (err) {
                _hideLoading();
                alert(err.statusText);
            }
        });
    } else {
        $.ajax({
            url: encodeURI(url),
            type: 'GET',
            async: false,
            contentType: 'application/json; charset=utf-8',
            success: function (data) {
                _hideLoading();

                if (data.Success) {
                    returnData = data.Data;
                } else {
                    consolelog(data.ResponseText);
                }
            },
            error: function (err) {
                _hideLoading();
                alert(err.statusText);
            }
        });
    }

    consolelog(returnData);
    return returnData;
}

function initDropdown(dropdownId) {
    const properId = toProperId(dropdownId, false);
    if (!properId.exists) return;

    const required = isRequired(properId.value);
    const value = required ? '' : '';
    const text = required ? '-Required-' : '-Optional-';
    $(properId.value).html('').append($("<option />").val(value).text(text));
}
function populateDropdown(url, dropdownId, selectedValue) {
    if (!dropdownId || dropdownId.length == 0) return;

    url = url.replace('&amp;', '&');
    consolelog('populateDropdown', [url, dropdownId, selectedValue]);

    dropdownId = dropdownId.startsWith('#') ? dropdownId : '#' + dropdownId;
    var options = $(dropdownId);

    $.ajax({
        url: encodeURI(url),
        type: 'GET',
        async: false,
        success: function (data) {
            if (data.Success) {
                options.html('');
                $.each(data.Data, function (index, item) {
                    options.append($("<option />").val(item.Value).text(item.Text));
                });

                if (toInt(selectedValue) > 0 || hasContent(selectedValue))
                    $(dropdownId).val(selectedValue);
                else
                    options.prop('selectedIndex', 0);

            } else {
                showAlert('', data.ResponseText);
            }
        },
        error: function (err) {
            showAlert('', err.statusText);
        }
    });
}

function displayErrors(data, alertElement) {
    consolelog('displayErrors');

    if (!data || !alertElement) return;
    $('#' + alertElement).hide();
    $('#modalOverrideValidation').hide();
    $('#overrideValidation').prop('checked', false);

    var displayMessage = '';
    if (data.Severity == 1) {
        for (var i = 0; i < data.ValidationErrors.length; i++) {
            displayMessage += data.ValidationErrors[i].Message + '<br/>';
        }
        $('#' + alertElement).removeClass('alert-danger').addClass('alert-warning');
        if (data.ValidationErrors.length > 0) $('#modalOverrideValidation').show();
    } else {
        if (data.ErrorDetail && data.ErrorDetail.length > 0 && gDebugMode == true) {
            displayMessage = data.ErrorDetail;
            $('#' + alertElement).removeClass('alert-warning').addClass('alert-danger');
        }
    }
    if (displayMessage && displayMessage.length > 0)
        $('#' + alertElement).html(displayMessage).show();
}


let clientSideValidationEnable = true;
let validationLogging = true;
let showDebugOnError = true;

function validateAddModalFrm(errContainer) {
	var success = validateModalFrm('pageAddModalContent', _onErrorAdd, errContainer);
	return success;
}
function validateEditModalFrm(errContainer) {
	var success = validateModalFrm('pageEditModalContent', _onErrorEdit, errContainer);
	return success;
}
function validateViewEditModalFrm(errContainer) {
	var success = validateModalFrm('pageViewEditModalContent', _onErrorViewEdit, errContainer);
	return success;
}
function validateModalFrm(frmId, fnError, errContainer) {
	var success = validateFrm(null, frmId, errContainer, true);
	if (!success && fnError)
		fnError('Validation Failed. Please enter all details as indicated.')

	return success;
}

function validateAddFrm(frmId, highlightErrors) {
	return validateFrm(null, frmId, 'pageAddModalMessage', highlightErrors);
}
function validateEditFrm(frmId, highlightErrors) {
	return validateFrm(null, frmId, 'pageEditModalMessage', highlightErrors);
}
function validateViewEditFrm(frmId, highlightErrors) {
	return validateFrm(null, frmId, 'pageViewEditModalMessage', highlightErrors);
}
function validateFrm(evt, frmId, errContainer, highlightErrors, clearServerSide) {
	//Make sure the frm exists
	if (!toProperId(frmId).exists) return false;
	frmId = gProperId;

	consolelog('Validating...', [frmId]);

    //Check if client side validation is enabled
	if (!clientSideValidationEnable) {
		consolelog('Validation Complete...', [frmId, 'Client Side Validation Disabled']);
		return true;
	} 

	//Default to valid
	let valid = true;

	if (clearServerSide && clearServerSide == true)
		$('#serverSideValidationErrorsId').html('');

	if (toProperId(errContainer).exists)
		$(gProperId).html('');

    //Validate all inputs, selects, and textareas in the form
	$(frmId).find('input, select, textarea').each(function () {
		valid = validateFld(this, errContainer, highlightErrors) && valid;
	});

	//Call additional validation that might exist on the page
	if (typeof pageValidation === 'function') {
		valid = pageValidation() && valid;
	}

	if (!valid) {
		if (evt) evt.preventDefault();
		consolelog('Validation Complete ', [frmId, '**invalid**']);
		return false;
	}

    //REMOVE DISABLED ATTRIBUTES FROM INPUTS SO THEY WILL BE SUBMITTED
	if (evt) {
		$(frmId).find('input, select, textarea').each(function () {
			if ($(this).prop('disabled')) {
				$(this).prop('disabled', false); // Remove disabled attribute
			}
		});
	}

	consolelog('Validation Complete ', [frmId, '!!valid!!']);
	return valid;
}

function validateAddFld(fld, highlightErrors) {
	return validateFld(fld, 'pageAddModalMessage', highlightErrors);
}
function validateEditFld(fld, highlightErrors) {
	return validateFld(fld, 'pageEditModalMessage', highlightErrors);
}
function validateViewEditFld(fld, highlightErrors) {
	return validateFld(fld, 'pageViewEditModalMessage', highlightErrors);
}
function validateFld(fld, errContainer, highlightErrors) {
	if (!fld) return true;

	if (!toProperId(fld.id).exists) {
		validationLog('.Does not exist: ' + gProperId);
		return true;
	}

	const fldId = gProperId;

	if (fldId.startsWith("multiselect_")) {
		validationLog('.Ignoring multiselect: ' + fldId);
		return true;
	}

	validationLog('.Validating Field: ' + fldId);

	const altId = toProperId($(fldId).attr('data-validation-alt-id')).value;

	clearInvalid(fldId, altId);

	let ignoreSuccess = false;
	let toProperIgnoreId = toProperId($(fldId).attr('data-validation-ignoreif'));

	let ignoreIfId = '';
	if (toProperIgnoreId.exists) {
		ignoreIfId = toProperIgnoreId.value;
		const ignoreIfValue = $(ignoreIfId).val();
		const ignoreIfType = $(ignoreIfId).attr('type');
		if (ignoreIfType == 'number' && ignoreIfValue && ignoreIfValue > 0) ignoreSuccess = true;
		if (ignoreIfType == 'text' && ignoreIfValue && ignoreIfValue.length > 0) ignoreSuccess = true;

		if (ignoreSuccess) {
			validationLog('...ignoring because ' + ignoreIfId + ' is set')
			return true;
		}
	}
	
	const ignoreHidden = $(fldId).attr('data-ignore-hidden');
	if (ignoreHidden == 'true' && $(fldId).is(":hidden")) {
		validationLog('...ignoring because ' + fldId + ' is hidden')
		return true;
	}

	const value = $(fldId).val();
	const required = isRequired(fldId);
	validationLog('...required: ' + required + ', value: ' + value);

	if (required && (!value || value == '' || value == '0')) {
		setInvalid(fldId, 'Required', altId, errContainer, highlightErrors, ignoreIfId);
		return false;
	}

	const minLength = $(fldId).attr('data-validation-min-length');
	if (minLength && !isNaN(minLength) && value.length < minLength) {
		setInvalid(fldId, 'This field requires at least ' + minLength + ' characters', altId, errContainer, highlightErrors);
		return false;
	}

	const maxLength = $(fldId).attr('data-validation-max-length');
	if (maxLength && !isNaN(maxLength) && value.length > maxLength) {
		setInvalid(fldId, 'This field is limited to ' + maxLength + ' characters', altId, errContainer, highlightErrors);
		return false;
	}

	const match = $(fld).attr('data-validation-match');
    const matchProperId = toProperId(match);
	if (matchProperId.exists) {
        const matchId = matchProperId.value;
		const matchValue = $(matchId).val();
		if (matchValue != value) {
			const matchName = $(matchId).attr('data-validation-name')
			setInvalid(fldId, 'This field does not match the field ' + matchName, altId, errContainer, highlightErrors);
			return false;
		}
	}

	const minValue = $(fldId).attr('data-validation-min-value');
	if (minValue && !isNaN(minValue) && (isNaN(value) || value < minValue)) {
		setInvalid(fldId, 'This field must have a value of at least ' + minValue, altId, errContainer, highlightErrors);
		return false;
	}

	return true;
}

function clearInvalid(fldId, altId) {
	if (!fldId && !altId) return;

	const id = toInt(altId) > 0 ? altId : fldId;

	validationLog('...clearing invalid: ' + id);

	if (!toProperId(id).exists) return;
	const cleanId = id.replace('#', '');

	$("label[for='" + cleanId + "']").removeClass('text-danger').removeClass('text-warning');
	$("h2[for='" + cleanId + "']").removeClass('text-danger').removeClass('text-warning');
	$("span[for='" + cleanId + "']").removeClass('text-danger').removeClass('text-warning');

	$(id).removeClass('invalid').removeClass('invalidwarning');
	if (toProperId(id + 'Invalid').exists) {
		$(id + 'Invalid').html('').removeClass('invalid').removeClass('invalidwarning');
	}
}

function setInvalid(fldId, msg, altId, errContainer, highlightErrors, ignoreIfId) {
	const properFldId = toProperId(fldId, false);
	const properAltFldId = toProperId(altId, false);
	let actualFldId = '';
	let colourClass = 'text-danger';
	let invalidCss = 'invalid';
	let name = '';

	if (properFldId.exists || properAltFldId.exists) {
		actualFldId = properFldId.value;
		if (properAltFldId.exists) actualFldId = properAltFldId.value;
		validationLog('...setting fld invalid: ' + actualFldId);

		const cleanId = actualFldId.replace('#', '');
		const ignoring = toProperId(ignoreIfId).exists;
		colourClass = ignoring ? 'text-warning' : colourClass;
		invalidCss = ignoring ? 'invalidwarning' : invalidCss;
		name = $(actualFldId).attr('data-validation-name');

		$("label[for='" + cleanId + "']").addClass(colourClass);
		$("h2[for='" + cleanId + "']").addClass(colourClass);
		$("span[for='" + cleanId + "']").addClass(colourClass);

		if (highlightErrors) $(actualFldId).addClass(invalidCss);
		if (toProperId(actualFldId + 'Invalid').exists) $(gProperId).html(msg).addClass(invalidCss);
	}

	const toProperErrContainer = toProperId(errContainer, false);
	if (!toProperErrContainer.exists) return; 

	let html = '<div style="cursor:pointer;" class="' + colourClass + '"';
	if (hasContent(actualFldId)) html += ' onclick="$(\'' + actualFldId + '\').focus();"'
	html += hasContent(name) ? '><b>' + name + '</b>: ' + msg + '</div>' : '><b>Error</b>: ' + msg + '</div>';

	$(toProperErrContainer.value).append(html);
}

function setRequired(fldId, required) {
	if (!toProperId(fldId).exists) return;
	consolelog('setRequired', [gProperId, required]);
	$(gProperId).attr('data-validation-required', required);
}

function validationLog(msg, values) {
	if (validationLogging == true)
		consolelog(msg, values);
}

function addValidationError(fld, msg, errContainer) {
	if (!hasContent(errContainer)) errContainer = 'clientSideValidationErrors';
	setInvalid(fld, msg, null, errContainer);
}

function isRequired(id) {
	const properId = toProperId(id, false);
	if (!properId.exists) return;

	const attr = $(properId.value).attr('data-validation-required');
	return attr && attr == 'true';
}
