package com.sdtool.common.servlet.apidoc;

import com.sdtool.common.base.PCERPAdminHttpServlet;
import com.sdtool.common.tdoc.TAppDoc;
import com.sweetfish.boot.Application;
import com.sweetfish.net.http.*;
import com.sweetfish.util.AnyValue;
import com.sweetfish.util.AutoLoad;
import com.sweetfish.util.Utility;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.FileResourceLoader;

import javax.annotation.Resource;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ConcurrentHashMap;

import static com.sweetfish.net.Server.RESNAME_SERVER_ROOT;

/**
 * Created by Administrator on 2017-03-25.
 */
@AutoLoad(false)
@WebServlet({"/xdoc/*"})
public class ApiDocServlet extends PCERPAdminHttpServlet {

    protected static class HtmlEntity {
        protected final String filename;

        protected final File file; //如果所有资源文件打包成zip文件则file=null

        protected ByteBuffer content;

        public HtmlEntity(File file) {
            this.file = file;
            this.filename = file.getName();
            update();
        }

        public void update() {
            if (this.file == null) {
                return;
            }
            if (this.content != null) {
                this.content = null;
            }
            long length = this.file.length();
            try {
                FileInputStream in = new FileInputStream(file);
                ByteArrayOutputStream out = new ByteArrayOutputStream((int) file.length());
                byte[] bytes = new byte[10240];
                int pos;
                while ((pos = in.read(bytes)) != -1) {
                    out.write(bytes, 0, pos);
                }
                in.close();
                byte[] bs = out.toByteArray();
                ByteBuffer buf = ByteBuffer.allocateDirect(bs.length);
                buf.put(bs);
                buf.flip();
                this.content = buf.asReadOnlyBuffer();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        protected void finalize() throws Throwable {
            super.finalize();
        }
    }

    //网页缓存，只存储一个对象
    protected final ConcurrentHashMap<String, HtmlEntity> html = new ConcurrentHashMap<>();

    //application对象，在Application Start中注入
    @Resource(name = "APPLICATION")
    Application application;

    @Resource(name = "APP_HOME")
    private String appHome;

    //网页根目录
    @Resource(name = RESNAME_SERVER_ROOT)
    File webRoot;

    @Resource(name = RESNAME_SERVER_ROOT)
    String webRootStr;

    private String runEnvironment;

    @Override
    public void init(HttpContext context, AnyValue config) {
        super.init(context, config);
        AnyValue environmentValue = config.getAnyValue("environment");
        if (environmentValue != null) {
            runEnvironment = environmentValue.getValue("value");
        } else {
            runEnvironment = "product";
        }
    }

    @HttpMapping(url = "/xdoc/index", methods = {"GET"}, moduleid = 9999, actionid = 1)
    public void get(HttpRequest request, HttpResponse response) throws IOException {

        if ("dev".equalsIgnoreCase(runEnvironment)) {
            CompletionHandler<File, ByteBuffer> handler = Utility.createAsyncHandler(
                    (V, A) -> {
                        try {
                            response.finishFile(V, A);
                        } catch (IOException e) {
                            logger.error("doc get error", e);
                            response.finish(500, e.getMessage());
                        }
                    },
                    (T, A) -> {
                        response.finish(500, T.getMessage());
                        T.printStackTrace();
                    }
            );
            submit(() -> {
                        logger.info(request);
                        HtmlEntity entity = html.computeIfAbsent("docs", this::createEntity);
                        if (handler != null) {
                            handler.completed(entity.file, entity.content);
                        }
                    }
            );
        } else {
            response.finish("无效的地址");
        }
    }

    @HttpMapping(url = "/xdoc/clear", methods = {"GET"}, moduleid = 9999, actionid = 1)
    public void clear(HttpRequest request, HttpResponse response) throws IOException {
        CompletionHandler<String, Void> handler = Utility.createAsyncHandler(
                response::finish,
                (T) -> {
                    response.finish(500, T.getMessage());
                    T.printStackTrace();
                }
        );
        submit(() -> {
                    html.remove("docs");
                    if (handler != null) {
                        handler.completed("清除缓存成功", null);
                    }
                }
        );
    }

    protected HtmlEntity createEntity(String key) {
        HtmlEntity entity = null;
        try {
            FileResourceLoader resourceLoader = new FileResourceLoader(webRootStr + File.separator + "api", "utf-8");
            Configuration cfg = Configuration.defaultConfiguration();
            GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
            Template t = gt.getTemplate("api-template.html");

            TAppDoc doc = new TAppDoc();
            doc.setAppName(System.getProperty("current.app.name"));
            doc.bind(application).appHome(appHome).generate();

            t.binding("appdoc", doc);
            String content = t.render();

            File api = new File(webRoot, "newapidoc.html");
            FileOutputStream outhtml = new FileOutputStream(api);
            outhtml.write(content.getBytes(StandardCharsets.UTF_8));
            outhtml.close();
            entity = new HtmlEntity(api);
        } catch (Exception e) {
            logger.error("doc get error", e);
        }
        return entity;
    }
}
