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

import com.brilliance.mda.runtime.mda.*;
import com.brilliance.mda.runtime.mda.impl.StreamImpl;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.brilliance.mda.runtime.mda.Constants.CR;
import static com.brilliance.mda.runtime.mda.Constants.NO_ERROR;

public class Streams {

    private static final Logger log = LoggerFactory.getLogger(Streams.class);

    public static final void copy(InputStream is, OutputStream os)
            throws IOException {
        try {
            IOUtils.copy(is, os);
        } finally {
            MdaUtils.closeQuietly(is);
            MdaUtils.closeQuietly(os);
        }
    }

    public static final void copy(Reader reader, OutputStream os, Charset charset)
            throws IOException {
        try {
            IOUtils.copy(reader, os, charset);
        } finally {
            MdaUtils.closeQuietly(reader);
            MdaUtils.closeQuietly(os);
        }
    }

    //TODO
    public static int streamCount(IStream stream){
        if (stream == null) return 0;

        return stream.countLines();
    }
    public static int streamSearch(IStream stream,String line){
        if (stream == null) return 0;
        return stream.searchLine(line);
    }



    public static int streamSearch(IStream stream, String vtag, int start, int end) {
        List<String> rows = stream.getRows();
        if (end < 0 || end > rows.size()) end = rows.size();
        if (start > end) return 0;
        int i = start-1;
        for (; i < end; i++) {
            if (stream.isKeepsort() && rows.get(i).startsWith(vtag)) {
                break;
            }
            //非保持排序，忽略大小写
            if(!stream.isKeepsort() && rows.get(i).toLowerCase().startsWith(vtag.toLowerCase())){
                break;
            }
        }
        if (i == rows.size()) return 0;
        return i + 1;
    }
    public static int streamSearch(IStream objStream, String vtag, int start) {

        return streamSearch(objStream, vtag, start, -1);
    }
    public static void streamSetLine(IStream stream,int idx,String line){
        if(stream.isKeepsort()){
            return;
        }
        stream.setLine(idx, line);
    }

    public static String streamGetLine(IStream stream, int idx) {
        return stream.getLine(idx);
    }

    public static void streamSet(IStream src, Object dist) {
        if (dist instanceof IStream) {
            streamSetByIStream(src, (IStream) dist);
        } else if (dist instanceof String) {
            streamSetByString(src, (String) dist);
        }
    }

    public static void streamSetByIStream(IStream src, IStream dist) {
        src.clearLines();
        dist.getRows().forEach(src::addLine);
    }

    public static void streamSetByString(IStream src, String str) {
        if (str == null || str.trim().isEmpty()) {
            MdaUtils.clear(src);
            return;
        }
        src.clearLines();
        String[] lines = str.split("[\\n]|\\r\\n");
        Arrays.stream(lines).forEach(line -> src.addLine(line));
    }

    public static void streamSet(IStream src, String str, int len) {
        if (str == null || str.trim().isEmpty()) {
            MdaUtils.clear(src);
            return;
        }
        src.clearLines();
        String[] lines = str.split("[\\n]|\\r\\n");
        Arrays.stream(lines).forEach(line->{
            int begPos = 0;
            while(begPos + len<line.length()){
                src.addLine(line.substring(begPos,begPos+len));
                begPos += len;
            }
            if(begPos<line.length()) {
                src.addLine(line.substring(begPos));
            }
        });
    }

    public static void streamSet(IStream src, String str, double len) {
        streamSet(src,str,(int)len);
    }
    public static void streamInsert(IStream stream,int idx,String line){
        if (stream==null) return;
        stream.insertLine(idx, line);
    }
    public static void streamInsert(IStream stream,int idx,IStream lines){
        if(idx <=0 || idx > stream.countLines()) {
            lines.getRows().forEach(stream::addLine);
        }else{
            //如果已通过调用 StreamSort 并为 keepsorted 参数提供 TRUE 设置了流的“keepsorted”标志，则将在适当的位置插入行。在这种情况下，
            // 为idx提供除 <=0 或 > StreamCount(S) 之外的任何值都会将错误代码设置为 117。
            if(stream.isKeepsort()){
                return;
            }
            AtomicInteger count = new AtomicInteger(-1);
            lines.getRows().forEach(item->stream.getRows().add(idx - 1 + count.incrementAndGet(),item));
        }
    }
    public static void streamDelete(IStream stream,int idx){
        stream.deleteLine(idx);
    }
    public static void streamSort(IStream stream){
        streamSort(stream,false);
    }
    public static void streamSort(IStream stream,boolean keepsort){
        stream.sortLines();
        stream.setKeepsort(keepsort);
    }
    public static void streamSave(IStream stream, String fileName) {
        try {
            fileName = Strings.convertPrefix(fileName);
            File file = Files.mkdirs(fileName);
            stream.saveLines(file);
            return;

        } catch (Exception e) {
            log.error("streamSave error.", e);

        }
    }
    public static void streamLoad(IStream stream, String fileName) {
        try {
            fileName = Strings.convertPrefix(fileName);
            File file = new File(fileName);
            stream.close();
            stream.loadLines(file);
        } catch (IOException e) {
            log.error("streamLoad error.", e);
            //throw new RuleExecuteException(String.format("文件读取失败[%s]。",fileName),e);
        }
    }
    public static void streamClear(IStream stream) {
        if(stream != null) {
            //stream.close();
            stream.clearLines();
        }
    }
    public static void getAttributeStream(IStream out,IStream dist,String attr){
        if (dist == null){
            return;
        }
        IStream tmp = dist.getAttribute(attr);
        if(tmp == null || tmp.countLines() == 0){
            out.clearLines();
            return;
        }
        out.setRows(tmp.getRows());
    }

    public static void setAttributeStream(IStream dist,String attr,IStream value){
        dist.setAttribute(attr, value);
    }



    public static String streamGetAdditional(IStream stm,String s1,String s2){
        switch (s1){
            case "ANNOTATION_TEXT":
                break;
            case "ANNOTATION_CLASS":
                break;
            case "ANNOTATION_HINT":
                break;
            case "ANNOTATION_USER":
                break;
            case "ANNOTATION_TIMESTAMP":
                break;
            case "ANNOTATION_COUNT":
                break;
            case "CHARDATA":
                if (s2.equals("")){
                    return stm.getValue();
                }
                break;
            case "RANGETEXT":
                break;
            case "SELRANGE":
                break;
        }

        return null;
    }

}
