package com.huigou.bpm.webservice.common;

import com.huigou.cache.SystemCache;
import com.huigou.exception.ApplicationException;
import com.huigou.uasp.log4j.interceptor.Log4jLoggingInInterceptor;
import com.huigou.uasp.log4j.interceptor.Log4jLoggingOutInterceptor;
import com.huigou.util.ClassHelper;
import com.huigou.util.DateUtil;
import com.huigou.util.StringUtil;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.log4j.Logger;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 创建接口调用对象
 * 
 * @author xiexin
 */
public abstract class SapWsProxyFactoryCreater {
    public static final Logger logger = Logger.getLogger("cxf.loggingInInterceptor");

    public static final int CXF_CLIENT_CONNECT_TIMEOUT = 10 * 1000;

    public static final int CXF_CLIENT_RECEIVE_TIMEOUT = 30 * 1000;

    private static LoggingInInterceptor inInterceptor;

    private static LoggingOutInterceptor outInterceptor;

    private static LoggingInInterceptor getLoggingInInterceptor() {
        if (inInterceptor == null) {
            Log4jLoggingInInterceptor log4jLoggingInInterceptor = new Log4jLoggingInInterceptor();
            log4jLoggingInInterceptor.setLoggerName("cxf.loggingInInterceptor");
            inInterceptor = log4jLoggingInInterceptor;
        }
        return inInterceptor;
    }

    private static LoggingOutInterceptor getLoggingOutInterceptor() {
        if (outInterceptor == null) {
            Log4jLoggingOutInterceptor log4jOutInterceptor = new Log4jLoggingOutInterceptor();
            log4jOutInterceptor.setLoggerName("cxf.loggingOutInterceptor");
            outInterceptor = log4jOutInterceptor;
        }
        return outInterceptor;
    }

    @SuppressWarnings("unchecked")
    public <T> T create(String url, Class<T> cls) {
        String sapUrl = SystemCache.getParameter("sap.ws.service.url", String.class);
        if (StringUtil.isBlank(sapUrl)) {
            sapUrl = "http://10.15.65.151:8000/sap";
        }
        JaxWsProxyFactoryBean clientFactory = new JaxWsProxyFactoryBean();

        clientFactory.getInInterceptors().add(getLoggingInInterceptor());
        clientFactory.getOutInterceptors().add(getLoggingOutInterceptor());
        // 获取SAP服务器系统号
        String sapClient = SystemCache.getParameter("sap.ws.service.client", String.class);
        if (StringUtil.isBlank(sapClient)) {
            sapClient = "600";
        }
        clientFactory.setAddress(sapUrl + String.format(url, sapClient));
        clientFactory.setServiceClass(cls);
        // 对去参数中
        String username = SystemCache.getParameter("sap.ws.security.username", String.class);
        String password = SystemCache.getParameter("sap.ws.security.password", String.class);
        if (StringUtil.isBlank(username)) {
            username = "bpm";
        }
        if (StringUtil.isBlank(password)) {
            password = "bpm123456";
        }
        clientFactory.setUsername(username);
        clientFactory.setPassword(password);
        // 创建服务
        T t = (T) clientFactory.create();
        // 设置超时时间
        Client proxy = ClientProxy.getClient(t);
        HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
        HTTPClientPolicy policy = new HTTPClientPolicy();
        policy.setConnectionTimeout(CXF_CLIENT_CONNECT_TIMEOUT);
        policy.setReceiveTimeout(CXF_CLIENT_RECEIVE_TIMEOUT);
        conduit.setClient(policy);
        return t;
    }

    /**
     * 对象转换为map
     * 
     * @param obj
     * @return
     */
    public Map<String, Object> toMap(Object obj) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = ClassHelper.toMap(obj);
        Map<String, Object> newMap = new HashMap<String, Object>(map.size());
        for (String key : map.keySet()) {
            newMap.put(StringUtil.getHumpName(key), map.get(key));
        }
        map = null;
        return newMap;
    }

    /**
     * 转换为list map
     * 
     * @param list
     * @return
     */
    public List<Map<String, Object>> toListMap(List<?> list) {
        if (list == null || list.size() == 0) {
            return new ArrayList<>();
        }
        List<Map<String, Object>> newList = new ArrayList<Map<String, Object>>(list.size());
        for (Object obj : list) {
            newList.add(this.toMap(obj));
        }
        return newList;
    }

    /**
     * 转换为list map 增加日期格式转换
     * 
     * @param list
     * @param fields
     * @return
     */
    public List<Map<String, Object>> toListMapAndChangeDate(List<?> list, String... fields) {
        if (list == null || list.size() == 0) {
            return new ArrayList<>();
        }
        List<Map<String, Object>> newList = new ArrayList<Map<String, Object>>(list.size());
        String dateStr = "";
        for (Object obj : list) {
            Map<String, Object> map = this.toMap(obj);
            if (fields != null && fields.length > 0) {
                for (String field : fields) {
                    dateStr = ClassHelper.convert(map.get(field), String.class, "");
                    map.put(field, this.getDateStr(dateStr));
                }
            }
            newList.add(map);
        }
        return newList;
    }

    /**
     * 根据map数据初始化对象 将字段名称转换为小写，同时将字段转换为String 再进行复制
     * 
     * @param cls
     * @param param
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T> T getObject(Class<T> cls, Map<String, Object> param) {
        Map<String, Object> map = new HashMap<String, Object>(param.size());
        for (String key : param.keySet()) {
            map.put(key.toLowerCase(), param.get(key));
        }
        try {
            Object obj = cls.newInstance();
            List<Field> fields = ClassHelper.getDeclaredAndInheritedFields(obj);
            String name = null;
            for (Field field : fields) {
                name = field.getName();
                if (map.containsKey(name)) {
                    field.setAccessible(true);
                    field.set(obj, ClassHelper.convert(map.get(name), String.class, ""));
                }
            }
            return (T) obj;
        } catch (InstantiationException e) {
            throw new ApplicationException(e);
        } catch (IllegalAccessException e) {
            throw new ApplicationException(e);
        }
    }

    /**
     * 根据map数据完全初始化对象
     * 字段和类型都需要相同
     *
     * @param cls
     * @param param
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T> T getObjectAll(Class<T> cls, Map<String, Object> param) {
        try {
            Object obj = cls.newInstance();
            List<Field> fields = ClassHelper.getDeclaredAndInheritedFields(obj);
            String name = null;
            for (Field field : fields) {
                name = field.getName();
                if (param.containsKey(name)) {
                    field.setAccessible(true);
                    field.set(obj, ClassHelper.convert(param.get(name), field.getType()));
                }
            }
            return (T) obj;
        } catch (InstantiationException e) {
            throw new ApplicationException(e);
        } catch (IllegalAccessException e) {
            throw new ApplicationException(e);
        }
    }

    /**
     * 根据map数组对象数据初始化对象列表
     * 
     * @param cls
     * @param list
     * @return
     */
    public <T> List<T> getObjectList(Class<T> cls, List<Map<String, Object>> list) {
        List<T> beanList = new ArrayList<>();
        if (list != null && list.size() > 0) {
            for (Map<String, Object> m : list) {
                beanList.add(this.getObject(cls, m));
            }
        }
        return beanList;
    }

    /**
     * 解析日期格式
     * 
     * @param dateStr
     * @return
     */
    public Date getDateByStr(String dateStr) {
        Date date = null;
        if (StringUtil.isNotBlank(dateStr)) {
            SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
            try {
                date = df.parse(dateStr);
            } catch (ParseException e) {

            }
        }
        return date;
    }

    /**
     * 解析日期格式
     * 
     * @param dateStr
     * @return
     */
    public String getDateStr(String dateStr) {
        Date date = this.getDateByStr(dateStr);
        if (date != null) {
            return DateUtil.getDateFormat(date);
        }
        return "";
    }

    /**
     * 解析日期格式
     * 
     * @param date
     * @return
     */
    public String getDateStr(Date date) {
        return DateUtil.getDateFormat(date, "yyyyMMdd");
    }

}