package com.brilliance.mda.runtime.mda.util;

import com.brilliance.mda.runtime.mda.IStream;
import com.brilliance.isc.vo.ResponseSet;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.brilliance.mda.runtime.mda.Constants.NULLSTR;


public class Files {

    private static final Logger log = LoggerFactory.getLogger(Files.class);
    private final static String rootPath = "/DATA/DISPLAY/";
    public static final String separator = File.separator;
//    public static ResponseSet<Object> fileOutput(String trninr) {
//        FileInputStream fis = null;
//        InputStreamReader isr = null;
//        BufferedReader br = null;
//        String str = "";
//        String messageStr = "";
//        try {
//            fis = new FileInputStream(AppEnv.getRootPath() + rootPath +trninr.substring(0,4)+"/"+ trninr + ".DSP");
//            isr = new InputStreamReader(fis);
//            br = new BufferedReader(isr);
//            while ((str = br.readLine()) != null) {
//                messageStr += str;
//            }
//        } catch (FileNotFoundException e) {
//            System.out.println("找不到指定文件");
//            e.printStackTrace();
//        } catch (IOException e) {
//            System.out.println("读取文件失败");
//            e.printStackTrace();
//        } finally {
//            try {
//                if(null!=br){
//                    br.close();
//                }
//                if(null!=isr){
//                    isr.close();
//                }
//                if(null!=fis){
//                    fis.close();
//                }
//
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
//        return new ResponseSet(messageStr);
//    }

    public static File mkdirs(String fileName) {
        if(fileName == null) return null;
        File file = new File(fileName);
        if (!file.getParentFile().exists())
            file.getParentFile().mkdirs();
        return file;
    }

    public static boolean fileCopy(String sourceFileName, String targetFileName) {
        try {
            sourceFileName = Strings.convertPrefix(sourceFileName);
            targetFileName = Strings.convertPrefix(targetFileName);
            File sourceFile = new File(sourceFileName);
            File targetFile = new File(targetFileName);
            if (targetFile.exists()) {
                if (sourceFile.isDirectory())
                    FileUtils.copyDirectoryToDirectory(sourceFile, targetFile);
                else if (targetFile.isDirectory())
                    FileUtils.copyFileToDirectory(sourceFile, targetFile);
                else {
                    FileUtils.copyFile(sourceFile, targetFile);
                }

            } else if (sourceFile.isDirectory()) {
                targetFile.mkdirs();
                FileUtils.copyDirectory(sourceFile, targetFile);
            } else {
                FileUtils.copyFile(new File(sourceFileName), mkdirs(targetFileName));
            }
            return true;
        } catch (Exception e) {
            log.error("fileCopy error", e);
        }
        return false;
    }

    public static boolean fileDelete(String fileName) {
        try {
            fileName = Strings.convertPrefix(fileName);
            FileUtils.forceDelete(new File(fileName));
            return true;
        } catch (Exception e) {
            log.error("fileDelete error", e);
        }
        return false;
    }

    public static boolean fileMove(String sourcefileNameOrPath, String targetFileOrPathName) {
        try {
            sourcefileNameOrPath = Strings.convertPrefix(sourcefileNameOrPath);
            targetFileOrPathName = Strings.convertPrefix(targetFileOrPathName);
            File sourceFile = new File(sourcefileNameOrPath);
            File targetFile = new File(targetFileOrPathName);
            if (targetFile.exists()) {
                if (sourceFile.isDirectory())
                    FileUtils.moveDirectoryToDirectory(sourceFile, targetFile, false);
                else if (targetFile.isDirectory())
                    FileUtils.moveFileToDirectory(sourceFile, targetFile, false);
                else {
                    FileUtils.moveFile(sourceFile, targetFile);
                }

            } else if (sourceFile.isDirectory())
                FileUtils.moveDirectoryToDirectory(sourceFile, targetFile, true);
            else {
                FileUtils.moveFile(sourceFile, targetFile);
            }
            return true;
        } catch (Exception e) {
            log.error("fileMove error", e);
        }
        return false;
    }

    public static boolean fileMkdirs(String filePath) {
        return new File(filePath).mkdirs();
    }

    public static String fileName(String fileName) {
        return FilenameUtils.getName(fileName);
    }

    public static String fileBaseName(String fileName) {
        return FilenameUtils.getBaseName(fileName);
    }

    public static String fileExtension(String fileName) {
        return FilenameUtils.getExtension(fileName);
    }

    public static boolean fileExists(String fileName) {
        fileName = Strings.convertPrefix(fileName);
        return new File(fileName).exists();
    }

    public static long fileSize(String fileName) {
        return new File(fileName).length();
    }

    public static String fileMD5Value(String fileName) {
        try {
            return DigestUtils.md5Hex(new FileInputStream(fileName));
        } catch (Exception e) {
            log.error("Get MD5 error.", e);
        }
        return null;
    }

    public static void fileArchive(String zipFileName, String[] fileNames, String baseDirectoryName) {
        try {
            Archives.archive(new FileOutputStream(zipFileName), fileNames, baseDirectoryName);
        } catch (Exception e) {
            log.error("Archive file error.", e);
        }
    }

    public static void fileArchive(IStream zipStream, String[] fileNames, String baseDirectoryName) {
        try {
            Archives.archive(zipStream.getOutputStream(), fileNames, baseDirectoryName);
        } catch (Exception e) {
            log.error("Archive file error.", e);
        }
    }

    public static boolean fileExtract(String zipFileName, String entryName, String outputFileName) {
        try {
            return Archives.extract(new FileInputStream(zipFileName), entryName, new FileOutputStream(outputFileName));
        } catch (Exception e) {
            log.error("Extract file error.", e);
        }
        return false;
    }

    public static boolean fileExtract(IStream zipStream, String entryName, IStream outputStream) {
        try {
            return Archives.extract(zipStream.getInputStream(), entryName, outputStream.getOutputStream());
        } catch (Exception e) {
            log.error("Extract file error.", e);
        }
        return false;
    }

    public static final List<String> loadLines(String fileName, String encoding) {
        try {
            FileInputStream fis = new FileInputStream(fileName);
            List list = IOUtils.readLines(fis, encoding);
            fis.close();
            return list;
        } catch (Exception e) {
            log.error("Read lines error.", e);
        }
        return Collections.EMPTY_LIST;
    }

    public static final void saveLines(List<String> lines, String lineEnding, String fileName, String encoding) {
        try {
            IOUtils.writeLines(lines, "", new FileOutputStream(fileName), encoding);
        } catch (Exception e) {
            log.error("Save lines error.", e);
        }
    }

    public static final void saveContent(String content, String fileName, String encoding) {
        try {
            IOUtils.write(content, new FileOutputStream(fileName), encoding);
        } catch (Exception e) {
            log.error("Load content error.", e);
        }
    }

    public static final String[] loadExcelSheetNames(IStream s) {
        Workbook wb = getWorkbook(s);
        if (wb == null)
            return null;
        int count = wb.getNumberOfSheets();
        String[] sheetNames = new String[count];
        for (int i = 0; i < count; i++)
            sheetNames[i] = wb.getSheetName(i);
        resetQuietly(s);
        return sheetNames;
    }

    private static final Workbook getWorkbook(IStream s) {
        Workbook wb = null;
        try {
            wb = new HSSFWorkbook(s.getInputStream());
        } catch (OfficeXmlFileException _e) {
            try {
                resetQuietly(s);
                wb = new XSSFWorkbook(s.getInputStream());
            } catch (IOException e) {
                log.warn("load excel error.", e);
            }
        } catch (IOException e) {
            log.warn("load excel error.", e);
        }
        resetQuietly(s);
        return wb;
    }

    private static final void resetQuietly(IStream s) {
        try {
            s.getInputStream().reset();
        } catch (IOException localIOException) {
        }
    }

    public static final int loadExcel(List<String[]> list, IStream s, int sheetIndex, int rowOffset, int rowMax, int columnOffset, int columnCount) {
        Workbook wb = getWorkbook(s);
        if (wb == null)
            return -1;
        if ((sheetIndex < 0) || (sheetIndex >= wb.getNumberOfSheets())) {
            log.warn("load excel sheet with a illegal index.");
            return -3;
        }
        Sheet sheet = wb == null ? null : wb.getSheetAt(sheetIndex);
        if (sheet == null) {
            log.warn("load excel sheet error.");
            return -2;
        }

        int rows = rowMax > 0 ? Math.min(rowMax, sheet.getLastRowNum() - rowOffset) : sheet.getLastRowNum() - rowOffset;
        if (columnCount > 0) {
            for (int i = 0; i <= rows; i++) {
                Row row = sheet.getRow(i + rowOffset);
                String[] values = new String[columnCount];
                for (int j = 0; j < columnCount; j++) {
                    if (row == null) {
                        values[j] = "";
                    } else {
                        Cell cell = row.getCell(j + columnOffset);
                        values[j] = (cell != null ? getCellValue(cell, cell.getCellTypeEnum()) : "");
                    }
                }
                list.add(values);
            }
        }
        return rows;
    }

    private static final String getCellValue(Cell cell, CellType type) {
        switch (type) {
            case FORMULA:
                return getCellValue(cell, cell.getCachedFormulaResultTypeEnum());
            case ERROR:
                return cell.getStringCellValue();
            case BOOLEAN:
                int df = cell.getCellStyle().getDataFormat();

                if ((df == 20) || (df == 32))
                    return MdaUtils.timeFormat.format(cell.getDateCellValue());
                if ((DateUtil.isInternalDateFormat(df)) || (df == 31) || (df == 57) || (df == 58) || (DateUtil.isCellDateFormatted(cell)))
                    return MdaUtils.dateFormat.format(cell.getDateCellValue());
                return MdaUtils.format.format(Double.valueOf(cell.getNumericCellValue()));
        }
        return cell.toString();
    }

    private static final int unloadExcel(Object value, Row row, int cellNum) {
        Cell cell = row.createCell(cellNum);
        if ((value != null) && ((value instanceof Number))) {
            cell.setCellType(CellType.NUMERIC);
            cell.setCellValue(((Number) value).doubleValue());
        } else {
            cell.setCellType(CellType.STRING);
            if ((value == null) || ((value instanceof String)))
                cell.setCellValue((String) value);
            else
                cell.setCellValue(value.toString());
        }
        return cellNum + 1;
    }

    private static final void unloadExcel(List list, Sheet sheet) {
        int rowNum = 0;
        for (Iterator localIterator1 = list.iterator(); localIterator1.hasNext(); ) {
            Object values = localIterator1.next();

            Row row = sheet.createRow(rowNum);
            int cellNum = 0;
            if ((values instanceof Iterable)) {
                for (Iterator localIterator2 = ((Iterable) values).iterator(); localIterator2.hasNext(); ) {
                    Object value = localIterator2.next();
                    cellNum = unloadExcel(value, row, cellNum);
                }
            } else if ((values instanceof Object[])) {
                for (Object value : (Object[]) values)
                    cellNum = unloadExcel(value, row, cellNum);
            }
            rowNum++;
        }
    }

    public static final void unloadExcel(List[] lists, String[] sheetNames, IStream s, boolean flag) {
        Workbook wb = flag ? new XSSFWorkbook() : new HSSFWorkbook();
        OutputStream os = null;
        try {
            for (int i = 0; i < lists.length; i++) {
                List list = lists[i];
                String sheetname = sheetNames[i];
                Sheet sheet = MdaUtils.isEmpty(sheetname) ? wb.createSheet() : wb.createSheet(sheetname);
                unloadExcel(list, sheet);
            }
            os = s.getOutputStream();
            wb.write(os);
            os.flush();
        } catch (IOException e) {
            log.error("unload Excel error.", e);
        } finally {
            MdaUtils.closeQuietly(os);
            MdaUtils.closeQuietly(wb);
        }
    }

    public static final void unloadExcel(List list, IStream s, boolean flag) {
        unloadExcel(new List[]{list}, new String[1], s, flag);
    }

    public static final void forceDelete(File path)
            throws IOException {
        IOException exception = null;
        for (int i = 0; i < 10; ) {
            try {
                FileUtils.forceDelete(path);
                return;
            } catch (IOException e) {
                exception = e;
                try {
                    Thread.sleep(1000L);
                } catch (Exception localException) {
                }
                i++;
            }

        }

        throw exception;
    }

    public static String fileCreate(String filename){
        File file = new File(filename);
        File parentFolder = file.getParentFile();
        String reg = "#{1,}";
        Matcher m = Pattern.compile(reg).matcher(filename);
        if(m.find()){
            int beg = m.start();
            int end = m.end();
            for (int i = beg; i <= end; i++){
                if (filename.indexOf(beg) != '#'){
//                    MdaEnv.getContext().setErrorCode(75);
                }
            }
            int len = end - beg;
            if(!parentFolder.exists()){
                parentFolder.mkdirs();
                String nfilename = filename.substring(0,beg)+ String.format("%0"+len+"d",0) +filename.substring(end);
                file.delete();
                File nfile = new File(nfilename);
                try {
                    nfile.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return nfilename;
            }
            int maxNum = -1;
            File[] fileList = parentFolder.listFiles();
            String path2 = file.getAbsolutePath();
            for (File file1 : fileList) {
                if(file1.isDirectory())
                    continue;
                String path1 = file1.getAbsolutePath();
                //判断长度相等
                //判断前后是否一致
                if (path1.length() == path2.length()
                        && path1.substring(0, beg).equals(path2.substring(0, beg))
                        && path1.substring(end).equals(path2.substring(end))){
                    //取出中间字符，判断是否符合纯数字
                    String temp = path1.substring(beg, end);
                    int i = 0;
                    for (i = 0; i < temp.length(); i++){
                        if (!Character.isDigit(temp.charAt(i))){
                            break;
                        }
                    }
                    //与maxNum比较与赋值
                    if (i == temp.length()){
                        int num = Integer.parseInt(temp);
                        if ((temp+1+NULLSTR).length() > len){       //99...99格式
//                            MdaEnv.getContext().setErrorCode(76);
                        }
                        maxNum = Math.max(maxNum, num);
                    }
                }
            }
            String numstr = String.format("%0"+len+"d",maxNum+1);
            String nfilename = filename.substring(0,beg)+numstr+filename.substring(end);
            File nfile = new File(nfilename);
            //文件重新创建
            try {
                nfile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return nfilename;
        }else{
            if(!parentFolder.exists())
                parentFolder.mkdirs();
            if(file.exists())
                file.delete();
            try {
                file.createNewFile();
            }catch (IOException e)
            {
//                MdaEnv.getContext().setErrorCode(10);
                return null;
            }
            return filename;
        }
    }

    //TODO 补充
    public static String fileCreate(String filename,String val){
        String reg = "#{1,}";
        Matcher m = Pattern.compile(reg).matcher(filename);
        if(m.find())
        {
            int beg = m.start();
            int end = m.end();
            for (int i = beg; i <= end; i++){
                if (filename.charAt(beg) != '#'){
//                    MdaEnv.getContext().setErrorCode(75);
                }
            }
            if (!filename.substring(0, beg).equals(val.substring(0, beg))){
//                MdaEnv.getContext().setErrorCode(75);
            }
            String numstr = val.substring(beg,end);
            int num = Integer.parseInt(numstr);
            num++;
            numstr = String.format("%0"+m.group().length()+"d",num);
            String nfilename = filename.substring(0,beg)+numstr+filename.substring(end);
            File file = new File(nfilename);
            File parentFolder = file.getParentFile();
            if(!parentFolder.exists())
                parentFolder.mkdirs();
            if(file.exists())
                file.delete();
            try {
                if (!file.createNewFile()){
//                    MdaEnv.getContext().setErrorCode(10);
                }
            }catch (IOException e)
            {
                return null;
            }
            return nfilename;
        }else{
            File file = new File(filename);
            if (file.exists()){
//                MdaEnv.getContext().setErrorCode(12);
            }
        }
        return null;
    }

    public static void getDirStream(IStream dirstream, String path, String filemask, int filetype) {
        path = Strings.convertPrefix(path);
        File file = new File(path);
        if(!file.exists() || !file.isDirectory())
        {
//            MdaEnv.getContext().setErrorCode(2);
            return;
        }
        final String fileReg = filemask.replace("*", "\\w*").replaceAll("\\.","\\.");
        File[] fitFiles=file.listFiles(new FileFilter() {
            @Override
            public boolean accept(File item) {
                boolean flag = true;
                if (item.isDirectory()){
                    if (filetype != 16){
                        return false;
                    }
                    flag = true;
                }
                if (filetype == 1){
                    flag = item.canRead() && !item.canWrite();
                }
                if (filetype == 2){
                    flag = item.isHidden();
                }
                if (filetype == 16){
                    flag = item.isDirectory();
                }
                if (filetype == 32){
                    String suffix = item.getName().substring(item.getName().lastIndexOf(".") + 1);
                    flag = suffix.equals("zip") || suffix.equals("rar") || suffix.equals("7-Zip") || suffix.equals("JAR") || suffix.equals("ISO") || suffix.equals("TAR");
                }
                return flag && item.getName().matches(fileReg);
            }
        });
        if(!(filetype == 0 || filetype == 1 || filetype == 2 || filetype == 4 || filetype == 8 || filetype == 16 || filetype == 32 || filetype == 63)){
//            MdaEnv.getContext().setErrorCode(-1);
        }
        //TODO      未确定返回name还是绝对路径。在TD未触发函数执行
        Arrays.stream(fitFiles).forEach(fileItem->dirstream.addLine(fileItem.getName()));
    }

//    public static Date fileDateTime(String frmFile) {
//        if (frmFile == null) return null;
//        if (frmFile.startsWith("/")) {
//            frmFile = Strings.getAbsPath(frmFile);
//        }
//        File f = new File(frmFile);
//        if (f.exists()) {
//            Calendar c = Calendar.getInstance();
//            long time = f.lastModified();
//            c.setTimeInMillis(time);
//            return c.getTime();
//        }
//        return null;
//    }
//
//    public static Date fileDate(String frmFile) {
//        if (frmFile == null) return null;
//        if (frmFile.startsWith("/")) {
//            frmFile = Strings.getAbsPath(frmFile);
//        }
//        File f = new File(frmFile);
//        if (f.exists()) {
//            Date date = new Date();
//            long time = f.lastModified();
//            date.setTime(time);
//            return date;
//        }
//        return null;
//    }

//    public static double fileTime(String str) {
//        Calendar c = Calendar.getInstance();
//        c.setTime(fileDateTime(str));
//        int h = c.get(Calendar.HOUR_OF_DAY);
//        int m = c.get(Calendar.MINUTE);
//        int s = c.get(Calendar.SECOND);
//        return h + m / 100 + s / 10000;
//    }

    public static List<String> listFiles(String path, String[] extensions) {
        List list = new ArrayList();
        try {
            for (File file : FileUtils.listFiles(new File(path), extensions, false))
                list.add(file.getAbsolutePath());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return list;
    }

    public static List<String> listDirectories(String path) {
        List list = new ArrayList();
        try {
            for (File file : new File(path).listFiles((FileFilter) DirectoryFileFilter.DIRECTORY))
                list.add(file.getAbsolutePath());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return list;
    }

}
