package com.steerinfo.file.fileUpdate.controller;

import com.steerinfo.baseinfo.meterbasetimespace.model.MeterBaseTimeSpace;
import com.steerinfo.baseinfo.meterbasetimespace.service.IMeterBaseTimeSpaceService;
import com.steerinfo.file.fileUpdate.model.FileModel;
import com.steerinfo.framework.controller.BaseRESTfulController;
import com.steerinfo.framework.controller.RESTfulResult;
import com.steerinfo.util.ResultModel;
import com.steerinfo.util.StringUtils;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.dom4j.*;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

@RestController
@RequestMapping("/${api.version}/HFile")
public class HttpFileServiceController extends BaseRESTfulController {
    /**
     * 获取路径
     * @return /D:/apache-tomcat-8.5.45/webapps/core-file-ftp/AutoUpdate
     * @throws Exception
     */
    @PostMapping(value = "getPath")
    public String getPath() throws Exception {
        String path = "";
        try
        {
            path = Thread.currentThread().getContextClassLoader().getResource("/").getPath();
            if (path.indexOf("WEB-INF") > 0) {
                path = path.substring(0, path.indexOf("/WEB-INF/classes"));
            }
            path = path.replace("%20", " ")+"/AutoUpdate";

            String os = System.getProperty("os.name");
            if(os.toLowerCase().startsWith("win")){
                path=path.substring(1);
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.getMessage());
        }
        return path;
    }


    /**
     * 上传文件 多文件上传
     * @return
     * @throws Exception
     */
    @PostMapping(value = "updateFile")
    public ResultModel updateFile() throws Exception {
        ResultModel rm=new ResultModel();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        List<FileModel> lm=null;
        try{
            String basePath=getPath();
            lm=getFileXml(basePath+"/serviceFilelist.xml");
            //这个地方设置就不会出现中文名称乱码现象
            request.setCharacterEncoding("UTF-8");
            DiskFileItemFactory fac = new DiskFileItemFactory();
            ServletFileUpload sfp = new  ServletFileUpload(fac);
            List<FileItem> items = sfp.parseRequest(request);
            Iterator<FileItem> iter = items.iterator(); // 处理上传的项目
            while (iter.hasNext()) { //如果是一次性上传多个文件，那这里会分别去保存
                FileItem item = iter.next();
                if (!item.isFormField()) { // 过滤表单里的非文件类型字段
                    if (!"".equals(item.getName())) { // 过滤非文件类型的input
                        String s_name =item.getName(); // 获得原始文件名
                        //int position = s_name.lastIndexOf(".");
                        //String s_fileType = s_name.substring(position, s_name.length()); // 获得文件后缀
                        String filePath=item.getFieldName().substring(0,item.getFieldName().length()-1);
                        InputStream inputStream = item.getInputStream(); //文件的对应输入流

                        if(CreateFiles(basePath +"/"+ filePath)){
                            //File file = new File("d:/" + s_name);
                            File file = new File(basePath +"/"+ filePath +"/"+ s_name);
                            copyInputStreamToFile(inputStream, file);
                            boolean bNewFile=true;
                            for(FileModel fm:lm){
                                if(fm.getFileName().equals(s_name)&&fm.getFileUrl().equals(filePath)){
                                    fm.setEdition(fm.getEdition()+1);
                                    bNewFile=false;
                                    break;
                                }
                            }
                            if(bNewFile){
                                FileModel fm=new FileModel();
                                fm.setFileName(s_name);
                                fm.setFileUrl(filePath);
                                fm.setEdition(1);
                                lm.add(fm);
                            }
                        }
                    }
                }
            }
            rm.setState("200");
        }catch(Exception ex){
            rm.setState("500");
            rm.setMsgInfo("上传失败!"+ex.getMessage());
            ex.printStackTrace();
        }
        if(lm!=null&&lm.size()>0){
            WriteFileXml(getPath()+"/serviceFilelist.xml", lm);
        }
        return rm;
    }
    private void copyInputStreamToFile(InputStream inputStream, File file) throws IOException {
        try (FileOutputStream outputStream = new FileOutputStream(file)) {
            int read;
            byte[] bytes = new byte[1024];
            while ((read = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, read);
            }
        }
    }



    /**
     * 下载文件
     * */
    @PostMapping(value = "downLoadFile")
    public void downLoadFile(){
        try{
            HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
            String fileName="";
            String path="";
            try{
                request.setCharacterEncoding("UTF-8");
                path= URLDecoder.decode(request.getParameter("path"),"UTF-8");

                fileName=path.split("/")[path.split("/").length-1];
            }catch(Exception ex){
                ex.printStackTrace();
                return;
            }
            path=getPath()+"/"+path;

            byte[] buffer=InputStream2ByteArray(path);//"d:/eason/语言/Git参考手册-新.CHM");

            HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
            // 清空response
            response.reset();
            response.setContentType("text/html;charset=UTF-8");
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes("UTF-8"),"ISO-8859-1"));
            //response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(oldFileName,"UTF-8"));
            //response.addHeader("Content-Length", "" + fis.length());
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        }catch(Exception ex){
            ex.printStackTrace();
            return;
        }
    }
    private byte[] InputStream2ByteArray(String filePath) throws IOException {
        InputStream in = new FileInputStream(filePath);
        byte[] data = toByteArray(in);
        in.close();
        return data;
    }
    private byte[] toByteArray(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024 * 4];
        int n = 0;
        while ((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    }


    /**
     * 创建文件夹
     * @param path
     * @return
     */
    private boolean CreateFiles(String path) {
        if ((path == null) || (path.trim().length() == 0)) {
            return false;
        }
        File file = new File(path);
        try
        {
            if (!file.exists()) {
                file.mkdir();
            } else {
                return true;
            }
        }
        catch (Exception ex)
        {
            return false;
        }
        return true;
    }

    /**
     * 读取xml文件
     * 调用方式：getFileXml("D:/serviceFilelist.xml");
     * @param path
     * @param
     * @return
     * @throws DocumentException
     * @throws IOException
     */
    private List<FileModel> getFileXml(String path) throws Exception {
        List<FileModel> lm=new ArrayList<>();
        File file = new File(path);
        if (!file.exists()) { //存在为true，不存在为false
            //没有文件则创建并写入document对象
            lm =readfile(getPath(),null);
            for(FileModel f:lm){
                f.setEdition(1);
            }
            if(lm.size()==0){
                FileModel fm=new FileModel();
                fm.setFileUrl("");
                fm.setEdition(1);
                fm.setFileName("serviceFilelist.xml");
                lm.add(fm);
            }
            WriteFileXml(path,lm);
        } else {
            //有文件则读取文件中的信息
            //1.创建SAXReader对象用于读取xml文件
            SAXReader reader = new SAXReader();
            //2.读取xml文件，获得Document对象
            Document doc = reader.read(new File(path));
            //3.获取根元素
            Element root = doc.getRootElement();
            //4.获取根元素下的所有子元素（通过迭代器）
            Iterator<Element> it = root.elementIterator();
            while(it.hasNext()){
                FileModel f=new FileModel();

                Element e = it.next();
                //获取id属性(attribute是属性的意思)
                Attribute fn = e.attribute("filename");
                //f.setFileName(fn.getName());
                f.setFileName(fn.getStringValue());
                fn = e.attribute("path");
                f.setFileUrl(fn.getStringValue());
                fn = e.attribute("edition");
                f.setEdition(fn.getStringValue().equals(null)?0:Integer.parseInt(fn.getStringValue()));
                lm.add(f);
                //Element author = e.element("author"); 子子节点
            }
        }

        return lm;
    }

    /**
     * 读取某个文件夹下的所有文件(支持多级文件夹)
     */
    private List<FileModel> readfile(String filepath,List<FileModel> lm) throws Exception {
        try {
            if(lm==null) lm=new ArrayList<FileModel>();

            File file = new File(filepath);
            if (!file.isDirectory()) {
                ////system.out.println("文件");

                FileModel fm=new FileModel();
                fm.setFileName(file.getName());
                fm.setFileUrl(file.getPath());
                //fm.setFileType(file.getAbsolutePath());
                lm.add(fm);

            } else if (file.isDirectory()) {
                ////system.out.println("文件夹");
                String[] filelist = file.list();
                for (int i = 0; i < filelist.length; i++) {
                    File readfile = new File(filepath + "\\" + filelist[i]);
                    if (!readfile.isDirectory()) {
                        FileModel fm=new FileModel();
                        fm.setFileName(readfile.getName());
                        fm.setFileUrl(readfile.getPath());
                        //fm.setFileUrl(readfile.getAbsolutePath());
                        lm.add(fm);

                    } else if (readfile.isDirectory()) {
                        readfile(filepath + "\\" + filelist[i],lm);
                    }
                }

            }

        } catch (Exception e) {
            //system.out.println("readfile()   Exception:" + e.getMessage());
        }
        return lm;
    }

	/*
	public static void main(String[] args) throws Exception {
		List<FileModel> lm = null;
		try {
			lm = readfile("d:/Debug",null);
		} catch (IOException ex) {
		}
		//system.out.println("ok");
	}
	//*/


    /**
     * 写入xml文件
     * @param path
     * @param
     * @return
     * @throws Exception
     */
    private boolean WriteFileXml(String path, List<FileModel> lm) throws Exception {
        if ((path == null) || (path.trim().length() == 0)) {
            return false;
        }
        if (lm==null) {
            return false;
        }
        int index = path.lastIndexOf("/");
        String updatePath = path.substring(0, index);
        File checkSpaceh = new File(updatePath);
        long freeSpace = checkSpaceh.getFreeSpace() / 1024L / 1024L;
        if (freeSpace < 2L) {
            //throw new CoreException("磁盘空间不足,保存filelist.xml失败");
        }
        File file = new File(path);
        try
        {
            if (!file.exists()) {
                file.createNewFile();
            } else {
                file.delete();
            }

            // 1、创建document对象
            Document document = DocumentHelper.createDocument();
            // 2、创建根节点rss
            Element rss = document.addElement("files");
            for(FileModel fm:lm){
                // 4、生成子节点及子节点内容
                Element fl = rss.addElement("file");
                // 4.1、向channel节点添加filename属性
                fl.addAttribute("filename", fm.getFileName());
                fl.addAttribute("path", fm.getFileUrl());
                fl.addAttribute("edition", fm.getEdition()+"");

                //fl.setText("国内最新新闻"); //给子节点fl添加内容<file>国内最新新闻</file>
            }



            // 5、设置生成xml的格式
            OutputFormat format = OutputFormat.createPrettyPrint();
            // 设置编码格式
            format.setEncoding("UTF-8");


            // 6、生成xml文件
            XMLWriter writer = new XMLWriter(new FileOutputStream(file), format);
            // 设置是否转义，默认使用转义字符
            writer.setEscapeText(false);
            writer.write(document);
            writer.close();

        }
        catch (Exception e)
        {
            throw new Exception(e.getMessage());
        }
        return true;
    }


    /**
     * 删除文件及文件夹
     * @param
     * @return
     * @throws Exception
     */
    @PostMapping(value = "delFileOrFiles")
    public ResultModel delFileOrFiles(ArrayList<String> paths) throws Exception{
        ResultModel rm=new ResultModel();
        List<FileModel> lm=null;
        try{
            lm=getFileXml(getPath()+"/serviceFilelist.xml");
            boolean bError=true;
            rm.setState("200");
            String sUrl="";
            for(String str:paths){
                if(DelFileOrFiles(str)){//删除成功则写入
                    for(FileModel fm:lm){
                        if(!fm.getFileUrl().isEmpty()){
                            sUrl=fm.getFileUrl()+"/"+fm.getFileName();
                        }else{
                            sUrl=fm.getFileName();
                        }
                        if(sUrl.equals(str)){
                            lm.remove(fm);
                            break;
                        }
                    }
                    bError=false;
                }
            }
            if(bError){
                rm.setState("500");
            }
        }catch(Exception ex){
            rm.setState("500");
            rm.setMsgInfo(ex.getMessage());
        }

        if(lm!=null){
            WriteFileXml(getPath()+"/serviceFilelist.xml", lm);
        }

        return rm;
    }
    private boolean DelFileOrFiles(String path) {
        if ((path == null) || (path.trim().length() == 0)) {
            return false;
        }
        try {
            File file = new File(getPath()+"/"+path);

            if (file.exists())
            {
                if (file.isFile())
                {
                    return file.delete();
                }
                else if (file.isDirectory())
                {
                    File[] cFile = file.listFiles();
                    if (cFile.length > 0) {
                        for (int i = 0; i < cFile.length; i++) {
                            DelFileOrFiles(cFile[i].getPath());
                        }
                    }
                    return file.delete();
                }
            }
            else {
                return true;
            }
        }
        catch (Exception ex) {
            return false;
        }
        return true;
    }
}
