package com.alibaba.datax.plugin.unstructuredstorage.writer;

import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;

import com.alibaba.datax.common.util.Configuration;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.csvreader.CsvWriter;


public class TextCsvWriterManager {

    public static UnstructuredWriter produceTextWriter( Writer writer, String fieldDelimiter, Configuration config) {
        return new TextWriterImpl(writer, fieldDelimiter, config);
    }

    public static UnstructuredWriter produceCsvWriter( Writer writer, char fieldDelimiter, Configuration config) {
        return new CsvWriterImpl(writer, fieldDelimiter, config);
    }
}

class CsvWriterImpl implements UnstructuredWriter {
    private static final Logger LOG = LoggerFactory
            .getLogger(CsvWriterImpl.class);
    // csv 严格符合csv语法, 有标准的转义等处理
    private char fieldDelimiter;
    private String lineDelimiter;
    private DataXCsvWriter csvWriter;

    public CsvWriterImpl(Writer writer, char fieldDelimiter, Configuration config) {
        this.fieldDelimiter = fieldDelimiter;
        this.lineDelimiter = config.getString(Key.LINE_DELIMITER, IOUtils.LINE_SEPARATOR);
        this.csvWriter = new DataXCsvWriter(writer, this.fieldDelimiter);
        this.csvWriter.setTextQualifier('"');
        this.csvWriter.setUseTextQualifier(true);
        // warn: in linux is \n , in windows is \r\n
        this.csvWriter.setRecordDelimiter(this.lineDelimiter.charAt(0));

        String csvWriterConfig = config.getString(Key.CSV_WRITER_CONFIG);
        if (StringUtils.isNotBlank(csvWriterConfig)) {
            try {
                HashMap<String, Object> csvWriterConfigMap = JSON.parseObject(csvWriterConfig,
                        new TypeReference<HashMap<String, Object>>() {
                        });
                if (!csvWriterConfigMap.isEmpty()) {
                    // this.csvWriter.setComment(var1);
                    // this.csvWriter.setDelimiter(var1);
                    // this.csvWriter.setEscapeMode(var1);
                    // this.csvWriter.setForceQualifier(var1);
                    // this.csvWriter.setRecordDelimiter(var1);
                    // this.csvWriter.setTextQualifier(var1);
                    // this.csvWriter.setUseTextQualifier(var1);
                    BeanUtils.populate(this.csvWriter, csvWriterConfigMap);
                    LOG.info(String.format("csvwriterConfig is set successfully. After setting, csvwriter:%s", JSON.toJSONString(this.csvWriter)));
                }
            } catch (Exception e) {
                LOG.warn(String.format("invalid csvWriterConfig config: %s, DataX will ignore it.", csvWriterConfig),
                        e);
            }
        }
    }

    @Override
    public void writeOneRecord(List<String> splitedRows) throws IOException {
        if (splitedRows.isEmpty()) {
            LOG.info("Found one record line which is empty.");
        }
        this.csvWriter.writeRecord(splitedRows.toArray(new String[0]));
    }

    @Override
    public void flush() throws IOException {
        this.csvWriter.flush();
    }

    @Override
    public void close() throws IOException {
        this.csvWriter.close();
    }

}

class TextWriterImpl implements UnstructuredWriter {
    private static final Logger LOG = LoggerFactory
            .getLogger(TextWriterImpl.class);
    // text StringUtils的join方式, 简单的字符串拼接
    private String fieldDelimiter;
    private Writer textWriter;
    private String lineDelimiter;

    public TextWriterImpl(Writer writer, String fieldDelimiter, Configuration config) {
        this.fieldDelimiter = fieldDelimiter;
        this.textWriter = writer;
        this.lineDelimiter = config.getString(Key.LINE_DELIMITER, IOUtils.LINE_SEPARATOR);
    }

    @Override
    public void writeOneRecord(List<String> splitedRows) throws IOException {
        if (splitedRows.isEmpty()) {
            LOG.info("Found one record line which is empty.");
        }
        this.textWriter.write(String.format("%s%s",
                StringUtils.join(splitedRows, this.fieldDelimiter),
                this.lineDelimiter));
    }

    @Override
    public void flush() throws IOException {
        this.textWriter.flush();
    }

    @Override
    public void close() throws IOException {
        this.textWriter.close();
    }

}
