
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
// Skins functions
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//


var sBrandCssVars = '';   // overwritten on page load by Razor-emitted inline script

var SKINS = [
    { id: 'st-default',       label: 'Default'       },
    { id: 'st-blue',          label: 'Blue'           },
    { id: 'st-dark',          label: 'Dark'           },
    { id: 'st-green',         label: 'Green'          },
    { id: 'st-high-contrast', label: 'High Contrast'  },
    { id: 'st-compact',       label: 'Compact'        },
    { id: 'st-countryroads',    label: 'Country Roads'    },
    { id: 'st-atomicfireballs', label: 'Atomic Fireballs'  },
    { id: 'st-cobaltbold',      label: 'Cobalt Bold'       },
    { id: 'st-sunkist',         label: 'Sun Kist'          },
    { id: 'st-thunderstorm',    label: 'Thunderstorm'      },
];


function GetBuiltInSkinNames() {
    return SKINS.map(function (s) { return s.id; }).join(',');
}


function GetSkinFromCookie() {
    var sSkin = localStorage.getItem('ST-Skin');
    if (!sSkin)
        sSkin = getCookie('st-skin');
    return sSkin || 'st-default';
}


function SetSkinToCookie(sSkinName) {
    localStorage.setItem('ST-Skin', sSkinName);
    setCookie('st-skin', sSkinName, 365);
}


/**
 * Injects or replaces <style id="st-brand-style"> with the brand CSS variable block from VarinfoSet.CssVars.
 * Inserted before #st-skin-link so user skin choices (layers 3-4) still override brand colors.
 * Called once on page load when the brand block was not server-rendered (rare); not user-accessible.
 */
function ApplyBrandCssVars(sCssVars) {
    var style = document.getElementById('st-brand-style');
    if (!style) {
        style = document.createElement('style');
        style.id = 'st-brand-style';
        var oSkinLink = document.getElementById('st-skin-link');
        if (oSkinLink)
            document.head.insertBefore(style, oSkinLink);
        else
            document.head.appendChild(style);
    }
    style.textContent = sCssVars || '';
}


/**
 * Applies a skin from a raw CSS variable block (e.g. DB-stored CssVars string). Injects or replaces a <style id="st-skin-style"> appended after all other stylesheets so it wins on cascade order.
 * */
function ApplySkinFromCss(sCssVars) {
    // Reuse the existing style element if present; creating a new one each call would leave orphaned
    // blocks in <head> and the last one would win unpredictably depending on insertion order.
    var style = document.getElementById('st-skin-style');
    if (!style) {
        // First call: create the element and append it after all other stylesheets so its :root
        // variable overrides win on cascade order without needing !important.
        style = document.createElement('style');
        style.id = 'st-skin-style';
        document.head.appendChild(style);
    }

    // Replace the entire contents with the new CSS variable block (a full :root { --st-*: ...; } string).
    // Assigning textContent is a single DOM mutation — the browser recalculates all custom properties at once.
    style.textContent = sCssVars;
}


/**
 * Removes any active skin: resets #st-skin-link to st-default, clears the inline #st-skin-style block, restores the default IgniteUI theme, and clears the persisted cookie/localStorage.
 * */
function RemoveSkin() {
    // Point #st-skin-link back to st-default.css, which is a comment-only no-op file, so all CSS custom
    // properties revert to the default values declared in standardtime-skin-variables.css.
    var link = document.getElementById('st-skin-link');
    if (link)
        link.href = '/Content/skins/st-default.css?v=' + Date.now();

    // Revert to the brand baseline (or bare defaults if no brand is configured). Restoring sBrandCssVars
    // here rather than clearing to '' means Remove Skin shows brand colors, not generic defaults.
    var style = document.getElementById('st-skin-style');
    if (style)
        style.textContent = sBrandCssVars || '';

    // Remove the persisted choice so GetSkinFromCookie() returns 'st-default' on next load,
    // and the server-side Razor cookie read in _HeadScripts.cshtml also emits st-default.
    localStorage.removeItem('ST-Skin');
    deleteCookie('st-skin');

    // Restore the default IgniteUI CDN theme; dark/high-contrast skins swap this to metro,
    // so it must be explicitly reset or grid/chart chrome stays dark after removal.
    var igLink = document.querySelector('link[href*="infragistics.theme.css"]');
    if (igLink)
        igLink.href = 'https://cdn-na.infragistics.com/igniteui/2021.2/latest/css/themes/infragistics/infragistics.theme.css';
}


/**
 * Applies a built-in file-based skin by swapping #st-skin-link, persists the choice to localStorage and cookie, and swaps the IgniteUI CDN theme for dark/high-contrast skins.
 * */
function ApplySkin(sSkinName) {
    // Swap the skin stylesheet; cache-bust with Date.now() so the browser doesn't serve the previous skin file.
    var link = document.getElementById('st-skin-link');
    if (link)
        link.href = '/Content/skins/' + sSkinName + '.css?v=' + Date.now();

    // Persist the choice so it survives page reload.
    SetSkinToCookie(sSkinName);

    // Swap the IgniteUI CDN theme: dark/high-contrast skins need the metro theme; all others use the default infragistics theme.
    var igLink = document.querySelector('link[href*="infragistics.theme.css"]');
    if (igLink) {
        var bDark = sSkinName === 'st-dark' || sSkinName === 'st-high-contrast' || sSkinName === 'st-thunderstorm';
        igLink.href = bDark
            ? 'https://cdn-na.infragistics.com/igniteui/2021.2/latest/css/themes/metro/infragistics.theme.css'
            : 'https://cdn-na.infragistics.com/igniteui/2021.2/latest/css/themes/infragistics/infragistics.theme.css';
    }

    // Propagate to open AI chat popup windows so their skin link is swapped immediately.
    if (typeof AiChatWindows !== 'undefined') {
        Object.keys(AiChatWindows).forEach(function (sSessionId) {
            var entry = AiChatWindows[sSessionId];
            if (entry && entry.win && !entry.win.closed && entry.win.ApplySkin)
                entry.win.ApplySkin(sSkinName);
        });
    }
}

// Representative [ribbonBg, bodyBg, accent] colors for each built-in skin; used by BuildSkinSwatchItem to render three-band previews.
var SWATCH_COLORS = {
    'st-default':       ['whitesmoke',  'whitesmoke', '#6366f1'],
    'st-blue':          ['#e7f1ff',     'whitesmoke',  '#0d6efd'],
    'st-dark':          ['#2a2a3e',     '#1e1e2e',     '#89b4fa'],
    'st-green':         ['#e8f5e9',     'whitesmoke',  '#198754'],
    'st-high-contrast': ['#000000',     '#000000',     '#ffff00'],
    'st-compact':       ['whitesmoke',  'whitesmoke',  '#6366f1'],
    'st-countryroads':    ['#f5e6da',  '#fdf6f0', '#a0522d'],
    'st-atomicfireballs': ['#fde8e0',  '#fff5f0', '#c41e3a'],
    'st-cobaltbold':      ['#d6e4ff',  '#f0f4ff', '#0047ab'],
    'st-sunkist':         ['#feecd6',  '#fffbf5', '#e8650a'],
    'st-thunderstorm':    ['#16213e',  '#1a1a2e', '#1e90ff'],
};


/**
 * Opens a floating skin-picker panel anchored below the clicked ribbon button (oEvent.target).
 * Clicking the button again, or clicking outside the panel, closes it.
 * Call as onclick="ChooseAndApplySkin(event)" so oEvent.target resolves to the button element.
 */
function ChooseAndApplySkin(oEvent) {
    // Toggle: if the picker is already open, close it and stop.
    var oExisting = document.getElementById('st-skin-picker');
    if (oExisting) { CloseSkinPicker(); return; }

    var sCurrentSkin = GetSkinFromCookie();

    // Build the floating panel (fixed-position, CSS grid so all swatches align in uniform columns).
    var oPicker = document.createElement('div');
    oPicker.id = 'st-skin-picker';
    oPicker.style.cssText = 'position:fixed;z-index:99999;background:#fff;border:1px solid #ccc;border-radius:6px;padding:12px;box-shadow:0 4px 16px rgba(0,0,0,0.18);display:grid;grid-template-columns:repeat(4,1fr);gap:10px;width:380px;';

    // Anchor below the clicked button; clamp to the right edge so the panel stays on screen.
    var oRect = (oEvent && oEvent.target) ? oEvent.target.getBoundingClientRect() : { left: 100, bottom: 60 };
    oPicker.style.left = Math.min(oRect.left, window.innerWidth - 400) + 'px';
    oPicker.style.top  = (oRect.bottom + 4) + 'px';

    // "Remove Skin" first, then one tile per built-in skin.
    oPicker.appendChild(BuildSkinSwatchItem(null, 'Remove Skin', null, sCurrentSkin));
    SKINS.forEach(function (oSkin) {
        oPicker.appendChild(BuildSkinSwatchItem(oSkin.id, oSkin.label, SWATCH_COLORS[oSkin.id] || SWATCH_COLORS['st-default'], sCurrentSkin));
    });

    document.body.appendChild(oPicker);

    // Register the click-outside handler in a setTimeout so this same click doesn't immediately close the panel.
    setTimeout(function () {
        document.addEventListener('click', OnSkinPickerClickOutside);
    }, 0);
}


/**
 * Builds one swatch tile for the skin picker.
 * sSkinId: skin id (e.g. 'st-dark'), or null for the "Remove Skin" entry.
 * aColors: [ribbonBg, bodyBg, accent] drawn as three horizontal bands; null renders a striped ✕ tile instead.
 * sCurrentSkin: the active skin id from GetSkinFromCookie(); highlights the matching tile with an accent border.
 */
function BuildSkinSwatchItem(sSkinId, sLabel, aColors, sCurrentSkin) {
    var bActive = sSkinId !== null && sSkinId === sCurrentSkin;

    // Outer tile: column flex so the swatch sits above the label; accent border when this skin is active.
    var oItem = document.createElement('div');
    oItem.style.cssText = 'display:flex;flex-direction:column;align-items:center;cursor:pointer;border-radius:4px;padding:4px;border:2px solid ' + (bActive ? '#6366f1' : 'transparent') + ';';

    // Swatch box: fixed size, clips the color bands (or the ✕ overlay) at rounded corners.
    var oSwatch = document.createElement('div');
    oSwatch.style.cssText = 'width:60px;height:42px;border-radius:4px;overflow:hidden;border:1px solid #bbb;';

    if (aColors) {
        // Three equal horizontal bands: ribbon bg / body bg / accent.
        aColors.forEach(function (sColor) {
            var oBand = document.createElement('div');
            oBand.style.cssText = 'height:33.34%;background:' + sColor + ';';
            oSwatch.appendChild(oBand);
        });
    } else {
        // "Remove Skin" tile: diagonal stripe pattern with a centered ✕.
        oSwatch.style.background = 'repeating-linear-gradient(45deg,#f0f0f0,#f0f0f0 4px,#d0d0d0 4px,#d0d0d0 8px)';
        var oX = document.createElement('div');
        oX.style.cssText = 'display:flex;align-items:center;justify-content:center;height:100%;font-size:18px;color:#888;font-weight:bold;';
        oX.textContent = '✕';
        oSwatch.appendChild(oX);
    }

    // Label beneath the swatch.
    var oLabel = document.createElement('div');
    oLabel.style.cssText = 'font-size:10px;margin-top:4px;text-align:center;color:#333;white-space:nowrap;';
    oLabel.textContent = sLabel;

    oItem.appendChild(oSwatch);
    oItem.appendChild(oLabel);

    // Hover highlight — skip on the already-active tile so the accent border stays visible.
    oItem.addEventListener('mouseenter', function () { if (!bActive) oItem.style.borderColor = '#aaa'; });
    oItem.addEventListener('mouseleave', function () { oItem.style.borderColor = bActive ? '#6366f1' : 'transparent'; });

    // On click: close the picker, then remove or apply the chosen skin.
    oItem.addEventListener('click', function (e) {
        e.stopPropagation();
        CloseSkinPicker();
        if (sSkinId === null) RemoveSkin(); else ApplySkin(sSkinId);
    });

    return oItem;
}


// Removes the picker panel and detaches the click-outside listener.
function CloseSkinPicker() {
    var oPicker = document.getElementById('st-skin-picker');
    if (oPicker) oPicker.remove();
    document.removeEventListener('click', OnSkinPickerClickOutside);
}


// Document-level click handler registered while the picker is open; closes the picker on any outside click.
function OnSkinPickerClickOutside(e) {
    var oPicker = document.getElementById('st-skin-picker');
    if (oPicker && !oPicker.contains(e.target))
        CloseSkinPicker();
}
