/*
 * Copyright (c) 2019 WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.wso2.carbon.apimgt.rest.api.publisher.v1.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.jaxrs.ext.MessageContext;

import org.wso2.carbon.apimgt.api.APIManagementException;
import org.wso2.carbon.apimgt.api.APIProvider;
import org.wso2.carbon.apimgt.api.model.API;
import org.wso2.carbon.apimgt.api.model.Documentation;
import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.impl.utils.APIUtil;
import org.wso2.carbon.apimgt.rest.api.publisher.v1.SearchApiService;
import org.wso2.carbon.apimgt.rest.api.publisher.v1.dto.PaginationDTO;
import org.wso2.carbon.apimgt.rest.api.publisher.v1.dto.SearchResultDTO;
import org.wso2.carbon.apimgt.rest.api.publisher.v1.dto.SearchResultListDTO;
import org.wso2.carbon.apimgt.rest.api.publisher.v1.utils.mappings.SearchResultMappingUtil;
import org.wso2.carbon.apimgt.rest.api.util.RestApiConstants;
import org.wso2.carbon.apimgt.rest.api.util.utils.RestApiUtil;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.ws.rs.core.Response;

public class SearchApiServiceImpl implements SearchApiService {

    private static final Log log = LogFactory.getLog(SearchApiServiceImpl.class);

    public Response searchGet(Integer limit, Integer offset, String query, String ifNoneMatch,
                              MessageContext messageContext) {

        SearchResultListDTO resultListDTO = new SearchResultListDTO();
        List<SearchResultDTO> allmatchedResults = new ArrayList<>();

        limit = limit != null ? limit : RestApiConstants.PAGINATION_LIMIT_DEFAULT;
        offset = offset != null ? offset : RestApiConstants.PAGINATION_OFFSET_DEFAULT;
        query = query == null ? "*" : query;

        try {
            if (!query.contains(":")) {
                query = (APIConstants.CONTENT_SEARCH_TYPE_PREFIX + ":" + query);
            }
            String newSearchQuery = APIUtil.constructNewSearchQuery(query);
            APIProvider apiProvider = RestApiUtil.getLoggedInUserProvider();

            String username = RestApiUtil.getLoggedInUsername();
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(username));
            Map<String, Object> result = apiProvider
                    .searchPaginatedAPIs(newSearchQuery, tenantDomain, offset, limit, false);
            ArrayList<Object> apis;
            /* Above searchPaginatedAPIs method underneath calls searchPaginatedAPIsByContent method and searchPaginatedAPIs
            method in AbstractApiManager. And those methods respectively returns ArrayList and a TreeSet.
            Hence the below logic.
            */
            Object apiSearchResults = result.get("apis");
            if (apiSearchResults instanceof List<?>) {
                apis = (ArrayList<Object>) apiSearchResults;
            } else {
                apis = new ArrayList<Object>();
                apis.addAll((Collection<?>) apiSearchResults);
            }

            for (Object searchResult : apis) {
                if (searchResult instanceof API) {
                    API api = (API) searchResult;
                    SearchResultDTO apiResult = SearchResultMappingUtil.fromAPIToAPIResultDTO(api);
                    allmatchedResults.add(apiResult);
                } else if (searchResult instanceof Map.Entry) {
                    Map.Entry pair = (Map.Entry) searchResult;
                    SearchResultDTO docResult = SearchResultMappingUtil.fromDocumentationToDocumentResultDTO(
                            (Documentation) pair.getKey(), (API) pair.getValue());
                    allmatchedResults.add(docResult);
                }
            }

            resultListDTO.setList(allmatchedResults);
            resultListDTO.setCount(allmatchedResults.size());
            SearchResultMappingUtil.setPaginationParams(resultListDTO, query, offset, limit, resultListDTO.getCount());

        } catch (APIManagementException e) {
            String errorMessage = "Error while retrieving search results";
            RestApiUtil.handleInternalServerError(errorMessage, e, log);
        }

        return Response.ok().entity(resultListDTO).build();
    }
}

@@ -1786,24 +1786,50 @@
 Collection;%0A
+import java.util.HashMap;%0A
 import java.
@@ -3321,21 +3321,17 @@
 t method
- and 
+,
 searchPa
@@ -3361,16 +3361,40 @@
  method 
+and searchAPIDoc method 
 in Abstr
@@ -3460,22 +3460,43 @@
 List
- and a TreeSet
+,%0A            TreeSet and a HashMap
 .%0A  
@@ -3717,16 +3717,215 @@
 esults;%0A
+            %7D else if (apiSearchResults instanceof HashMap) %7B%0A                Collection%3CString%3E values = ((HashMap) apiSearchResults).values();%0A                apis = new ArrayList%3CObject%3E(values);%0A
         
@@ -4764,32 +4764,221 @@
 %0A            %7D%0A%0A
+            Object totalLength = result.get(%22length%22);%0A            Integer length = 0;%0A            if (totalLength != null) %7B%0A                length = (Integer) totalLength;%0A            %7D%0A%0A
             resu
@@ -5174,32 +5174,14 @@
 it, 
-resultListDTO.getCount()
+length
 );%0A%0A

Fix pagination issue and doc: filtered search issue