package com.ruoyi.web.controller.map.controller;

import cn.hutool.core.io.file.FileReader;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONReader;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.gson.stream.JsonReader;
import com.ruoyi.common.core.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.FileUtils;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import org.gdal.gdal.gdal;
import org.gdal.ogr.DataSource;
import org.gdal.ogr.Driver;
import org.gdal.ogr.ogr;
import com.ruoyi.web.controller.map.util.CoordinateUtil;
import com.ruoyi.web.controller.map.util.GeoJsonUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author wrh
 * @since 2023-03-29
 */
@RestController
@Api(tags = "多源数据加载")
@RequestMapping("/map/multiDataSource")
public class MultiDataSourceController {

    @Value("${ruoyi.profile}")
    private String upLoadPath;

    private JSONObject processValue = new JSONObject();

    private int port = 6111;
    private Server server = new Server(new InetSocketAddress("127.0.0.1", port));

    private String workspace = "";
    /**
     * 文件夹映射
     */
    @ApiOperation(value = "文件夹映射", notes = "文件夹映射")
    @RequestMapping(value = "/folderMapping", method = RequestMethod.GET)
    public AjaxResult folderMapping(@RequestParam(name = "folderName") String folderName) {
        String msg = "";
        String timeStamp = String.valueOf(new Date().getTime());
        if (startSeverWithTime(folderName, timeStamp)) {
            msg = "http://localhost:" + 6111 + "/model/" + timeStamp;
        }
        return AjaxResult.success(msg);
    }
    private boolean startSeverWithTime(String folderName, String timeStamp) {
        try {
            if (server.isRunning()) {
                System.out.println("正在停止");
                server.stop();
                server.join();
            }
            WebAppContext webContext = new WebAppContext(folderName, "/model/" + timeStamp);
            server.setHandler(webContext);
            server.start();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    private boolean startSever(String folderName) {
        try {
            if (server.isRunning()) {
                System.out.println("正在停止");
                server.stop();
                server.join();
            }
            WebAppContext webContext = new WebAppContext(folderName, "/model");
            server.setHandler(webContext);
            server.start();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 返回映射文件夹下含有tileset.json或tilemapresource.xml文件的子文件夹列表
     */
    @ApiOperation(value = "文件夹映射", notes = "文件夹映射")
    @RequestMapping(value = "/getModelList", method = RequestMethod.GET)
    public AjaxResult getModelList(@RequestParam(name = "folderName") String folderName) {
        File dir = new File(folderName);
        workspace = folderName;
        List<String> fileFolderList = new ArrayList<>();
        getAllFileFolder(dir, fileFolderList);
        String msg = "";
        if (startSever(folderName)) {
            msg = "http://localhost:" + 6111 + "/model";
        }
        return AjaxResult.success(msg, fileFolderList);
    }

    public void getAllFileFolder(File fileInput, List<String> fileFolderList) {
        // 获取文件列表
        File[] fileList = fileInput.listFiles();
        if ((fileList != null ? fileList.length : 0) > 0) {
            for (File file : fileList) {
                if (file.isDirectory()) {
                    getAllFileFolder(file, fileFolderList);
                } else {
                    // 含有tileset.json或tilemapresource.xml文件
                    if (file.getName().equals("tileset.json") || file.getName().equals("tilemapresource.xml")) {
                        String fileFolder = file.getParent().replace("\\","/").replace(workspace,"") + "/" + file.getName();
                        fileFolderList.add(fileFolder);
                        break;
                    }
                    if (file.getName().endsWith(".kml") || file.getName().endsWith(".geojson")) {
                        String fileFolder = file.getParent().replace("\\","/").replace(workspace,"") + "/" + file.getName();
                        fileFolderList.add(fileFolder);
                    }
                }
            }
        }
    }

    /**
     * 上传文件
     */
    @ApiOperation(value = "上传文件", notes = "上传文件")
    @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
    public AjaxResult uploadFile(HttpServletRequest request) throws IOException {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            String fileName = entity.getValue().getOriginalFilename();
            File dest = new File(upLoadPath + "/" + fileName);
            FileUtils.copyInputStreamToFile(entity.getValue().getInputStream(), dest);
        }
        return AjaxResult.success("successful upload");
    }

    @ApiOperation(value = "dxf转geojson", notes = "dxf转geojson")
    @RequestMapping(value = "/dxf2GeoJSON", method = RequestMethod.POST)
    public AjaxResult dxf2GeoJSON(HttpServletRequest request) throws IOException {
        AjaxResult ajax = new AjaxResult();
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            String fileName = entity.getValue().getOriginalFilename() + "";
            File file = new File(upLoadPath + "/" + fileName);
            FileUtils.copyInputStreamToFile(entity.getValue().getInputStream(), file);
            processValue.put("percentage", "正在转换，请稍等");
            File geoJsonFile = new File(file.getAbsolutePath().replace(".dxf", ".geojson").replace("\\","/"));
            String geoJson = dxf2GeoJson(file, geoJsonFile);
            if (geoJson.equals("success")) {
                JSONObject newJsonObject = new JSONObject();
                newJsonObject.put("type", "FeatureCollection");
                newJsonObject.put("name", fileName.replace(".dxf", ""));
                SplitGeoJson(geoJsonFile, newJsonObject);
                ajax = AjaxResult.success("上传成功");
            }
            else
                ajax = AjaxResult.error("加载失败");
        }
        return ajax;
    }

    @ApiOperation(value = "dxf转shp", notes = "dxf转shp")
    @RequestMapping(value = "/dxf2Shp", method = RequestMethod.POST)
    public AjaxResult dxf2Shp(HttpServletRequest request) throws IOException {
        AjaxResult ajax = new AjaxResult();
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            String fileName = entity.getValue().getOriginalFilename() + "";
            File file = new File(upLoadPath + "/" + fileName);
            FileUtils.copyInputStreamToFile(entity.getValue().getInputStream(), file);
            processValue.put("percentage", "正在转换，请稍等");
            File shpFile = new File(file.getAbsolutePath().replace(".dxf", ".shp").replace("\\","/"));
            String shp = dxf2Shp(file, shpFile);
            if (shp.equals("success")) {
                ajax = AjaxResult.success("上传成功");
            }
            else
                ajax = AjaxResult.error("加载失败");
        }
        return ajax;
    }

    /**
     * 获取session中的进度值
     */
    @ApiOperation(value = "获取上传进度", notes = "获取上传进度")
    @RequestMapping(value = "/getProcess", method = RequestMethod.GET)
    public AjaxResult getProcess() {
        AjaxResult ajax;
        if (processValue.size() == 0)
            processValue.put("percentage", "正在转换，请稍等");
        if (processValue.getString("fileNum") == null)
            ajax = AjaxResult.success(processValue.getString("percentage") + "," + "0");
        else
            ajax = AjaxResult.success(processValue.getString("percentage") + "," + processValue.getString("fileNum"));
        return ajax;
    }

    /**
     * 获取GeoJSON文件
     */
    @ApiOperation(value = "获取单个geojson文件", notes = "获取单个geojson文件")
    @RequestMapping(value = "/geoJSONFromDxf", method = RequestMethod.GET)
    public AjaxResult geoJSONFromDxf(@RequestParam(name = "geoJsonName") String geoJsonName) {
        if (new File(upLoadPath + "/" + geoJsonName + ".geojson").exists())
//            return AjaxResult.success("", new FileReader(upLoadPath + "/" + geoJsonName + ".geojson").readString());
            return AjaxResult.success("", new FileReader(upLoadPath + "/" + geoJsonName + ".geojson").readString());
        else
            return AjaxResult.success("加载完成");
    }

    /**
     * 获取文件夹列表
     */
    @ApiOperation(value = "获取文件夹列表", notes = "获取文件夹列表")
    @RequestMapping(value = "/getPath", method = RequestMethod.GET)
    public AjaxResult getPath(@RequestParam(name = "pathName") String pathName) {
        JSONObject ajaxResult = new JSONObject();
        List<String> folderList = new ArrayList<>();
        File[] roots;
        if (pathName.equals(" ")) {
            if (System.getProperty("os.name").toLowerCase().contains("linux")) {
                roots = new File[1];
                roots[0] = new File("/home");
            }
            else
                roots = File.listRoots();
        }
        else {
            roots = new File(pathName).listFiles();
        }
        if (roots != null) {
            for (File root : roots)
                folderList.add(root.getPath());
        }
        ajaxResult.put("folderList", folderList);
        return AjaxResult.success(ajaxResult);
    }
    /**
     * 拆分geojson
     */
    private void SplitGeoJson(File geoJsonFile, JSONObject newJsonObject) throws IOException {
        String rootName;
        int featuresLength = 0;
        JsonReader reader = new JsonReader(new FileReader(geoJsonFile.getAbsolutePath()).getReader());
        reader.beginObject();
        while (reader.hasNext()) {
            rootName = reader.nextName();
            if (rootName.equals("features")) {
                reader.beginArray();
                while (reader.hasNext()) {
                    reader.skipValue();
                    featuresLength++;
                }
            }
            else {
                reader.skipValue();
            }
        }
        reader.close();
        JSONReader jsonReader = new JSONReader(new FileReader(geoJsonFile.getAbsolutePath()).getReader());
        jsonReader.startObject();
        JSONArray newFeaturesArray = new JSONArray();
        String geometryType,geometryType1,flag;
        StringBuilder jsonObjectString;
        while (jsonReader.hasNext()) {
            rootName = jsonReader.readString();
            if (rootName.equals("features")) {
                jsonReader.startArray();
                int currentPercent;
                int fileSize = 500;
                if (featuresLength > 100000)
                    fileSize = 5000;
                int batch = (featuresLength % fileSize == 0) ? (featuresLength / fileSize) : (featuresLength / fileSize + 1);
                int featuresNumber = 0;//记数
                for (int j = 0; j < batch; j++) {
                    File subFile = new File(upLoadPath + "/" + geoJsonFile.getName().split("\\.")[0] + j + ".geojson");
                    jsonObjectString = new StringBuilder().append("[");
                    int toIndex = j == batch - 1 ? featuresLength : fileSize * (j + 1);
                    while (jsonReader.hasNext() && featuresNumber < toIndex && featuresNumber >= fileSize * j) {
                        jsonObjectString.append(jsonReader.readObject()).append(",");
                        featuresNumber++;
                    }
                    newFeaturesArray = JSONArray.parseArray(jsonObjectString.append("]").toString());
                    jsonObjectString.setLength(0);
                    if (!subFile.exists()) {
                        geometryType = newFeaturesArray.getJSONObject(0).getJSONObject("geometry").getString("coordinates");
                        geometryType1 = newFeaturesArray.getJSONObject(0).getJSONObject("geometry").getString("geometries");
                        flag = geometryType == null ? JSONArray.parseArray(geometryType1).getJSONObject(0).getString("coordinates") : geometryType;
                        double validate = Double.parseDouble(flag.split(",")[0].replace("[", ""));
                        if (CoordinateUtil.outOfChina(validate,0))
                            GeoJsonUtil.convertCoordinate(newFeaturesArray);
                        newJsonObject.put("features", newFeaturesArray);
                        String content = JSON.toJSONString(newJsonObject, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
                                SerializerFeature.WriteDateUseDateFormat);
                        Writer writer = new OutputStreamWriter(new FileOutputStream(subFile), StandardCharsets.UTF_8);
                        writer.write(content);
                        writer.flush();
                        writer.close();
                    }
                    currentPercent = (int) Math.floor(((double) j / batch) * 100);
                    processValue.put("percentage", "正在加载" + geoJsonFile.getName().replace(".geojson","") + ":" + currentPercent + "%");
                    processValue.put("fileNum", j);
                }
                processValue.put("percentage", "正在加载" + geoJsonFile.getName().replace(".geojson","") + ":" + 100 + "%");
                jsonReader.endArray();
            }
            else {
                jsonReader.readObject();
            }
        }
        jsonReader.endObject();
        jsonReader.close();
    }

    /**
     * 基于gdal实现dxf转GeoJson
     */
    private String dxf2GeoJson(File dxfFile, File geoJsonFile) {
        ogr.RegisterAll();
        gdal.SetConfigOption("DXF_ENCODING", "UTF-8");
        if (!geoJsonFile.exists()) {
            DataSource ds = ogr.Open(dxfFile.getAbsolutePath(), 0);
            if (ds == null) {
                return "打开文件失败！";
            } else {
                Driver driver = ogr.GetDriverByName("GeoJSON");
                driver.CopyDataSource(ds, geoJsonFile.getAbsolutePath()).delete();
                ds.delete();
                return "success";
            }
        }
        else
            return "success";
    }

    /**
     * 基于gdal实现dxf转Shp
     */
    private String dxf2Shp(File dxfFile, File shpFile) {
        ogr.RegisterAll();
        gdal.SetConfigOption("DXF_ENCODING", "UTF-8");
        gdal.SetConfigOption("SHAPE_ENCODING","CP936");
        if (!shpFile.exists()) {
            DataSource ds = ogr.Open(dxfFile.getAbsolutePath(), 0);
            if (ds == null) {
                return "打开文件失败！";
            } else {
                Driver driver = ogr.GetDriverByName("ESRI Shapefile");
                driver.CopyDataSource(ds, shpFile.getAbsolutePath()).delete();
                ds.delete();
                return "success";
            }
        }
        else
            return "success";
    }

    /**
     * 创建文件夹
     */
    private void makeDir(String filePath) {
        if (filePath.lastIndexOf('/') > 0) {
            String dirPath = filePath.substring(0, filePath.lastIndexOf('/'));
            File dir = new File(dirPath);
            if (!dir.exists()) {
                dir.mkdirs();
            }
        }
    }
}
