package com.sagacloud.endpoints;

import com.sagacloud.dict.EqStaticInfo;
import com.sagacloud.endpoints.tagset.ObjectTagCache;
import com.sagacloud.search.AllObjs;
import com.sagacloud.search.objs.*;
import com.sagacloud.utils.CommonUtil;
import com.sagacloud.utils.Const;
import com.sagacloud.utils.DpUtils;
import com.sagacloud.utils.jsonHelper.search.inforPointSearchResult.SearchResultObj;
import com.sagacloud.utils.jsonHelper.search.inforPointSearchResult.SearchResultType;
import com.sagacloud.utils.jsonHelper.search.searchInput.SearchInput;
import org.apache.htrace.fasterxml.jackson.databind.ObjectMapper;
import org.apache.htrace.fasterxml.jackson.databind.ObjectWriter;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Created by wo on 8/24/17.
 */
@Path("object")
public class ObjectSearch {
    private static final Logger log = LoggerFactory.getLogger(ObjectSearch.class);

    @Context
    private ResourceContext resourceContext;

    private AllObjs allObjs;

    private static Map<String, String> spFuncCode2name = new HashMap<>();

    @Path("/search")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String search(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
        ObjectMapper mapper = new ObjectMapper();
        SearchInput searchInput = null;
        projectId = projectId.substring(2, projectId.length());
        try {
            EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
            searchInput = mapper.readValue(jsonStr, SearchInput.class);
            allObjs  = AllObjs.get(projectId);
            List resultList = new ArrayList();
            if(searchInput.getCategory().contains("Eq")){
                resultList.addAll(searchEqOrSyClassByName(projectId, searchInput.getLimit() - resultList.size(), true, searchInput.getKeywords(), eqStaticInfo));
            }
            if(searchInput.getCategory().contains("Sy")){
                resultList.addAll(searchEqOrSyClassByName(projectId, searchInput.getLimit() - resultList.size(), false, searchInput.getKeywords(), eqStaticInfo));
            }
            if(searchInput.getCategory().contains("SpObj")){
                resultList.addAll(searchObjByName(projectId, searchInput.getLimit() - resultList.size(), "SpObj", searchInput, eqStaticInfo));
            }
            if(searchInput.getCategory().contains("FlObj")){
                resultList.addAll(searchObjByName(projectId, searchInput.getLimit() - resultList.size(), "FlObj", searchInput, eqStaticInfo));
            }
            if(searchInput.getCategory().contains("BdObj")){
                resultList.addAll(searchObjByName(projectId, searchInput.getLimit() - resultList.size(), "BdObj", searchInput, eqStaticInfo));
            }
            if(searchInput.getCategory().contains("EqObj")){
                resultList.addAll(searchObjByName(projectId, searchInput.getLimit() - resultList.size(), "EqObj", searchInput, eqStaticInfo));
            }
            if(searchInput.getCategory().contains("SyObj")){
                resultList.addAll(searchObjByName(projectId, searchInput.getLimit() - resultList.size(), "SyObj", searchInput, eqStaticInfo));
            }
            if(searchInput.getCategory().contains("ShObj")){
                resultList.addAll(searchObjByName(projectId, searchInput.getLimit() - resultList.size(), "ShObj", searchInput, eqStaticInfo));
            }
            Map map = new HashMap();
            map.put("Result","success");
            map.put("Count", resultList.size());
            map.put("Content", resultList);
            map.put("ResultMsg", "");

            ObjectWriter ow = new ObjectMapper().writer();
            String json = ow.writeValueAsString(map);
            return json;
        } catch (IOException e) {
            return DpUtils.errorJsonMsg(e.getMessage());
        }
    }

    private List searchEqOrSyClassByName(String pjId, int limit, boolean searchEq, List<String> keyWords, EqStaticInfo eqStaticInfo){
        List resultLst = new ArrayList();
        if(limit <= 0){
            return  resultLst;
        }
        int keyLenth = 2;
        String resultType = "Sy";
        if(searchEq){
            keyLenth = 4;
            resultType = "Eq";
        }
        for(String key : eqStaticInfo.getCateToNameMap().keySet()){
            if(key.length() != keyLenth){
                continue;
            }
            if(CommonUtil.isSearchHit(eqStaticInfo.getCateToNameMap().get(key), keyWords)){
                SearchResultType searchResultType = new SearchResultType();
                searchResultType.setType(resultType);
                searchResultType.setSys(key.substring(0,2));
                searchResultType.setSysName(eqStaticInfo.getCateToNameMap().get(key.substring(0,2)));
                searchResultType.setMajor(eqStaticInfo.getCateToMajorMap().get(key));
                searchResultType.setMajorName(eqStaticInfo.getMajorCodeToNameMap().get(searchResultType.getMajor()));
                if(keyLenth == 4){
                    searchResultType.setEq(key);
                    searchResultType.setEqName(eqStaticInfo.getCateToNameMap().get(key));
                }
                resultLst.add(searchResultType);

            }
        }
        if(resultLst.size() >= limit){
            resultLst.subList(limit, resultLst.size()).clear();
            return resultLst;
        }
        return resultLst;
    }

    private List searchObjByName(String pjId, int limit, String objType, SearchInput searchInput, EqStaticInfo eqStaticInfo) {
        List subResultLst = new ArrayList();
        if(limit <= 0){
            return  subResultLst;
        }
        Set<String> objTags = searchInput.getTagsByType(objType);
        for(String key : allObjs.getIdToObjMap().keySet()){
            if(!key.startsWith(objType.substring(0, 2))){
                continue;
            }
            if(!objTags.isEmpty()) {
            	Set<String> objHasTags = ObjectTagCache.getTagsByObjId(key);
            	if(objHasTags.isEmpty()) {
            		continue;
            	}else {
            		boolean hasTag = false;
            		for(String tag : objHasTags) {
            			if(objTags.contains(tag)) {
            				hasTag = true;
            				break;
            			}
            		}
            		if(!hasTag) {
            			continue;
            		}
            	}
            }
            if(searchInput.getIds() != null && !searchInput.getIds().isEmpty()){
                if(!searchInput.getIds().contains(key)){
                    continue;
                }
            }
            SearchViewBaseObj searchViewBaseObj = allObjs.getIdToObjMap().get(key);
            String searchName = null;
            if(searchViewBaseObj.getLocalName() == null) {
                if(searchViewBaseObj.getSysName() != null) {
                    searchName = searchViewBaseObj.getSysName().getValue();
                }
            }else {
                searchName = searchViewBaseObj.getLocalName().getValue();
            }

            List<String> searchKeywords = searchInput.getKeywords();
            boolean keywordsFilter = false;
            if(searchKeywords != null && !searchKeywords.isEmpty()) {
                keywordsFilter = true;
            }

            if(!keywordsFilter || CommonUtil.isSearchHit(searchName, searchKeywords)) {
                if (key.startsWith("Eq")) {
                    subResultLst.add(buildEqSearchResultObj(pjId, searchViewBaseObj, eqStaticInfo));
                }else if (key.startsWith("Sy")) {
                    subResultLst.add(buildSySearchResultObj(pjId, searchViewBaseObj, eqStaticInfo));
                }else if (key.startsWith("Sp")) {
                    subResultLst.add(buildSpSearchResultObj(searchViewBaseObj));
                }else if (key.startsWith("Fl")) {
                    subResultLst.add(buildFlSearchResultObj(searchViewBaseObj));
                }else if (key.startsWith("Bd")) {
                    subResultLst.add(buildBdSearchResultObj(searchViewBaseObj));
                }else if (key.startsWith("Sh")) {
                    subResultLst.add(buildShSearchResultObj(searchViewBaseObj));
                }
            }

            if(subResultLst.size() >= limit){
                subResultLst.subList(limit, subResultLst.size()).clear();
                return subResultLst;
            }
        }
        return subResultLst;
    }


    private SearchResultObj buildEqSearchResultObj(String pjId, SearchViewBaseObj searchViewBaseObj, EqStaticInfo eqStaticInfo){
        SVEqObj svEqObj = (SVEqObj)searchViewBaseObj;
        SearchResultObj searchResultObj = new SearchResultObj();
        searchResultObj.setType("EqObj");
        searchResultObj.setEqObj(svEqObj.getId());
        searchResultObj.setEqObjName(svEqObj.getLocalName() == null? svEqObj.getSysName().getValue() : svEqObj.getLocalName().getValue());
        searchResultObj.setEqObjLocalId(svEqObj.getLocalId().getValue());
        if (svEqObj.getSy() != null) {
            searchResultObj.setSysObj(svEqObj.getSy().getId());
            searchResultObj.setSysObjName(svEqObj.getSy().getLocalName() == null ? svEqObj.getSy().getSysName().getValue() : svEqObj.getSy().getLocalName().getValue());
            searchResultObj.setMajor(svEqObj.getSy().getMajorId());
            searchResultObj.setMajorName(svEqObj.getSy().getMajorName());
            searchResultObj.setSysObjLocalId(svEqObj.getSy().getLocalId().getValue());
        }
        if(svEqObj.getSp() != null){
            searchResultObj.setSpObj(svEqObj.getSp().getId());
            searchResultObj.setSpObjName(svEqObj.getSp().getLocalName()==null? svEqObj.getSp().getSysName().getValue() : svEqObj.getSp().getLocalName().getValue());
            searchResultObj.setSpObjLocalId(svEqObj.getSp().getLocalId().getValue());
            if(svEqObj.getSp().getFl() != null){
                searchResultObj.setFlObj(svEqObj.getSp().getFl().getId());
                searchResultObj.setFlObjName(svEqObj.getSp().getFl().getLocalName()==null? svEqObj.getSp().getFl().getSysName().getValue() : svEqObj.getSp().getFl().getLocalName().getValue());
                searchResultObj.setFlObjLocalId(svEqObj.getSp().getFl().getLocalId().getValue());
            }
        }
        if (svEqObj.getBd() != null) {           //数据异常时此处可能会空
            searchResultObj.setBdObj(svEqObj.getBd().getId());
            searchResultObj.setBdObjName(svEqObj.getBd().getLocalName() == null ? svEqObj.getBd().getSysName().getValue() : svEqObj.getBd().getLocalName().getValue());
            searchResultObj.setBdObjLocalId(svEqObj.getBd().getLocalId().getValue());
        }
        //设置设备类型
        searchResultObj.setEq(allObjs.getIdToSubtype().get(svEqObj.getId()));
        searchResultObj.setEqName(eqStaticInfo.getCateToNameMap().get(allObjs.getIdToSubtype().get(svEqObj.getId())));
        return searchResultObj;
    }

    private SearchResultObj buildSySearchResultObj(String pjId, SearchViewBaseObj searchViewBaseObj, EqStaticInfo eqStaticInfo){
        SVSyObj svSyObj = (SVSyObj)searchViewBaseObj;
        SearchResultObj searchResultObj = new SearchResultObj();
        searchResultObj.setType("SyObj" );

        searchResultObj.setSysObj(svSyObj.getId());
        searchResultObj.setSysObjName(svSyObj.getLocalName() == null ? svSyObj.getSysName().getValue() : svSyObj.getLocalName().getValue());
        searchResultObj.setMajor(svSyObj.getMajorId());
        searchResultObj.setMajorName(svSyObj.getMajorName());
        searchResultObj.setSysObjLocalId(svSyObj.getLocalId().getValue());

        if(svSyObj.getSp() != null){
            searchResultObj.setSpObj(svSyObj.getSp().getId());
            searchResultObj.setSpObjName(svSyObj.getSp().getLocalName()==null? svSyObj.getSp().getSysName().getValue() : svSyObj.getSp().getLocalName().getValue());
            searchResultObj.setSpObjLocalId(svSyObj.getSp().getLocalId().getValue());
            if(svSyObj.getSp().getFl() != null){
                searchResultObj.setFlObj(svSyObj.getSp().getFl().getId());
                searchResultObj.setFlObjName(svSyObj.getSp().getFl().getLocalName()==null? svSyObj.getSp().getFl().getSysName().getValue() : svSyObj.getSp().getFl().getLocalName().getValue());
                searchResultObj.setFlObjLocalId(svSyObj.getSp().getFl().getLocalId().getValue());
            }
        }
        if (svSyObj.getBd() != null) {           //数据异常时此处可能会空
            searchResultObj.setBdObj(svSyObj.getBd().getId());
            searchResultObj.setBdObjName(svSyObj.getBd().getLocalName() == null ? svSyObj.getBd().getSysName().getValue() : svSyObj.getBd().getLocalName().getValue());
            searchResultObj.setBdObjLocalId(svSyObj.getBd().getLocalId().getValue());
        }
        //设置系统类型
        searchResultObj.setSy(allObjs.getIdToSubtype().get(svSyObj.getId()).substring(0, 2));

        searchResultObj.setSyName(eqStaticInfo.getCateToNameMap().get(allObjs.getIdToSubtype().get(svSyObj.getId()).substring(0, 2)));
        return searchResultObj;
    }

    private SearchResultObj buildSpSearchResultObj(SearchViewBaseObj searchViewBaseObj){
        SVSpObj svSpObj = (SVSpObj)searchViewBaseObj;
        SearchResultObj searchResultObj = new SearchResultObj();
        searchResultObj.setType("SpObj" );

        searchResultObj.setSpObj(svSpObj.getId());
        searchResultObj.setSpObjName(svSpObj.getLocalName() == null ? svSpObj.getSysName().getValue() : svSpObj.getLocalName().getValue());
        searchResultObj.setSpObjLocalId(svSpObj.getLocalId().getValue());


        if(svSpObj.getFl() != null){
            searchResultObj.setFlObj(svSpObj.getFl().getId());
            searchResultObj.setFlObjName(svSpObj.getFl().getLocalName()==null? svSpObj.getFl().getSysName().getValue() : svSpObj.getFl().getLocalName().getValue());
            searchResultObj.setFlObjLocalId(svSpObj.getFl().getLocalId().getValue());
        }
        if (svSpObj.getBd() != null) {           //数据异常时此处可能会空
            searchResultObj.setBdObj(svSpObj.getBd().getId());
            searchResultObj.setBdObjName(svSpObj.getBd().getLocalName() == null ? svSpObj.getBd().getSysName().getValue() : svSpObj.getBd().getLocalName().getValue());
            searchResultObj.setBdObjLocalId(svSpObj.getBd().getLocalId().getValue());
        }
        if (svSpObj.getRoomFuncType() != null) {
            searchResultObj.setSpType(svSpObj.getRoomFuncType().getValue());
            searchResultObj.setSpTypeName(this.getSpFuncName(svSpObj.getRoomFuncType().getValue()));
        }
        return searchResultObj;
    }

    private String getSpFuncName(String code){
        if(spFuncCode2name.get(code) == null) {
            synchronized (spFuncCode2name) {
                if(spFuncCode2name.get(code) == null) {
                    JSONObject json = new JSONObject(resourceContext.getResource(InfoCode.class).queryEquipment(null, "GeneralZone", false));
                    JSONArray arr = json.getJSONArray("Content");
                    JSONArray typeArr = null;
                    //dataSource有两种来源，判断具体是哪种
                    boolean fromExternal = false;
                    for (int i = 0; i < arr.length(); i++) {
                        JSONObject item = arr.getJSONObject(i);
                        if(item.getString("infoPointCode").equalsIgnoreCase("ProjRoomFuncType")){
                            if(item.get("dataSource") instanceof JSONArray){
                                typeArr = item.getJSONArray("dataSource");
                            }else{
                                fromExternal = true;
                            }

                            break;
                        }
                    }
                    if(fromExternal){
                        JSONObject extJson = new JSONObject(resourceContext.getResource(Dictionary.class).querySpaceFunction());
                        JSONArray contentArr = extJson.getJSONArray("Content");
                        for(int i = 0; i < contentArr.length(); i++){
                            JSONObject item = contentArr.getJSONObject(i);
                            spFuncCode2name.put(item.getString("code"), item.getString("name"));
                            item.getJSONArray("content").forEach(obj -> {
                                JSONObject lay2 = (JSONObject)obj;
                                spFuncCode2name.put(lay2.getString("code"), lay2.getString("name"));
                                lay2.getJSONArray("content").forEach(lay3Obj -> {
                                    JSONObject lay3 = (JSONObject)lay3Obj;
                                    spFuncCode2name.put(lay3.getString("code"), lay3.getString("name"));
                                });
                            });
                        }
                    }else{
                        if(typeArr == null){
                            typeArr = new JSONArray();
                        }

                        for(int i = 0; i < typeArr.length(); i++){
                            JSONObject item = typeArr.getJSONObject(i);
                            spFuncCode2name.put(item.getString("code"), item.getString("name"));

                        }
                    }

                }
            }
        }
        return spFuncCode2name.get(code);
    }

    private SearchResultObj buildFlSearchResultObj(SearchViewBaseObj searchViewBaseObj){
        SVFlObj svFlObj = (SVFlObj)searchViewBaseObj;
        SearchResultObj searchResultObj = new SearchResultObj();
        searchResultObj.setType("FlObj" );

        searchResultObj.setFlObj(svFlObj.getId());
        searchResultObj.setFlObjName(svFlObj.getLocalName() == null ? svFlObj.getSysName().getValue() : svFlObj.getLocalName().getValue());
        searchResultObj.setFlObjLocalId(svFlObj.getLocalId().getValue());

        if (svFlObj.getBd() != null) {           //数据异常时此处可能会空
            searchResultObj.setBdObj(svFlObj.getBd().getId());
            searchResultObj.setBdObjName(svFlObj.getBd().getLocalName() == null ? svFlObj.getBd().getSysName().getValue() : svFlObj.getBd().getLocalName().getValue());
            searchResultObj.setBdObjLocalId(svFlObj.getBd().getLocalId().getValue());
        }
        return searchResultObj;
    }

    private SearchResultObj buildShSearchResultObj(SearchViewBaseObj searchViewBaseObj){
        SVShObj svShObj = (SVShObj)searchViewBaseObj;
        SearchResultObj searchResultObj = new SearchResultObj();
        searchResultObj.setType("ShObj" );

        searchResultObj.setShObj(svShObj.getId());
        searchResultObj.setShObjName(svShObj.getLocalName() == null ? svShObj.getSysName().getValue() : svShObj.getLocalName().getValue());
        searchResultObj.setShObjLocalId(svShObj.getLocalId().getValue());

        if (svShObj.getBd() != null) {           //数据异常时此处可能会空
            searchResultObj.setBdObj(svShObj.getBd().getId());
            searchResultObj.setBdObjName(svShObj.getBd().getLocalName() == null ? svShObj.getBd().getSysName().getValue() : svShObj.getBd().getLocalName().getValue());
            searchResultObj.setBdObjLocalId(svShObj.getBd().getLocalId().getValue());
        }
        return searchResultObj;
    }

    private SearchResultObj buildBdSearchResultObj(SearchViewBaseObj searchViewBaseObj){
        SVBdObj svBdObj = (SVBdObj)searchViewBaseObj;
        SearchResultObj searchResultObj = new SearchResultObj();
        searchResultObj.setType("BdObj" );

        searchResultObj.setBdObj(svBdObj.getId());
        searchResultObj.setBdObjName(svBdObj.getLocalName() == null ? svBdObj.getSysName().getValue() : svBdObj.getLocalName().getValue());
        searchResultObj.setBdObjLocalId(svBdObj.getLocalId().getValue());

        return searchResultObj;
    }

}
