package com.example.struts2;

import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import com.google.gson.Gson;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.*;

/**
 * 类加载可视化Action - 展示JVM类加载机制
 * 
 * 学习点：
 * - 类加载器层次结构（Bootstrap -> Extension -> Application）
 * - 类的加载过程
 * - 双亲委派模型
 */
public class ClassLoaderAction extends ActionSupport {
    
    private static final Gson gson = new Gson();
    private Map<String, Object> classLoaderInfo;
    private List<Map<String, Object>> loadedClasses;
    
    /**
     * 显示类加载可视化页面
     */
    public String execute() {
        return SUCCESS;
    }
    
    /**
     * 获取类加载器层次结构信息（AJAX）
     */
    public String getClassLoaderHierarchy() {
        Map<String, Object> result = new LinkedHashMap<>();
        
        // 获取当前类的类加载器
        ClassLoader appLoader = this.getClass().getClassLoader();
        ClassLoader extLoader = appLoader.getParent();
        ClassLoader bootstrapLoader = extLoader != null ? extLoader.getParent() : null;
        
        List<Map<String, Object>> hierarchy = new ArrayList<>();
        
        // Bootstrap ClassLoader
        Map<String, Object> bootstrap = new LinkedHashMap<>();
        bootstrap.put("name", "Bootstrap ClassLoader");
        bootstrap.put("type", "bootstrap");
        bootstrap.put("description", "启动类加载器 - 加载核心Java类（rt.jar）");
        bootstrap.put("loadedClasses", getBootstrapClasses());
        bootstrap.put("parent", null);
        hierarchy.add(bootstrap);
        
        // Extension ClassLoader
        if (extLoader != null) {
            Map<String, Object> extension = new LinkedHashMap<>();
            extension.put("name", "Extension ClassLoader");
            extension.put("type", "extension");
            extension.put("description", "扩展类加载器 - 加载扩展类（ext目录）");
            extension.put("className", extLoader.getClass().getName());
            extension.put("loadedClasses", countLoadedClasses(extLoader));
            extension.put("parent", "Bootstrap ClassLoader");
            hierarchy.add(extension);
        }
        
        // Application ClassLoader
        Map<String, Object> application = new LinkedHashMap<>();
        application.put("name", "Application ClassLoader");
        application.put("type", "application");
        application.put("description", "应用类加载器 - 加载classpath下的类");
        application.put("className", appLoader.getClass().getName());
        application.put("loadedClasses", countLoadedClasses(appLoader));
        application.put("parent", extLoader != null ? "Extension ClassLoader" : "Bootstrap ClassLoader");
        hierarchy.add(application);
        
        // 当前Web应用的类加载器（如果是Web应用）
        ClassLoader threadLoader = Thread.currentThread().getContextClassLoader();
        if (threadLoader != appLoader) {
            Map<String, Object> web = new LinkedHashMap<>();
            web.put("name", "WebApp ClassLoader");
            web.put("type", "webapp");
            web.put("description", "Web应用类加载器 - 加载WEB-INF/classes和lib下的类");
            web.put("className", threadLoader.getClass().getName());
            web.put("loadedClasses", "动态加载");
            web.put("parent", "Application ClassLoader");
            hierarchy.add(web);
        }
        
        result.put("hierarchy", hierarchy);
        result.put("currentClassLoader", this.getClass().getClassLoader().getClass().getName());
        
        writeJsonResponse(result);
        return NONE;
    }
    
    /**
     * 获取已加载的类列表（AJAX）
     */
    public String getLoadedClasses() {
        Map<String, Object> result = new LinkedHashMap<>();
        List<Map<String, Object>> classes = new ArrayList<>();
        
        // 获取一些重要的Struts2相关类
        String[] classNames = {
            "com.opensymphony.xwork2.ActionSupport",
            "org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter",
            "com.opensymphony.xwork2.interceptor.AbstractInterceptor",
            "org.apache.struts2.components.Component",
            "com.opensymphony.xwork2.util.ValueStack",
            "ognl.Ognl",
            "com.example.struts2.HelloAction",
            "com.example.struts2.CalculatorAction"
        };
        
        for (String className : classNames) {
            try {
                Class<?> clazz = Class.forName(className);
                Map<String, Object> classInfo = new LinkedHashMap<>();
                classInfo.put("name", className);
                classInfo.put("simpleName", clazz.getSimpleName());
                classInfo.put("classLoader", clazz.getClassLoader() != null ? 
                    clazz.getClassLoader().getClass().getSimpleName() : "Bootstrap");
                classInfo.put("package", clazz.getPackage().getName());
                classInfo.put("superclass", clazz.getSuperclass() != null ? 
                    clazz.getSuperclass().getSimpleName() : "None");
                classInfo.put("interfaces", getInterfacesNames(clazz));
                classInfo.put("loadedTime", "运行时已加载");
                classes.add(classInfo);
            } catch (ClassNotFoundException e) {
                // 类未找到，跳过
            }
        }
        
        result.put("classes", classes);
        result.put("totalCount", classes.size());
        
        writeJsonResponse(result);
        return NONE;
    }
    
    /**
     * 模拟类加载过程（AJAX）
     */
    public String simulateClassLoading() {
        Map<String, Object> result = new LinkedHashMap<>();
        List<Map<String, Object>> steps = new ArrayList<>();
        
        // 步骤1: 加载
        Map<String, Object> step1 = new LinkedHashMap<>();
        step1.put("step", 1);
        step1.put("name", "加载 (Loading)");
        step1.put("description", "通过类的全限定名获取二进制字节流，将静态存储结构转化为方法区的运行时数据结构");
        step1.put("action", "查找.class文件 -> 读取字节码 -> 创建Class对象");
        step1.put("icon", "📂");
        steps.add(step1);
        
        // 步骤2: 验证
        Map<String, Object> step2 = new LinkedHashMap<>();
        step2.put("step", 2);
        step2.put("name", "验证 (Verification)");
        step2.put("description", "确保字节码符合JVM规范，不会危害虚拟机安全");
        step2.put("action", "文件格式验证 -> 元数据验证 -> 字节码验证 -> 符号引用验证");
        step2.put("icon", "✅");
        steps.add(step2);
        
        // 步骤3: 准备
        Map<String, Object> step3 = new LinkedHashMap<>();
        step3.put("step", 3);
        step3.put("name", "准备 (Preparation)");
        step3.put("description", "为类的静态变量分配内存并设置默认初始值");
        step3.put("action", "分配静态变量内存 -> 设置默认值(int=0, boolean=false, reference=null)");
        step3.put("icon", "📝");
        steps.add(step3);
        
        // 步骤4: 解析
        Map<String, Object> step4 = new LinkedHashMap<>();
        step4.put("step", 4);
        step4.put("name", "解析 (Resolution)");
        step4.put("description", "将常量池内的符号引用替换为直接引用");
        step4.put("action", "类/接口解析 -> 字段解析 -> 方法解析 -> 接口方法解析");
        step4.put("icon", "🔗");
        steps.add(step4);
        
        // 步骤5: 初始化
        Map<String, Object> step5 = new LinkedHashMap<>();
        step5.put("step", 5);
        step5.put("name", "初始化 (Initialization)");
        step5.put("description", "执行类构造器<clinit>()方法，为静态变量赋予正确的初始值");
        step5.put("action", "执行静态代码块 -> 初始化静态变量 -> 类完全可用");
        step5.put("icon", "🚀");
        steps.add(step5);
        
        result.put("steps", steps);
        result.put("totalSteps", steps.size());
        
        writeJsonResponse(result);
        return NONE;
    }
    
    /**
     * 获取Struts2框架核心类的加载信息
     */
    public String getStrutsClassesInfo() {
        Map<String, Object> result = new LinkedHashMap<>();
        List<Map<String, Object>> modules = new ArrayList<>();
        
        // Action模块
        Map<String, Object> actionModule = new LinkedHashMap<>();
        actionModule.put("name", "Action模块");
        actionModule.put("description", "处理用户请求的核心组件");
        actionModule.put("classes", Arrays.asList(
            createClassInfo("ActionSupport", "提供了Action的基础实现", "com.opensymphony.xwork2"),
            createClassInfo("ActionContext", "Action的上下文环境", "com.opensymphony.xwork2"),
            createClassInfo("ServletActionContext", "与Servlet集成的上下文", "org.apache.struts2"),
            createClassInfo("ActionInvocation", "Action调用链", "com.opensymphony.xwork2")
        ));
        modules.add(actionModule);
        
        // 拦截器模块
        Map<String, Object> interceptorModule = new LinkedHashMap<>();
        interceptorModule.put("name", "拦截器模块");
        interceptorModule.put("description", "在Action执行前后进行增强处理");
        interceptorModule.put("classes", Arrays.asList(
            createClassInfo("AbstractInterceptor", "拦截器基类", "com.opensymphony.xwork2.interceptor"),
            createClassInfo("Interceptor", "拦截器接口", "com.opensymphony.xwork2.interceptor"),
            createClassInfo("ActionInvocation", "拦截器链调用", "com.opensymphony.xwork2"),
            createClassInfo("DefaultActionInvocation", "默认实现", "com.opensymphony.xwork2")
        ));
        modules.add(interceptorModule);
        
        // OGNL模块
        Map<String, Object> ognlModule = new LinkedHashMap<>();
        ognlModule.put("name", "OGNL模块");
        ognlModule.put("description", "对象图导航语言，用于数据绑定");
        ognlModule.put("classes", Arrays.asList(
            createClassInfo("Ognl", "OGNL核心类", "ognl"),
            createClassInfo("OgnlContext", "OGNL上下文", "ognl"),
            createClassInfo("ValueStack", "值栈", "com.opensymphony.xwork2.util"),
            createClassInfo("CompoundRoot", "复合根对象", "com.opensymphony.xwork2.util")
        ));
        modules.add(ognlModule);
        
        // 结果处理模块
        Map<String, Object> resultModule = new LinkedHashMap<>();
        resultModule.put("name", "结果处理模块");
        resultModule.put("description", "处理Action执行结果");
        resultModule.put("classes", Arrays.asList(
            createClassInfo("Result", "结果接口", "com.opensymphony.xwork2"),
            createClassInfo("ServletDispatcherResult", "Servlet转发结果", "org.apache.struts2.dispatcher"),
            createClassInfo("ServletRedirectResult", "重定向结果", "org.apache.struts2.dispatcher"),
            createClassInfo("StreamResult", "流结果", "org.apache.struts2.dispatcher")
        ));
        modules.add(resultModule);
        
        result.put("modules", modules);
        
        writeJsonResponse(result);
        return NONE;
    }
    
    /**
     * 辅助方法：创建类信息
     */
    private Map<String, String> createClassInfo(String name, String desc, String pkg) {
        Map<String, String> info = new LinkedHashMap<>();
        info.put("name", name);
        info.put("description", desc);
        info.put("package", pkg);
        return info;
    }
    
    /**
     * 辅助方法：获取接口名称列表
     */
    private List<String> getInterfacesNames(Class<?> clazz) {
        List<String> interfaces = new ArrayList<>();
        for (Class<?> iface : clazz.getInterfaces()) {
            interfaces.add(iface.getSimpleName());
        }
        return interfaces;
    }
    
    /**
     * 辅助方法：统计已加载的类数量
     */
    private String countLoadedClasses(ClassLoader loader) {
        // 实际项目中可以使用Instrumentation API获取准确数字
        return "动态加载";
    }
    
    /**
     * 辅助方法：获取Bootstrap加载的核心类
     */
    private List<String> getBootstrapClasses() {
        return Arrays.asList("java.lang.Object", "java.lang.String", "java.lang.System", 
            "java.util.ArrayList", "java.util.HashMap", "java.io.File");
    }
    
    /**
     * 辅助方法：写入JSON响应
     */
    private void writeJsonResponse(Map<String, Object> data) {
        try {
            ServletActionContext.getResponse().setContentType("application/json;charset=UTF-8");
            PrintWriter out = ServletActionContext.getResponse().getWriter();
            out.print(gson.toJson(data));
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    // Getters and Setters
    public Map<String, Object> getClassLoaderInfo() { return classLoaderInfo; }
    public void setClassLoaderInfo(Map<String, Object> classLoaderInfo) { this.classLoaderInfo = classLoaderInfo; }
    
    public List<Map<String, Object>> getLoadedClasses() { return loadedClasses; }
    public void setLoadedClasses(List<Map<String, Object>> loadedClasses) { this.loadedClasses = loadedClasses; }
}
