<%+cbi/valueheader%>
<style type="text/css">
*{margin: 0;padding: 0;}

ul{
	list-style: none;
}

#tab{
	width: 100%;
	height: 100%;
	border: 1px solid #ddd;
	box-shadow: 0 0 2px #ddd;
	overflow: hidden;
}

#tab-header {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border-light, #e2e8f0);
    background: var(--bg-gray, #f1f5f9);
    min-width: 0;
    box-shadow: none;
    position: relative;
    z-index: 1;
}

#tab-header ul.cbi-tabmenu {
    display: flex;
    width: 100%;
    background: #f1f5f9;
    border-radius: 8px;
    border-bottom: none !important;
    border: none !important;
    gap: 5px;
    margin: 0;
    padding: 0;
}

#tab-header ul.cbi-tabmenu li {
    flex: 1 1 0;
    min-width: 0;
    width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px 0;
    height: 40px;
    font-size: 15px;
    font-weight: 500;
    color: #64748b;
    background: transparent;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.18s;
    margin: 0;
    user-select: none;
    position: relative;
    box-sizing: border-box;
}

#tab-header ul.cbi-tabmenu li.cbi-tab {
    background: #3b82f6;
    color: #fff;
    font-weight: 600;
    z-index: 2;
    border-radius: 6px;
    box-shadow: 0 1px 2px 0 rgba(0,0,0,0.03);
}

#tab-header ul.cbi-tabmenu li.cbi-tab a {
    color: #fff !important;
    font-weight: 600;
}

#tab-header ul.cbi-tabmenu li.cbi-tab-disabled {
    color: #fff;
    background: #f9f9f9;
    opacity: 0.7;
    cursor: pointer;
}

#tab-header ul.cbi-tabmenu li.cbi-tab-disabled a {
    color: #000 !important;
}

#tab-header ul.cbi-tabmenu li:not(.cbi-tab):hover,
#tab-header ul.cbi-tabmenu li:not(.cbi-tab):focus {
    color: #3b82f6;
    background: rgba(59,130,246,0.10);
}

#tab-header ul.cbi-tabmenu li:not(.cbi-tab):hover a,
#tab-header ul.cbi-tabmenu li:not(.cbi-tab):focus a {
    color: #3b82f6 !important;
}

#tab-header ul.cbi-tabmenu li a {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    text-align: center;
    text-decoration: none;
    background: none;
    border: none;
    outline: none;
    font: inherit;
    color: inherit;
    cursor: inherit;
    padding: 0;
    margin: 0;
    user-select: none;
    transition: color 0.18s;
}

#tab-content .dom{
	display: none;
}

#tab-content .dom ul li{
  float: left;
  margin: 15px 10px;
  width: 225px;
}

.radio-button {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 10px;
    background: #f1f5f9;
    border-radius: 6px;
    padding: 6px 10px;
    margin: 10px auto;
    width: 100%;
    max-width: 500px;
    flex-wrap: wrap;
    box-sizing: border-box;
    box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
}

.radio-button input[type="radio"] {
    display: none;
}
   
.radio-button label {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 6px 18px;
    font-size: 15px;
    color: #64748b;
    background: #fff;
    border: 1px solid #e2e8f0;
    border-radius: 4px;
    cursor: pointer;
    transition: all 0.2s;
    font-weight: 500;
    min-width: 60px;
    user-select: none;
}

.radio-button label:hover {
    color: #3b82f6;
    border-color: #3b82f6;
    background: #f0f6ff;
}

.radio-button input[type="radio"]:checked + label {
    background: #3b82f6;
    color: #fff;
    border-color: #3b82f6;
    box-shadow: 0 1px 2px 0 rgba(59,130,246,0.08);
}

.btn-group {
    display: flex;
    justify-content: space-between;
    width: 80%;
    margin: 10px auto;
}

:root[data-darkmode="true"] #tab-header {
    background: #374151;
    border-bottom: 1px solid #374151;
}

:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu {
    background: #374151;
}

:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li {
    background: #1f2937;
    color: #a1a1aa;
    border-color: #374151;
}

:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li.cbi-tab {
    background: #2563eb;
    color: #fff;
}

:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li.cbi-tab a {
    color: #fff !important;
}

:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li.cbi-tab-disabled {
    color: #1f2937;
    background: #1f2937;
    opacity: 0.7;
}

:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li.cbi-tab-disabled a {
    color: #fff !important;
}

:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li:not(.cbi-tab):hover,
:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li:not(.cbi-tab):focus {
    color: #3b82f6;
    border-color: #3b82f6;
    background: #22304a;
}

:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li:not(.cbi-tab):hover a,
:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li:not(.cbi-tab):focus a {
    color: #60a5fa !important;
}

:root[data-darkmode="true"] {
  .radio-button {
    background: #374151;
    box-shadow: 0 1px 2px 0 rgba(0,0,0,0.15);
  }
  .radio-button label {
    background: #1f2937;
    color: #d1d5db;
    border-color: #4b5563;
  }
  .radio-button label:hover {
    color: #3b82f6;
    border-color: #3b82f6;
    background: #22304a;
  }
  .radio-button input[type="radio"]:checked + label {
    background: #3b82f6;
    color: #fff;
    border-color: #3b82f6;
    box-shadow: 0 1px 2px 0 rgba(59,130,246,0.18);
  }
}
</style>

<body>
	<div id="tab" class="cbi-section">
		<div id="tab-header">
			<ul class="cbi-tabmenu">
				<li name="tab-header" class="cbi-tab"><a href="#"><%:OpenClash Log%></a></li>
				<li name="tab-header" class="cbi-tab-disabled"><a href="#"><%:Core Log%></a></li>
			</ul>
		</div>
		<div id="tab-content">
			<div class="dom" style="display: block;">
				<textarea id="cbid.openclash.config.clog" class="cbi-input-textarea" style="width: 100%;display:inline" data-update="change" rows="32" cols="60" readonly="readonly" ></textarea>
			</div>
			<div class="dom">
				<textarea id="core_log" class="cbi-input-textarea" style="width: 100%;display:inline" data-update="change" rows="32" cols="60" readonly="readonly" ></textarea>
				<div class="radio-button">
					<input type="radio" id="info" name="radios" value="info" checked onclick="return switch_log_level(this.value)"/>
					<label for="info">Info</label>
					<input type="radio" id="warning" name="radios" value="warning" onclick="return switch_log_level(this.value)"/>
					<label for="warning">Warning</label>
					<input type="radio" id="error" name="radios" value="error" onclick="return switch_log_level(this.value)"/>
					<label for="error">Error</label>
					<input type="radio" id="debug" name="radios" value="debug" onclick="return switch_log_level(this.value)"/>
					<label for="debug">Debug</label>
					<input type="radio" id="silent" name="radios" value="silent" onclick="return switch_log_level(this.value)"/>
					<label for="silent">Silent</label>
				</div>
			</div>
		</div>
	</div>

<fieldset style="text-align: center; width: 100%" class="cbi-section">
  <div class="btn-group">
    <input type="button" class="btn cbi-button cbi-button-apply" id="stop_refresh_button" value="<%:Stop Refresh%>" onclick=" return stop_refresh() "/>
    <input type="button" class="btn cbi-button cbi-button-apply" id="start_refresh_button" value="<%:Start Refresh%>" onclick=" return start_refresh() "/>
    <input type="button" class="btn cbi-button cbi-button-apply" id="del_log_button" value="<%:Clean%>" onclick=" return del_log() " />
    <input type="button" class="btn cbi-button cbi-button-apply" id="down_log_button" value="<%:Download Log%>" onclick=" return download_log() " />
  </div>
</fieldset>
</body>

<script type="text/javascript">//<![CDATA[
var r;
var s;
var log_len = 0;
var lv = document.getElementById('cbid.openclash.config.clog');
var cl = document.getElementById('core_log');
var animatingOC = false;
var animatingCore = false;

function get_log_level() {
	XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "log_level")%>', null, function(x, status) {
	if (x && x.status == 200 && status.log_level != "") {
		var radio = document.getElementsByName("radios");
		for (i=0; i<radio.length; i++) {
			if (radio[i].value == status.log_level && ! radio[i].checked) {
				radio[i].checked = true;
			}
		}
	}
	});
	s=setTimeout("get_log_level()",5000);
};
	
function switch_log_level(value)
{
	clearTimeout(s);
	XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "switch_log")%>', {log_level: value}, function(x, status) {
		if (x && x.status == 200) {
    	alert(' <%:Log Level%>: ' + value + ' <%:switching succeeded!%>');
    	get_log_level();
		}
		else {
			alert(' <%:Log Level%>: ' + value + ' <%:switching failed!%>');
			get_log_level();
		}
	});
};


function stop_refresh() {
	clearTimeout(r);
	return
};

function start_refresh() {
	clearTimeout(r);
	r=setTimeout("poll_log()",1000*2);
	return
};

function createAndDownloadFile(fileName, content) {
    var aTag = document.createElement('a');
    var blob = new Blob([content]);
    aTag.download = fileName;
    aTag.href = URL.createObjectURL(blob);
    aTag.click();
    URL.revokeObjectURL(blob);
};

function download_log(){
    var dt = new Date();
    var timestamp = dt.getFullYear()+"-"+(dt.getMonth()+1)+"-"+dt.getDate()+"-"+dt.getHours()+"-"+dt.getMinutes()+"-"+dt.getSeconds();
    
    var oc_content = "";
    if (typeof oc_editor !== 'undefined' && oc_editor) {
        oc_content = oc_editor.getValue();
    } else if (lv && lv.value) {
        oc_content = lv.value;
    } else if (lv && lv.innerHTML) {
        oc_content = lv.innerHTML;
    }
    
    var core_content = "";
    if (typeof core_editor !== 'undefined' && core_editor) {
        core_content = core_editor.getValue();
    } else if (cl && cl.value) {
        core_content = cl.value;
    } else if (cl && cl.innerHTML) {
        core_content = cl.innerHTML;
    }
    
    oc_content = oc_content.split('\n').filter(function(line) { 
        return line.indexOf("】订阅的下载链接为【") === -1 && line.indexOf("】Downloading URL【") === -1; 
    }).join('\n');
    
    if (!oc_content.trim() && !core_content.trim()) {
        return;
    }
    
    var downloadContent = "";
    if (oc_content.trim()) {
        downloadContent += "<%:OpenClash Log%>:\n" + oc_content + "\n\n";
    }
    if (core_content.trim()) {
        downloadContent += "<%:Core Log%>:\n" + core_content;
    }
    
    createAndDownloadFile("OpenClash-"+timestamp+".log", downloadContent);
    return;
};

function del_log() {
	XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "del_log")%>',null,function(x, data){
		lv.innerHTML="";
		cl.innerHTML="";
		log_len = 0;
		oc_editor.setValue(lv.value);
		core_editor.setValue(cl.value);
		core_editor.refresh();
		oc_editor.refresh();
	});
	return
};

function p(s) {
	return s < 10 ? '0' + s: s;
};

function line_tolocal(str) {
    var trans_local = new Array();
    var local_count = 0;

    
    str.trim().split('\n').forEach(function(v, i) {
        var regex = /(time=)"([^"]*)"/g;
        var res = regex.exec(v);
        
        try {
            if (res) {
                var dt = new Date(res[2]);
                
                if (!isNaN(dt.getTime())) {
                    if (v.indexOf("level=") != -1) {
                        var log_info = v.substring(res[2].length + 7);
                    } else {
                        var log_info = v.substring(res[2].length + 2);
                    }
                    trans_local[local_count] = dt.getFullYear() + "-" + p(dt.getMonth() + 1) + "-" + p(dt.getDate()) + " " + 
                                          p(dt.getHours()) + ":" + p(dt.getMinutes()) + ":" + p(dt.getSeconds()) + log_info;
                    local_count++;
                } else {
                    trans_local[local_count] = v;
                    local_count++;
                }
            } else {
                try {
                    var dtt = new Date(v.substring(0, 19));
                    
                    if (!isNaN(dtt.getTime()) && v.substring(0, 19).match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)) {
                        trans_local[local_count] = v;
                        local_count++;
                    } else {
                        trans_local[local_count] = v;
                        local_count++;
                    }
                } catch (e) {
                    trans_local[local_count] = v;
                    local_count++;
                }
            }
        } catch (e) {
            trans_local[local_count] = v;
            local_count++;
        }
    });
    
    return trans_local;
};

function smoothlyDisplayLogs(newLines, target, isEditor, currentContent, isActiveTab) {
    var scrollPosition = null;
    var isAtTop = false;
    var cursorPos = null;
    var selectionRange = null;
    
    var isFirstLoad = !currentContent || currentContent.trim() === "";
    
    if (isEditor && target) {
        scrollPosition = target.getScrollInfo();
        isAtTop = (scrollPosition.top < 20);
        
        if (target.hasFocus()) {
            cursorPos = target.getCursor();
            
            if (cursorPos.line === 0) {
                cursorPos = null;
                selectionRange = null;
            } else if (target.somethingSelected()) {
                selectionRange = {
                    from: target.getCursor(true),
                    to: target.getCursor(false)
                };
            } else {
                selectionRange = null;
            }
        } else {
            cursorPos = null;
            selectionRange = null;
        }
    } else if (!isEditor && target) {
        scrollPosition = target.scrollTop;
        isAtTop = (target.scrollTop < 20);
    }
    
    if ((target === oc_editor && animatingOC) || (target === core_editor && animatingCore) || !isActiveTab) {
        var content = "";
        var lines = newLines.slice().reverse();
        for (var i = 0; i < lines.length; i++) {
            content += lines[i] + "\n";
        }
        content = content + (currentContent || "");
        
        var allLines = content.split("\n");
        if (allLines.length > 2000) {
            allLines = allLines.slice(0, 1999);
            allLines.push("...");
            content = allLines.join("\n");
        }
        
        if (isEditor) {
            var addedLines = lines.length;
            target.setValue(content);
            
            if (!isAtTop && scrollPosition) {
                if (cursorPos) {
                    cursorPos.line += addedLines;
                    target.setCursor(cursorPos);
                    
                    target.scrollIntoView({line: cursorPos.line, ch: cursorPos.ch}, 300);
                } else {
                    target.scrollTo(scrollPosition.left, scrollPosition.top);
                }
                
                if (selectionRange) {
                    selectionRange.from.line += addedLines;
                    selectionRange.to.line += addedLines;
                    target.setSelection(selectionRange.from, selectionRange.to);
                    
                    target.scrollIntoView({
                        from: selectionRange.from,
                        to: selectionRange.to
                    }, 300);
                }
            } else if (isAtTop) {
                target.scrollTo(0, 0);
                if (isFirstLoad) {
                    target.setCursor({line: 0, ch: 0});
                }
            }
                        
            target.refresh();
        } else {
            var oldScrollTop = scrollPosition;
            target.innerHTML = content;
            if (!isAtTop && oldScrollTop) {
                target.scrollTop = oldScrollTop;
            }
        }
        return;
    }
    
    if (target === oc_editor || target === lv) {
        animatingOC = true;
    } else {
        animatingCore = true;
    }
    
    var totalLines = newLines.length;
    var batchSize, interval;
    
    if (totalLines <= 10) {
        batchSize = 2;
        interval = 90;
    } else if (totalLines <= 50) {
        batchSize = 10;
        interval = 60;
    } else if (totalLines <= 200) {
        batchSize = 30;
        interval = 35;
    } else if (totalLines <= 500) {
        batchSize = 60;
        interval = 25;
    } else if (totalLines <= 1000) {
        batchSize = 120;
        interval = 15;
    } else if (totalLines <= 1500) {
        batchSize = 180;
        interval = 10;
    } else {
        batchSize = 250;
        interval = 5;
    }
    
    var displayedContent = currentContent || "";
    var logLines = newLines.slice();
    var currentBatchCount = 0;
    var accumulatedContent = "";
    
    function displayNextBatch() {
        if (currentBatchCount >= logLines.length) {
            if (target === oc_editor || target === lv) {
                animatingOC = false;
            } else {
                animatingCore = false;
            }
            
            if (isEditor && !isAtTop && cursorPos) {
                cursorPos.line += logLines.length;
                target.setCursor(cursorPos);
                
                if (selectionRange) {
                    selectionRange.from.line += logLines.length;
                    selectionRange.to.line += logLines.length;
                    target.setSelection(selectionRange.from, selectionRange.to);
                    
                    target.scrollIntoView({
                        from: selectionRange.from,
                        to: selectionRange.to
                    }, 300);
                } else {
                    target.scrollIntoView({line: cursorPos.line, ch: cursorPos.ch}, 300);
                }
            }
            return;
        }
        
        var nextBatchSize = Math.min(batchSize, logLines.length - currentBatchCount);
        
        var batchLines = logLines.slice(currentBatchCount, currentBatchCount + nextBatchSize).reverse();
        currentBatchCount += nextBatchSize;
        
        if (accumulatedContent) {
            accumulatedContent = batchLines.join("\n") + "\n" + accumulatedContent;
        } else {
            accumulatedContent = batchLines.join("\n");
        }
        
        var content = accumulatedContent + (displayedContent ? "\n" + displayedContent : "");
        
        var contentLines = content.split("\n");
        if (contentLines.length > 2000) {
            contentLines = contentLines.slice(0, 1999);
            contentLines.push("...");
            content = contentLines.join("\n");
        }
        
        if (isEditor) {
            var currentScrollInfo = isAtTop ? null : target.getScrollInfo();
            target.setValue(content);
            
            if (!isAtTop && currentScrollInfo) {
                target.scrollTo(currentScrollInfo.left, currentScrollInfo.top);
            }
            target.refresh();
        } else {
            var currentScrollTop = isAtTop ? null : target.scrollTop;
            target.innerHTML = content;
            if (!isAtTop && currentScrollTop !== null) {
                target.scrollTop = currentScrollTop;
            }
        }
        
        if (currentBatchCount < logLines.length) {
            setTimeout(displayNextBatch, interval);
        } else {
            if (target === oc_editor || target === lv) {
                animatingOC = false;
            } else {
                animatingCore = false;
            }
            
            if (isEditor && !isAtTop && cursorPos) {
                cursorPos.line += logLines.length;
                target.setCursor(cursorPos);
                
                if (selectionRange) {
                    selectionRange.from.line += logLines.length;
                    selectionRange.to.line += logLines.length;
                    target.setSelection(selectionRange.from, selectionRange.to);
                    
                    target.scrollIntoView({
                        from: selectionRange.from,
                        to: selectionRange.to
                    }, 300);
                } else {
                    target.scrollIntoView({line: cursorPos.line, ch: cursorPos.ch}, 300);
                }
            }
        }
    }
    
    displayNextBatch();
}

function poll_log(){
    XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "refresh_log")%>', 
        { 
            log_len: log_len
        },
        function(x, status) {
            if (x && x.status == 200) {
                if (status) {
                    if (!status.update) {
                        r = setTimeout("poll_log()", 2000);
                        return;
                    }
                    
                    if (status.len) {
                        log_len = status.len;
                    }
                    
                    var activeTabId = 0;
                    var titles = document.getElementsByName('tab-header');
                    for(var i=0; i<titles.length; i++){
                        if(titles[i].className === 'cbi-tab') {
                            activeTabId = i;
                            break;
                        }
                    }
                    
                    if (status.oc_log && status.oc_log !== "") {
                        var oc_logs = line_tolocal(status.oc_log);
                        
                        if (oc_logs && oc_logs.length > 0) {
                            if (oc_editor) {
                                var currentContent = oc_editor.getValue();
                                smoothlyDisplayLogs(oc_logs, oc_editor, true, currentContent, activeTabId === 0);
                            } else if (lv) {
                                var currentContent = lv.innerHTML;
                                smoothlyDisplayLogs(oc_logs, lv, false, currentContent, activeTabId === 0);
                            }
                        }
                    }
                    
                    if (status.core_log && status.core_log !== "") {
                        var core_logs = line_tolocal(status.core_log);
                        
                        if (core_logs && core_logs.length > 0) {
                            if (core_editor) {
                                var currentCoreContent = core_editor.getValue();
                                smoothlyDisplayLogs(core_logs, core_editor, true, currentCoreContent, activeTabId === 1);
                            } else if (cl) {
                                var currentCoreContent = cl.innerHTML;
                                smoothlyDisplayLogs(core_logs, cl, false, currentCoreContent, activeTabId === 1);
                            }
                        }
                    }
                }
            }
            r = setTimeout("poll_log()", 2000);
        }
    );
};

window.onload = function(){
    var titles = document.getElementsByName('tab-header');
    var divs = document.getElementsByClassName('dom');
    if(titles.length != divs.length) return;
    for(var i=0; i<titles.length; i++){
        var li = titles[i];
        li.id = i;
        function handleTabSwitch(tab) {
            return function(e) {
                if (tab.className === 'cbi-tab') return;
                for(var j=0; j<titles.length; j++){
                    titles[j].className = 'cbi-tab-disabled';
                    divs[j].style.display = 'none';
                }
                tab.className = 'cbi-tab';
                divs[tab.id].style.display = 'block';

                if(tab.id == 0 && typeof oc_editor !== 'undefined') {
                    setTimeout(function(){
                        oc_editor.refresh();
                    }, 10);
                } else if(tab.id == 1 && typeof core_editor !== 'undefined') {
                    setTimeout(function(){
                        core_editor.refresh();
                    }, 10);
                }
            };
        }
        
        li.onclick = handleTabSwitch(li);
        li.ontouchstart = handleTabSwitch(li);
    }
    get_log_level();
    poll_log();
};
//]]>
</script>
<%+cbi/valuefooter%>
