package com.unionpay.acp.demo;

import com.unionpay.acp.sdk.SDKConfig;
import com.unionpay.acp.sdk.SDKConstants;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * 名称： demo中用到的方法<br>
 * 日期： 2015-09<br>
 * <p>
 * 版权： 中国银联<br>
 * 声明：以下代码只是为了方便商户测试而提供的样例代码，商户可以根据自己需要，按照技术文档编写。该代码仅供参考，不提供编码，性能，规范性等方面的保障<br>
 */
public class DemoUtil {

    //编码，一般固定用UTF-8就行
    public final static String encoding = "UTF-8";

    //版本号，从配置文件读
    public final static String version = SDKConfig.getConfig().getVersion();

    //后台服务对应的写法参照 FrontRcvResponse.java
    public final static String frontUrl = SDKConfig.getConfig().getFrontUrl();

    //后台服务对应的写法参照 BackRcvResponse.java
    public final static String backUrl = SDKConfig.getConfig().getBackUrl();//受理方和发卡方自选填写的域[O]--后台通知地址

    // 商户发送交易时间 格式:yyyyMMddHHmmss
    public static String getTxnTime() {
        return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
    }

    private static AtomicInteger orderIdCounter = new AtomicInteger(0);
    
	private static String generateSerial(){
        return String.format("%06d", orderIdCounter.getAndIncrement() % 1000000);
    }

    // AN8..40 商户订单号，不能含"-"或"_"
    public static String getOrderId() {
        return getTxnTime() + generateSerial();
    }
    
    public static String getReqId() {
        return getTxnTime() + generateSerial();
    }

    public static String getRandomString() {
        return getRandomString(10);
    }

    public static String getRandomString(int length) {

        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();

    }

    /**
     * 组装请求，返回报文字符串用于显示
     *
     * @param data
     * @return
     */
    public static String getPrintMapWithLf(Map<String, String> data) {
    	if(data == null) return "";

        TreeMap<String, String> tree = new TreeMap<String, String>();
        Iterator<Entry<String, String>> it = data.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, String> en = it.next();
            tree.put(en.getKey(), en.getValue());
        }
        it = tree.entrySet().iterator();
        StringBuffer sf = new StringBuffer();
        while (it.hasNext()) {
            Entry<String, String> en = it.next();
            String key = en.getKey();
            String value = en.getValue();
            sf.append(key + SDKConstants.EQUAL + value + "\n");
        }
        return sf.toString();
    }

    /**
     * 组装请求，返回报文字符串用于显示
     *
     * @param data
     * @return
     */
    public static String genHtmlResult(Map<String, String> data) {

        TreeMap<String, String> tree = new TreeMap<String, String>();
        Iterator<Entry<String, String>> it = data.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, String> en = it.next();
            tree.put(en.getKey(), en.getValue());
        }
        it = tree.entrySet().iterator();
        StringBuffer sf = new StringBuffer();
        while (it.hasNext()) {
            Entry<String, String> en = it.next();
            String key = en.getKey();
            String value = en.getValue();
            if ("respCode".equals(key)) {
                sf.append("<b>" + key + SDKConstants.EQUAL + escapeHtmlAndReplaceLfCr(value) + "</br></b>");
            } else
                sf.append(key + SDKConstants.EQUAL + escapeHtmlAndReplaceLfCr(value) + "</br>");
        }
        return sf.toString();
    }

    /**
     * 功能：解析全渠道商户对账文件中的ZM文件并以List<Map>方式返回
     * 适用交易：对账文件下载后对文件的查看
     *
     * @param filePath ZM文件全路径
     * @return 包含每一笔交易中 序列号 和 值 的map序列
     */
    public static List<Map<Integer, String>> parseZMFile(String filePath) {
        int lengthArray[] = {3, 11, 11, 6, 10, 19, 12, 4, 2, 21, 2, 32, 2, 6, 10, 13, 13, 4, 15, 2, 2, 6, 2, 4, 32, 1, 21, 15, 1, 15, 32, 13, 13, 8, 32, 13, 13, 12, 2, 1, 32, 98};
        return parseFile(filePath, lengthArray);
    }

    /**
     * 功能：解析全渠道商户对账文件中的ZME文件并以List<Map>方式返回
     * 适用交易：对账文件下载后对文件的查看
     *
     * @param filePath ZME文件全路径
     * @return 包含每一笔交易中 序列号 和 值 的map序列
     */
    public static List<Map<Integer, String>> parseZMEFile(String filePath) {
        int lengthArray[] = {3, 11, 11, 6, 10, 19, 12, 4, 2, 2, 6, 10, 4, 12, 13, 13, 15, 15, 1, 12, 2, 135};
        return parseFile(filePath, lengthArray);
    }

    /**
     * 功能：解析全渠道商户 ZM,ZME对账文件
     *
     * @param filePath
     * @param lengthArray 参照《全渠道平台接入接口规范 第3部分 文件接口》 全渠道商户对账文件 6.1 ZM文件和6.2 ZME 文件 格式的类型长度组成int型数组
     * @return
     */
    private static List<Map<Integer, String>> parseFile(String filePath, int lengthArray[]) {
        List<Map<Integer, String>> ZmDataList = new ArrayList<Map<Integer, String>>();
        try {
            String encoding = "gbk"; //文件是gbk编码
            File file = new File(filePath);
            if (file.isFile() && file.exists()) { //判断文件是否存在
                InputStreamReader read = new InputStreamReader(
                        new FileInputStream(file), "iso-8859-1");
                BufferedReader bufferedReader = new BufferedReader(read);
                String lineTxt = null;
                while ((lineTxt = bufferedReader.readLine()) != null) {
                    byte[] bs = lineTxt.getBytes("iso-8859-1");
                    //解析的结果MAP，key为对账文件列序号，value为解析的值
                    Map<Integer, String> ZmDataMap = new LinkedHashMap<Integer, String>();
                    //左侧游标
                    int leftIndex = 0;
                    //右侧游标
                    int rightIndex = 0;
                    for (int i = 0; i < lengthArray.length; i++) {
                        rightIndex = leftIndex + lengthArray[i];
                        String filed = new String(Arrays.copyOfRange(bs, leftIndex, rightIndex), encoding);
                        leftIndex = rightIndex + 1;
                        ZmDataMap.put(i, filed);
                    }
                    ZmDataList.add(ZmDataMap);
                }
                read.close();
            } else {
                System.out.println("找不到指定的文件");
            }
        } catch (Exception e) {
            System.out.println("读取文件内容出错");
            e.printStackTrace();
        }

        return ZmDataList;
    }

    public static String getFileContentTable(List<Map<Integer, String>> dataList, String file) {
        StringBuffer tableSb = new StringBuffer("对账文件的规范参考 https://open.unionpay.com/ajweb/help/file/ 产品接口规范->平台接口规范:文件接口</br> 文件【" + file + "】解析后内容如下：");
        tableSb.append("<table border=\"1\">");
//        if (dataList.size() > 0) {
//            Map<Integer, String> dataMapTmp = dataList.get(0);
//            tableSb.append("<tr>");
//            for (Iterator<Integer> it = dataMapTmp.keySet().iterator(); it.hasNext(); ) {
//                Integer key = it.next();
//                String value = dataMapTmp.get(key);
//                System.out.println("序号：" + (key + 1) + " 值: '" + value + "'");
//                tableSb.append("<td>序号" + (key + 1) + "</td>");
//            }
//            tableSb.append("</tr>");
//        }

        for (int i = 0; i < dataList.size(); i++) {
            System.out.println("行数: " + (i + 1));
            Map<Integer, String> dataMapTmp = dataList.get(i);
            tableSb.append("<tr>");
            for (Iterator<Integer> it = dataMapTmp.keySet().iterator(); it.hasNext(); ) {
                Integer key = it.next();
                String value = dataMapTmp.get(key);
                System.out.println("序号：" + (key + 1) + " 值: '" + value + "'");
                tableSb.append("<td>" + value + "</td>");
            }
            tableSb.append("</tr>");
        }
        tableSb.append("</table>");
        return tableSb.toString();
    }

    public static String getFileContentTableSimple(List<Map<Integer, String>> dataList, String file) {
        StringBuffer tableSb = new StringBuffer("对账文件的规范参考 https://open.unionpay.com/ajweb/help/file/ 产品接口规范->平台接口规范:文件接口 \n文件【" + file + "】内交易类型和订单号字段解析后内容如下（读取方式请参考demo代码）：\n");

        for (int i = 0; i < dataList.size(); i++) {
            Map<Integer, String> dataMapTmp = dataList.get(i);
            tableSb.append("第" + (i + 1) + "行：交易类型=" + dataMapTmp.get(19) + "，订单号=" + dataMapTmp.get(11) + "\n");
        }

        return tableSb.toString();
    }

    public static List<String> unzip(String zipFilePath, String outPutDirectory) {
        List<String> fileList = new ArrayList<String>();
        try {
            ZipInputStream zin = new ZipInputStream(new FileInputStream(zipFilePath));//输入源zip路径  
            BufferedInputStream bin = new BufferedInputStream(zin);
            BufferedOutputStream bout = null;
            File file = null;
            ZipEntry entry;
            try {
                while ((entry = zin.getNextEntry()) != null && !entry.isDirectory()) {
                    file = new File(outPutDirectory, entry.getName());
                    if (!file.exists()) {
                        (new File(file.getParent())).mkdirs();
                    }
                    bout = new BufferedOutputStream(new FileOutputStream(file));
                    int b;
                    while ((b = bin.read()) != -1) {
                        bout.write(b);
                    }
                    bout.flush();
                    fileList.add(file.getAbsolutePath());
                    System.out.println(file + "解压成功");
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    bin.close();
                    zin.close();
                    if (bout != null) {
                        bout.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return fileList;
    }

    public static Map<String, Object> unwarpJson(JSONObject jsonObject) {
        Map<String, Object> result = new HashMap<String, Object>();
        for (@SuppressWarnings("unchecked")
		Iterator<String> it = jsonObject.keys(); it.hasNext(); ) {
            String key = it.next();
            Object value = jsonObject.opt(key);
            if (value instanceof JSONArray) {
                result.put(key, unwarpJson((JSONArray) value));
            } else if (value instanceof JSONObject) {
                result.put(key, unwarpJson((JSONObject) value));
            } else {
                result.put(key, value);
            }
        }
        return result;
    }

    public static LinkedList<Object> unwarpJson(JSONArray jsonArray) {
        LinkedList<Object> result = new LinkedList<Object>();
        for(int i = 0; i < jsonArray.length(); i++){
            Object value = jsonArray.opt(i);
            if (value instanceof JSONArray) {
                result.add(unwarpJson((JSONArray) value));
            } else if (value instanceof JSONObject) {
                result.add(unwarpJson((JSONObject) value));
            } else {
                result.add(value);
            }
        }
        return result;
    }
	
	public static String escapeHtml(String str){
		return str
				.replace("&", "&amp;") //&必须最前面顺序不可换
				.replace("\"", "&quot;")
				.replace("<", "&lt;")
				.replace(">", "&gt;")
				.replace(" ", "&nbsp;");
	}
	
	public static String escapeHtmlAndReplaceLfCr(String str){
		return escapeHtml(str)
				.replace("\r\n", "\n")
				.replace("\r", "\n")
				.replace("\n", "<br>");
	}
}