<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Action生命周期可视化 - Struts2请求处理流程</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f7fa; padding: 20px; }
        .container { max-width: 1400px; margin: 0 auto; }
        
        .header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 15px; margin-bottom: 30px; text-align: center; }
        .header h1 { font-size: 2em; margin-bottom: 10px; }
        
        .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(500px, 1fr)); gap: 20px; margin-bottom: 30px; }
        
        .card { background: white; border-radius: 12px; padding: 25px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); }
        .card h3 { color: #333; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
        
        /* 生命周期流程 */
        .lifecycle-flow { display: flex; flex-direction: column; gap: 10px; }
        .stage-item { 
            display: flex; 
            align-items: flex-start;
            padding: 15px; 
            background: #f8f9fa; 
            border-radius: 10px;
            border-left: 4px solid #667eea;
            transition: all 0.3s;
            cursor: pointer;
        }
        .stage-item:hover { background: #e8f4f8; transform: translateX(5px); }
        .stage-item.active { background: #d4edda; border-left-color: #27ae60; }
        
        .stage-icon { 
            font-size: 28px; 
            margin-right: 15px;
            min-width: 40px;
            text-align: center;
        }
        
        .stage-content { flex: 1; }
        .stage-name { font-weight: bold; color: #333; margin-bottom: 5px; font-size: 15px; }
        .stage-desc { font-size: 13px; color: #666; margin-bottom: 8px; }
        .stage-components { display: flex; flex-wrap: wrap; gap: 5px; }
        .stage-component { 
            background: white; 
            padding: 3px 10px; 
            border-radius: 12px; 
            font-size: 11px;
            border: 1px solid #ddd;
        }
        
        .stage-detail {
            display: none;
            margin-top: 10px;
            padding: 12px;
            background: white;
            border-radius: 8px;
            font-size: 12px;
            color: #555;
            border-left: 3px solid #3498db;
        }
        .stage-detail.show { display: block; }
        
        /* 拦截器链 */
        .interceptor-chain { position: relative; padding: 20px 0; }
        .chain-line {
            position: absolute;
            left: 30px;
            top: 0;
            bottom: 0;
            width: 3px;
            background: linear-gradient(to bottom, #667eea, #764ba2);
        }
        
        .interceptor-item {
            display: flex;
            align-items: center;
            margin-bottom: 15px;
            position: relative;
            padding-left: 60px;
        }
        
        .interceptor-dot {
            position: absolute;
            left: 22px;
            width: 16px;
            height: 16px;
            border-radius: 50%;
            background: #667eea;
            border: 3px solid white;
            box-shadow: 0 0 0 3px #667eea;
        }
        .interceptor-item.framework .interceptor-dot { background: #3498db; box-shadow: 0 0 0 3px #3498db; }
        .interceptor-item.custom .interceptor-dot { background: #27ae60; box-shadow: 0 0 0 3px #27ae60; }
        
        .interceptor-card {
            background: #f8f9fa;
            padding: 12px 15px;
            border-radius: 8px;
            flex: 1;
            border-left: 3px solid #667eea;
        }
        .interceptor-item.framework .interceptor-card { border-left-color: #3498db; }
        .interceptor-item.custom .interceptor-card { border-left-color: #27ae60; }
        
        .interceptor-name { font-weight: bold; color: #333; margin-bottom: 3px; }
        .interceptor-desc { font-size: 12px; color: #666; }
        .interceptor-meta { 
            display: flex; 
            gap: 10px; 
            margin-top: 8px;
            font-size: 11px;
        }
        .interceptor-type {
            padding: 2px 8px;
            border-radius: 10px;
            background: #e8f4f8;
            color: #2980b9;
        }
        .interceptor-phase {
            padding: 2px 8px;
            border-radius: 10px;
            background: #eafaf1;
            color: #27ae60;
        }
        
        /* 模拟控制台 */
        .console {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            font-family: 'Monaco', 'Menlo', monospace;
            font-size: 13px;
            max-height: 400px;
            overflow-y: auto;
        }
        .console-line {
            padding: 3px 0;
            border-bottom: 1px solid #333;
        }
        .console-line:last-child { border-bottom: none; }
        .console-line.indent-1 { padding-left: 20px; }
        .console-line.indent-2 { padding-left: 40px; }
        .console-timestamp { color: #999; font-size: 11px; margin-right: 10px; }
        .console-arrow { color: #67eea; }
        .console-action { color: #f39c12; }
        .console-success { color: #2ecc71; }
        
        /* 值栈可视化 */
        .value-stack { display: flex; flex-direction: column; gap: 15px; }
        .stack-section {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 15px;
            border-left: 4px solid #667eea;
        }
        .stack-section.context { border-left-color: #f39c12; }
        
        .stack-title { font-weight: bold; color: #333; margin-bottom: 10px; }
        .stack-desc { font-size: 12px; color: #666; margin-bottom: 10px; }
        
        .stack-objects { display: flex; flex-direction: column; gap: 8px; }
        .stack-object {
            background: white;
            padding: 10px;
            border-radius: 6px;
            border: 1px solid #e0e0e0;
        }
        .stack-object-name { font-weight: bold; color: #667eea; font-size: 13px; }
        .stack-object-type { font-size: 11px; color: #999; margin-top: 2px; }
        .stack-object-props { font-size: 11px; color: #666; margin-top: 5px; }
        
        .btn { padding: 10px 20px; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; transition: all 0.3s; margin-right: 10px; }
        .btn-primary { background: #667eea; color: white; }
        .btn-primary:hover { background: #5a6fd6; }
        .btn-success { background: #27ae60; color: white; }
        .btn-success:hover { background: #219a52; }
        
        .nav { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
        .nav a { padding: 10px 20px; background: white; border-radius: 20px; text-decoration: none; color: #333; font-size: 0.9em; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
        .nav a:hover { background: #667eea; color: white; }
        
        .lab { background: #fff7e6; border-left: 4px solid #fa8c16; padding: 15px; border-radius: 8px; margin-bottom: 20px; }
        .lab strong { color: #874d00; }
        
        @keyframes pulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.7; }
        }
        .executing { animation: pulse 1s infinite; background: #fff3cd !important; }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>⚡ Action生命周期可视化</h1>
            <p>深入理解Struts2处理HTTP请求的完整流程</p>
        </div>
        
        <div class="nav">
            <a href="index.jsp">← 返回首页</a>
            <a href="learn">学习中心</a>
            <a href="classloader-visual">类加载可视化</a>
        </div>
        
        <div class="lab">
            <strong>🧪 实验任务</strong>
            <ul>
                <li>点击<strong>生命周期阶段</strong>，查看每个阶段的详细说明和涉及的组件</li>
                <li>观察<strong>拦截器链</strong>，理解责任链模式的执行顺序</li>
                <li>点击<strong>模拟请求执行</strong>，观看完整的请求处理流程</li>
                <li>查看<strong>值栈结构</strong>，理解OGNL如何访问数据</li>
            </ul>
        </div>
        
        <div class="grid">
            <!-- 生命周期流程 -->
            <div class="card">
                <h3>📋 Action生命周期流程（点击查看详情）</h3>
                <div id="lifecycleFlow" class="lifecycle-flow">
                    <div style="text-align: center; padding: 20px; color: #999;">加载中...</div>
                </div>
            </div>
            
            <!-- 拦截器链 -->
            <div class="card">
                <h3>⛓️ 拦截器链执行顺序</h3>
                <div id="interceptorChain" class="interceptor-chain">
                    <div class="chain-line"></div>
                    <div style="text-align: center; padding: 20px; color: #999;">加载中...</div>
                </div>
            </div>
            
            <!-- 模拟请求执行 -->
            <div class="card">
                <h3>🎬 模拟请求执行</h3>
                <div style="margin-bottom: 15px;">
                    <button class="btn btn-primary" onclick="simulateRequest()">开始模拟</button>
                    <button class="btn btn-success" onclick="clearConsole()">清空</button>
                </div>
                <div id="console" class="console">
                    <div class="console-line">点击"开始模拟"观看请求处理流程...</div>
                </div>
            </div>
            
            <!-- 值栈结构 -->
            <div class="card">
                <h3>📚 值栈（ValueStack）结构</h3>
                <div id="valueStack" class="value-stack">
                    <div style="text-align: center; padding: 20px; color: #999;">加载中...</div>
                </div>
            </div>
        </div>
        
        <div class="card">
            <h3>📖 学习要点</h3>
            <ul>
                <li><strong>请求入口:</strong> 所有请求先经过StrutsPrepareAndExecuteFilter过滤器</li>
                <li><strong>ActionProxy:</strong> 封装Action的调用信息，包含拦截器栈配置</li>
                <li><strong>拦截器链:</strong> 使用责任链模式，前置处理顺序执行，后置处理逆序执行</li>
                <li><strong>值栈:</strong> OGNL表达式的根对象，包含Action和上下文数据</li>
                <li><strong>结果渲染:</strong> 根据返回字符串查找对应的Result进行视图渲染</li>
                <li><strong>线程安全:</strong> 每个请求创建新的Action实例，不存在线程安全问题</li>
            </ul>
        </div>
    </div>
    
    <script>
        // 加载生命周期流程
        async function loadLifecycle() {
            try {
                const response = await fetch('lifecycle_getLifecycle');
                const data = await response.json();
                
                const container = document.getElementById('lifecycleFlow');
                container.innerHTML = '';
                
                data.stages.forEach((stage, index) => {
                    const div = document.createElement('div');
                    div.className = 'stage-item';
                    div.style.animationDelay = `${index * 0.1}s`;
                    div.onclick = () => toggleStageDetail(div, stage);
                    
                    const componentsHtml = stage.components.map(c => 
                        `<span class="stage-component">${c}</span>`
                    ).join('');
                    
                    div.innerHTML = `
                        <div class="stage-icon">${stage.icon}</div>
                        <div class="stage-content">
                            <div class="stage-name">${stage.id}. ${stage.name}</div>
                            <div class="stage-desc">${stage.description}</div>
                            <div class="stage-components">${componentsHtml}</div>
                            <div class="stage-detail" id="stage-detail-${stage.id}">
                                <strong>详细说明:</strong><br>
                                ${stage.details}
                            </div>
                        </div>
                    `;
                    
                    container.appendChild(div);
                });
            } catch (error) {
                document.getElementById('lifecycleFlow').innerHTML = 
                    `<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
            }
        }
        
        // 切换阶段详情
        function toggleStageDetail(element, stage) {
            document.querySelectorAll('.stage-item').forEach(item => {
                item.classList.remove('active');
            });
            document.querySelectorAll('.stage-detail').forEach(detail => {
                detail.classList.remove('show');
            });
            
            element.classList.add('active');
            element.querySelector('.stage-detail').classList.add('show');
        }
        
        // 加载拦截器链
        async function loadInterceptorChain() {
            try {
                const response = await fetch('lifecycle_getInterceptorChain');
                const data = await response.json();
                
                const container = document.getElementById('interceptorChain');
                container.innerHTML = '<div class="chain-line"></div>';
                
                data.interceptors.forEach((interceptor, index) => {
                    const div = document.createElement('div');
                    div.className = `interceptor-item ${interceptor.type}`;
                    div.style.animationDelay = `${index * 0.1}s`;
                    
                    div.innerHTML = `
                        <div class="interceptor-dot"></div>
                        <div class="interceptor-card">
                            <div class="interceptor-name">${interceptor.name}</div>
                            <div class="interceptor-desc">${interceptor.description}</div>
                            <div class="interceptor-meta">
                                <span class="interceptor-type">${interceptor.type === 'framework' ? '框架' : '自定义'}</span>
                                <span class="interceptor-phase">${interceptor.phase}</span>
                            </div>
                        </div>
                    `;
                    
                    container.appendChild(div);
                });
            } catch (error) {
                document.getElementById('interceptorChain').innerHTML = 
                    `<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
            }
        }
        
        // 模拟请求执行
        async function simulateRequest() {
            const console = document.getElementById('console');
            console.innerHTML = '<div class="console-line">开始模拟请求处理...</div>';
            
            try {
                const response = await fetch('lifecycle_simulate');
                const data = await response.json();
                
                let delay = 0;
                data.logs.forEach((log, index) => {
                    setTimeout(() => {
                        const line = document.createElement('div');
                        line.className = `console-line indent-${log.indent}`;
                        
                        let message = log.message;
                        if (message.includes('▶️')) message = message.replace('▶️', '<span class="console-action">▶️</span>');
                        if (message.includes('↩️')) message = message.replace('↩️', '<span class="console-arrow">↩️</span>');
                        if (message.includes('✅')) message = message.replace('✅', '<span class="console-success">✅</span>');
                        
                        line.innerHTML = `<span class="console-timestamp">${log.timestamp}</span>${message}`;
                        console.appendChild(line);
                        console.scrollTop = console.scrollHeight;
                    }, delay);
                    delay += 300;
                });
                
            } catch (error) {
                console.innerHTML += `<div class="console-line" style="color: #e74c3c;">模拟失败: ${error.message}</div>`;
            }
        }
        
        // 清空控制台
        function clearConsole() {
            document.getElementById('console').innerHTML = '<div class="console-line">点击"开始模拟"观看请求处理流程...</div>';
        }
        
        // 加载值栈
        async function loadValueStack() {
            try {
                const response = await fetch('lifecycle_getValueStack');
                const data = await response.json();
                
                const container = document.getElementById('valueStack');
                container.innerHTML = '';
                
                data.stack.forEach((section, index) => {
                    const div = document.createElement('div');
                    div.className = `stack-section ${section.type}`;
                    
                    const objectsHtml = section.objects.map(obj => `
                        <div class="stack-object">
                            <div class="stack-object-name">${obj.name}</div>
                            <div class="stack-object-type">${obj.type}</div>
                            <div class="stack-object-props">${obj.properties}</div>
                        </div>
                    `).join('');
                    
                    div.innerHTML = `
                        <div class="stack-title">${section.name}</div>
                        <div class="stack-desc">${section.description}</div>
                        <div class="stack-objects">${objectsHtml}</div>
                    `;
                    
                    container.appendChild(div);
                });
                
                // 添加OGNL示例
                const examplesDiv = document.createElement('div');
                examplesDiv.className = 'stack-section';
                examplesDiv.innerHTML = `
                    <div class="stack-title">OGNL表达式示例</div>
                    <div class="stack-desc">${data.ognl}</div>
                    <div class="stack-objects">
                        ${data.examples.map(ex => `
                            <div class="stack-object">
                                <div class="stack-object-props">${ex}</div>
                            </div>
                        `).join('')}
                    </div>
                `;
                container.appendChild(examplesDiv);
                
            } catch (error) {
                document.getElementById('valueStack').innerHTML = 
                    `<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
            }
        }
        
        // 页面加载时初始化
        window.onload = function() {
            loadLifecycle();
            loadInterceptorChain();
            loadValueStack();
        };
    </script>
</body>
</html>
