package com.huigou.bpm.webservice.utils;

import com.sap.conn.jco.*;
import com.sap.conn.jco.rt.DefaultTable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class SapJcoUtils {

    public static Map<String,Object> list2Map(JCoParameterList parameterList){
        Map<String,Object> map = new HashMap<String,Object>();
        if(parameterList==null){
            return map;
        }
        int fieldCount = parameterList.getFieldCount();
        if(fieldCount>0){
            JCoFieldIterator iterator = parameterList.getFieldIterator();
            while (iterator.hasNextField()){
                JCoField field =iterator.nextField();

                Object value = field.getValue();
                if(value instanceof JCoTable){
                    List<Map<String,Object>> valueList = table2ListMap((JCoTable) value);
                    map.put(field.getName(),valueList);
                }else if(value instanceof JCoStructure){
                    Map<String,Object> valueMap = toMap((JCoStructure)value);
                    map.put(field.getName(),valueMap);
                }else{
                    map.put(field.getName(),field.getValue());
                }
            }
        }
        return map;
    }

    private static List<Map<String,Object>> table2ListMap(JCoTable table){
        List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
        if(table.getNumRows()>0){
            list.add(toMap(table));
            while (table.nextRow()){
                list.add(toMap(table));
            }
        }
        return list;
    }

    private static Map<String,Object> toMap(JCoStructure data){
        Map<String,Object> map = new HashMap<>();
        int fieldCount = data.getFieldCount();
        if(fieldCount==0){
            JCoRecordFieldIterator fieldIterator =data.getRecordFieldIterator();
            while(fieldIterator.hasNextField()){
                JCoRecordField field = fieldIterator.nextRecordField();
                Object value = field.getValue();
                if(value instanceof JCoStructure){
                    Map<String,Object> valueMap = toMap((JCoStructure)value);
                    map.put(field.getName(),valueMap);
                }else{
                    map.put(field.getName(),value);
                }
            }
        }
        return map;
    }

    private static Map<String,Object> toMap(JCoTable table){
        Map<String,Object> map = new HashMap<String,Object>();
        JCoFieldIterator iterator =table.getFieldIterator();
        while (iterator.hasNextField()){
            JCoField field =iterator.nextField();
            Object value = field.getValue();
            if(value instanceof JCoStructure){
                Map<String,Object> valueMap = toMap((JCoStructure)value);
                map.put(field.getName(),valueMap);
            }else{
                map.put(field.getName(),value);
            }
        }
        return map;
    }

    private static Map<String,Object> toMap(JCoMetaData metaData){
        Map<String,Object> map = new HashMap<>();
        int fieldCount = metaData.getFieldCount();
        if(fieldCount==0){
            return null;
        }
        return map;
    }

    public static void fromMap(JCoStructure structure,Map<String,Object> map){
        JCoRecordFieldIterator iterator = structure.getRecordFieldIterator();
        while(iterator.hasNextField()){
            JCoRecordField field = iterator.nextRecordField();
            if(field.getValue() instanceof JCoStructure){
                fromMap((JCoStructure)field.getValue(),(Map)map.get(field.getName()));
            }else {
                field.setValue(map.get(field.getName()));
            }
        }
    }

    public static void fromMap(JCoTable table,List<Map<String,Object>> list){
        JCoRecordFieldIterator iterator = table.getRecordFieldIterator();
        if(list!=null&&list.size()>0){
            for(Map<String,Object> map : list){
                table.appendRow();
                while(iterator.hasNextField()){
                    JCoRecordField field = iterator.nextRecordField();
                    if(field.getValue() instanceof JCoStructure){
                        fromMap((JCoStructure)field.getValue(),(Map)map.get(field.getName()));
                    }else {
                        field.setValue(map.get(field.getName()));
                    }
                }
            }
        }
    }

    public static void fromMap(JCoTable table,Map<String,Object> map){
        JCoRecordFieldIterator iterator = table.getRecordFieldIterator();
        if(map!=null){
            table.appendRow();
            while(iterator.hasNextField()){
                JCoRecordField field = iterator.nextRecordField();
                if(field.getValue() instanceof JCoStructure){
                    fromMap((JCoStructure)field.getValue(),(Map)map.get(field.getName()));
                }else {
                    field.setValue(map.get(field.getName()));
                }
            }
        }
    }

    public static Map<String,Object> toLocalMap(Map<String,Object> sapMap,Map<String,Object> ruleMap){
        Map<String,Object> result = new HashMap<>();
        sapMap = sapMap.entrySet().stream()
                .filter(e -> ruleMap.containsKey(e.getKey()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        for(String key:sapMap.keySet()){
            if(sapMap.get(key) instanceof List){
                List<Map<String,Object>> lists = (List)sapMap.get(key);
                List<Map<String,Object>> reLists = toLocalList(lists,ruleMap);
                result.put(String.valueOf(ruleMap.get(key)),reLists);
            }else if(sapMap.get(key) instanceof Map){
                Map<String,Object> map2 = (Map)sapMap.get(key);
                Map<String,Object> map = toLocalMap(map2,ruleMap);
                result.put(String.valueOf(ruleMap.get(key)),map);
            }else{
                if(ruleMap.get(key)!=null){
                    result.put(String.valueOf(ruleMap.get(key)),sapMap.get(key));
                }/*else{
                    result.put(String.valueOf(ruleMap.get(key)),sapMap.get(key));
                }*/
            }
        }
        return result;
    }

    private static List<Map<String,Object>> toLocalList(List<Map<String,Object>> sapList,Map<String,Object> ruleMap){
        List<Map<String,Object>> list = new ArrayList<>(sapList.size());
        for(Map<String,Object> map: sapList){
            Map<String,Object> reMap = toLocalMap(map,ruleMap);
            list.add(reMap);
        }
        return list;
    }

    public static Map<String,Object> toSapMap(Map<String,Object> localmap,Map<String,Object> ruleMap){
        Map<String,Object> result = new HashMap<>();
        localmap = localmap.entrySet().stream()
                .filter(e -> ruleMap.containsKey(e.getKey()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        for(String key:localmap.keySet()){
            if(localmap.get(key) instanceof List){
                List<Map<String,Object>> lists = (List)localmap.get(key);
                List<Map<String,Object>> reLists = toSapList(lists,ruleMap);
                result.put(String.valueOf(ruleMap.get(key)),reLists);
            }else if(localmap.get(key) instanceof Map){
                Map<String,Object> map2 = (Map)localmap.get(key);
                Map<String,Object> map = toLocalMap(map2,ruleMap);
                result.put(String.valueOf(ruleMap.get(key)),map);
            }else{
                if(ruleMap.get(key)!=null){
                    result.put(ruleMap.get(key).toString(),localmap.get(key));
                }/*else{
                    result.put(String.valueOf(ruleMap.get(key)),localmap.get(key));
                }*/
            }
        }
        return result;
    }

    private static List<Map<String,Object>> toSapList(List<Map<String,Object>> localList,Map<String,Object> ruleMap){
        List<Map<String,Object>> list = new ArrayList<>(localList.size());
        for(Map<String,Object> map: localList){
            Map<String,Object> reMap = toLocalMap(map,ruleMap);
            list.add(reMap);
        }
        return list;
    }
}
