package com.sagacloud.dict;

/*
 * Author: Jxing
 * Create Time: 2017/8/25
 */

import com.sagacloud.exception.WrongInfosException;
//import com.sagacloud.json.JSONArray;
//import com.sagacloud.json.JSONObject;
//import com.sagacloud.json.JSONValue;
import com.alibaba.fastjson.*;
import com.sagacloud.utils.*;
import com.sagacloud.utils.objects.CommonQueryCriteria;
import com.sagacloud.utils.objects.ObjectIdName;
import com.sagacloud.utils.objects.ObjectType;
import com.sagacloud.utils.jsonHelper.infoPoint.InfoPoint;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.sagacloud.utils.Const.OBJ_TYPE_EQUIPMENT_COMPONENT;

public class InfosUtil {
    // 删除信息点的时候能删除Name 和 CreateTime吗?

    static {
        try {
            loadVOInfos();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static Map<String, HashMap<String, InfoPoint>> cache_VO = new ConcurrentHashMap<>();
    private static final String INFOPOINT_CODE = "infoPointCode";
    private static final String INFOPOINT_NAME = "infoPointName";
    private static ArrayList<String> additonalInfos = CommonUtil.createArrayList("RoomName", "EquipName", "SysName", "FloorName", "ProjName", "BuildName", "CompName", "ShaftName", "ConsumName", "ToolName"); //, "CreateTime");
    private static ArrayList<String> additonalIDInfos = CommonUtil.createArrayList("RoomID", "EquipID", "SysID", "FloorID", "ProjID", "BuildID", "CompID", "ShaftID", "ConsumID", "ToolID"); //, "CreateTime");

    public static Map<String, HashMap<String, InfoPoint>> getVOCache(){
        if(cache_VO.isEmpty()){
            synchronized (cache_VO){
                if(cache_VO.isEmpty()){
                    try {
                        loadVOInfos();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return cache_VO;
    }

    public static String getInfoLocalName(String obj_type){
        switch (obj_type.substring(0,2))
        {
            case Const.OBJ_TYPE_PROJECT:
                return additonalInfos.get(4);
            case Const.OBJ_TYPE_SYSTEM:
                return additonalInfos.get(2);
            case Const.OBJ_TYPE_SPACE:
            case Const.OBJ_TYPE_ISPACE:
                return additonalInfos.get(0);
            case Const.OBJ_TYPE_EQUIPMENT:
            case Const.OBJ_TYPE_PROPERTY:
            case OBJ_TYPE_EQUIPMENT_COMPONENT:
                return additonalInfos.get(1);
            case Const.OBJ_TYPE_FLOOR:
                return additonalInfos.get(3);
            case Const.OBJ_TYPE_BUILDING:
                return additonalInfos.get(5);
            case Const.OBJ_TYPE_VERTICAL_SHAFT:
                return additonalInfos.get(7);
            default:
                return "Name";
        }
    }
    public static String getInfoLocalId(String obj_type){
        switch (obj_type.substring(0,2))
        {
            case Const.OBJ_TYPE_PROJECT:
                return additonalIDInfos.get(4);
            case Const.OBJ_TYPE_SYSTEM:
                return additonalIDInfos.get(2);
            case Const.OBJ_TYPE_SPACE:
            case Const.OBJ_TYPE_ISPACE:
                return additonalIDInfos.get(0);
            case Const.OBJ_TYPE_EQUIPMENT:
            case Const.OBJ_TYPE_PROPERTY:
            case OBJ_TYPE_EQUIPMENT_COMPONENT:
                return additonalIDInfos.get(1);
            case Const.OBJ_TYPE_FLOOR:
                return additonalIDInfos.get(3);
            case Const.OBJ_TYPE_BUILDING:
                return additonalIDInfos.get(5);
            case Const.OBJ_TYPE_VERTICAL_SHAFT:
                return additonalIDInfos.get(7);
            case Const.OBJ_TYPE_CONSUMABLE:
                return additonalIDInfos.get(8);
            case Const.OBJ_TYPE_TOOL:
                return additonalIDInfos.get(9);
            default:
                return "ID";
        }
    }
    private static void loadVOInfos() throws Exception {
        Map<String, HashMap<String, InfoPoint>> cache_tmp = new ConcurrentHashMap<>();
        JSONObject vo = JSONObject.parseObject(OssUtils.getFileAsString(InfoCodeUtil.VOPath));
        for(String key: vo.keySet())
        {
            JSONArray infos = (JSONArray) vo.get(key);
            HashMap<String, InfoPoint> allInfoPoint = new HashMap<>();
            for(int i = 0 ; i < infos.size(); ++i)
            {
                JSONObject singleInfo = (JSONObject) infos.get(i);
                if(singleInfo.containsKey(INFOPOINT_CODE) && singleInfo.containsKey(INFOPOINT_NAME)) {
                    InfoPoint ip = new InfoPoint();
                    ip.setInfoPointCode(singleInfo.get(INFOPOINT_CODE).toString());
                    ip.setInfoPointName(singleInfo.get(INFOPOINT_NAME).toString());
                    allInfoPoint.put(singleInfo.get(INFOPOINT_CODE).toString(), ip);
                }
            }
            cache_tmp.put(key, allInfoPoint);
        }
        cache_VO = cache_tmp;
    }
    public static void clearCache()
    {
        cache_VO.clear();
    }
    // 返回不存在的信息点名称, 返回null表示成功
    // detailedType 为2位或4位的设备, 系统, 虚拟对象编码. jsonData为信息点集合, namePrefix是各种Name的前缀
    public static String CheckIntegrityAtCreation(String pjId, ObjectType type, String detailedType, JSONObject jsonData, String realId, ObjectIdName name) throws Exception {
        String result =checkIntegrity(pjId, type, detailedType, jsonData, new CommonQueryCriteria());
        if(result== null)
        {
            // 添加上Name 和 CreateTime
            if (addIdName(pjId, type, detailedType, jsonData, realId, name)) return null;
//            timeNode.put("time", time);
//            timeNode.put("value", time);
//            timeArr.add(timeNode);
//            jsonData.put(Const.JSON_FIELD_CTEATE_TIME, timeArr);
        }
        return result;
    }

    public static boolean addIdName(String pjId, ObjectType type, String detailedType, JSONObject jsonData, String realId, ObjectIdName name) {
        StringBuilder sb = new StringBuilder();
        StringBuilder si = new StringBuilder();
        JSONArray nameArr = new JSONArray();
        JSONArray idArr = new JSONArray();
        JSONObject nameNode = new JSONObject();
        JSONObject idNode = new JSONObject();
        String time = CommonUtil.getTime();
        String chineseName = null;
        EqStaticInfo eqStaticInfo = new EqStaticInfo(pjId);
        switch (type)
        {
            case ispace:
                name.setNameKey(additonalInfos.get(0));
                si.append("RoomID");
                sb.append(additonalInfos.get(0));
                chineseName = "元空间";
                break;
            case space:
                name.setNameKey(additonalInfos.get(0));
                si.append("RoomID");
                sb.append(additonalInfos.get(0));
                chineseName = "空间";
                break;
            case equipment:
                name.setNameKey(additonalInfos.get(1));
                si.append("EquipID");
                sb.append(additonalInfos.get(1));
                chineseName = eqStaticInfo.getCateToNameMap().get(detailedType);
                break;
            case system:
                name.setNameKey(additonalInfos.get(2));
                si.append("SysID");
                sb.append(additonalInfos.get(2));
                chineseName = eqStaticInfo.getCateToNameMap().get(detailedType);
                break;
            case floor:
                name.setNameKey(additonalInfos.get(3));
                si.append("FloorID");
                sb.append(additonalInfos.get(3));
                chineseName = "楼层";
                break;
            case shaft:
                name.setNameKey(additonalInfos.get(7));
                si.append("ShaftID");
                sb.append(additonalInfos.get(7));
                chineseName = "竖井";
                break;
            case project:
                name.setNameKey(additonalInfos.get(4));
                si.append("ProjID");
                sb.append(additonalInfos.get(4));
                chineseName = String.join("", GeoStaticInfo.codeToNameMap.get(pjId.substring(0, 6)), realId.substring(8), "项目");
                break;
            case building:
                name.setNameKey(additonalInfos.get(5));
                si.append("BuildID");
                sb.append(additonalInfos.get(5));
                chineseName = "建筑";
                break;
            case component:
                name.setNameKey(additonalInfos.get(1));
                si.append("EquipID");
                sb.append(additonalInfos.get(1));
                chineseName = eqStaticInfo.getCateToNameMap().get(detailedType);
                break;
            case consumable:
                name.setNameKey(additonalInfos.get(8));
                si.append("ConsumID");
                sb.append(additonalInfos.get(8));
                chineseName = CsStaticInfo.getCode2name().get(detailedType);
                break;
            case tool:
                name.setNameKey(additonalInfos.get(9));
                si.append("ToolID");
                sb.append(additonalInfos.get(9));
                chineseName = TlStaticInfo.getCode2name().get(detailedType);
                break;
            case VOBd:
                si.append("BuildID");
                sb.append(additonalInfos.get(0));
                break;
            case VO:
                //TODO 根据具体vo类型添加不同id，后续可能删除EquipID
                switch (detailedType){
                    case Const.OBJ_TYPE_VOSe:
                        si.append("SubentryID");
                        break;
                    case Const.OBJ_TYPE_VOTn:
                        si.append("TenantID");
                        break;
                    case Const.OBJ_TYPE_VOZn:
                        si.append("ZoneID");
                        break;
                    case Const.OBJ_TYPE_VOGp:
                        si.append("GroupID");
                        break;
                    case Const.OBJ_TYPE_VOCt:
                        si.append("ControlID");
                        break;
                    case Const.OBJ_TYPE_VOBc:
                        si.append("BeaconID");
                        break;
                    case Const.OBJ_TYPE_VOSc:
                        si.append("SubentryID");
                        break;
                    case Const.OBJ_TYPE_VOSh:
                        si.append("SubentryID");
                        break;
                    case Const.OBJ_TYPE_VOSw:
                        si.append("SubentryID");
                        break;
                    case Const.OBJ_TYPE_VOSg:
                        si.append("SubentryID");
                        break;
                    case Const.OBJ_TYPE_VOSf:
                        si.append("SubentryID");
                        break;
                    case Const.OBJ_TYPE_VOSv:
                        si.append("SubentryID");
                        break;
                    case Const.OBJ_TYPE_VOMt:
                        si.append("MeterID");
                        break;
                    case Const.OBJ_TYPE_VOBr:
                        si.append("BranchID");
                        break;
                    default:
                        si.append("EquipID");
                }
//                    si.append("EquipID");
                break;
            default:
                return true;
        }
        if(!jsonData.containsKey(si.toString())) {
            idNode.put("time", time);
            idNode.put("value", realId);
            idArr.add(idNode);
            jsonData.put(si.toString(), idArr);
        }
        if(sb.length() != 0 && chineseName != null){
            nameNode.put("time", time);
            nameNode.put("value", type.equals(ObjectType.project)? chineseName:String.join("-", chineseName, CommonMethods.generateRandomId(CommonMethods.idCharArr, CommonMethods.idLength)));
            nameArr.add(nameNode);
            if(!jsonData.containsKey(sb.toString()) || ((JSONArray)jsonData.get(sb.toString())).size() == 0) {
                jsonData.put(sb.toString(), nameArr);
                name.setNameValue(nameNode.get("value").toString());
            }else {
                JSONArray values = (JSONArray) jsonData.get(sb.toString());
                JSONObject singleInfo = (JSONObject) values.get(0);
                name.setNameValue((String)singleInfo.get("value"));
            }
        }

        name.setCreateTime(time);
        return false;
    }

    // 返回不存在的信息点名称, 返回null表示成功
    // VO 是 虚拟对象的类型, VOBd, VOCu, VOEi之类
    public static String checkIntegrity(String pjId, ObjectType type, String detailedType, JSONObject jsonData, CommonQueryCriteria cqc) throws Exception {
        if(type == null)
            throw new WrongInfosException("信息点名称错误!");
        HashMap<String, HashMap<String, InfoPoint>> allTypesList = null;
        HashMap<String, InfoPoint> list = null;
//        if(TypeToInfosMap.cache.size() == 0)
//            TypeToInfosMap.synCache();
        getVOCache();
        switch (type)
        {
            case building:
            case project:
            case floor:
            case shaft:
            case ispace:
//                list = TypeToInfosMap.get(type.name());
                allTypesList = InfoCodeUtil.getWholeInfosWithCustomMap(pjId, type.name());
                break;
            case space:
            case system:
            case equipment:
//                list = TypeToInfosMap.get(detailedType);
//                general = TypeToInfosMap.get(type.equals(ObjectType.system)? "sy-gen":"eq-gen");
                allTypesList = InfoCodeUtil.getWholeInfosWithCustomMap(pjId, detailedType);
                break;
            case VO:
                list = cache_VO.get(detailedType);
                list.putAll(InfoCodeUtil.getCustomInfosMap(pjId.replace("Pj", ""), detailedType).get(detailedType));
                break;
            case VOBd: // 虚拟建筑跟正常建筑一类
                allTypesList = InfoCodeUtil.getWholeInfosWithCustomMap(pjId, ObjectType.building.name());
//                list = TypeToInfosMap.get(ObjectType.building.name());
                break;
            case component:
                allTypesList = InfoCodeUtil.getWholeInfosWithCustomMap(pjId, detailedType);
//                list = TypeToInfosMap.get(detailedType);
//                general = TypeToInfosMap.get("ec-gen");
                break;
            case property:
                list = InfoCodeUtil.getWholeCommonInfosMap(pjId, detailedType);
                break;
            case consumable:
                allTypesList = InfoCodeUtil.getWholeInfosWithCustomMap(pjId, detailedType);
                break;
            case tool:
                allTypesList = InfoCodeUtil.getWholeInfosWithCustomMap(pjId, detailedType);
                break;
        }
        if(allTypesList != null) {
            for (String typeName : allTypesList.keySet()) {
                list = allTypesList.get(typeName);
                break;
            }
        }
        if(list == null)
            throw new Exception("服务器加载信息点出错");
        Iterator<String> it = jsonData.keySet().iterator();
        while (it.hasNext()){
            String key = it.next();
            if(!list.containsKey(key))
            {
                if(EqStaticInfo.propertyGeneralInfos.contains(key))
                    continue;
                if(cqc.isSkipErrorInfo()){
                    it.remove();
                }else
                    return key;
            }
        }
        return null;
    }


}
