/*
 * Copyright (C) 2005 - 2011 Jaspersoft Corporation. All rights reserved.
 * http://www.jaspersoft.com.
 *
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License  as
 * published by the Free Software Foundation, either version 3 of  the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero  General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public  License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package com.jaspersoft.jasperserver.search.filter;

import com.jaspersoft.jasperserver.api.common.domain.ExecutionContext;
import com.jaspersoft.jasperserver.api.metadata.common.domain.Resource;
import com.jaspersoft.jasperserver.api.metadata.common.service.ResourceFactory;
import com.jaspersoft.jasperserver.api.search.SearchCriteria;
import com.jaspersoft.jasperserver.api.search.SearchCriteriaFactory;
import com.jaspersoft.jasperserver.api.search.SearchFilter;
import com.jaspersoft.jasperserver.api.search.SearchSorter;
import com.jaspersoft.jasperserver.search.common.SearchAttributes;

import java.util.List;
import java.util.Map;

/**
 * Resource type search criteria factory.
 *
 * @author Yuriy Plakosh
 * @version $Id$
 */
public class ResourceTypeSearchCriteriaFactory implements SearchCriteriaFactory {
    private Map<String, String> resourceTypeMap;
    private ResourceFactory persistentClassMappings;
    private Map<String, SearchFilter> typeSpecificFilters;

    public void setResourceTypeMap(Map<String, String> resourceTypeMap) {
        this.resourceTypeMap = resourceTypeMap;
    }

    public void setPersistentClassMappings(ResourceFactory persistentClassMappings) {
        this.persistentClassMappings = persistentClassMappings;
    }

    public void setTypeSpecificFilters(Map<String, SearchFilter> typeSpecificFilters) {
        this.typeSpecificFilters = typeSpecificFilters;
    }

    public SearchCriteria create(ExecutionContext context, List<SearchFilter> filters) {
        SearchAttributes searchAttributes = SearchAttributesHelper.extract(context);

        if (searchAttributes != null
                && searchAttributes.getState() != null
                && searchAttributes.getState().getCustomFiltersMap() != null) {
            String resourceType = getResourceType(searchAttributes);

            // Search criteria creation.
            SearchCriteria searchCriteria =
                    SearchCriteria.forClass(persistentClassMappings.getImplementationClass(resourceType));

            // Applying type specific filter if exists.
            if (typeSpecificFilters.get(resourceType) != null) {
                typeSpecificFilters.get(resourceType).applyRestrictions(resourceType, context, searchCriteria);
            }

            // Applying regular filters.
            if (filters != null) {
                for (SearchFilter filter : filters) {
                    filter.applyRestrictions(resourceType, context, searchCriteria);
                }
            }

            return searchCriteria;
        } else {
            throw new RuntimeException("Resource type filter not found in the custom filters map.");
        }
    }

    public void applySorter(ExecutionContext context, SearchCriteria searchCriteria, SearchSorter sorter) {
        SearchAttributes searchAttributes = SearchAttributesHelper.extract(context);

        if (searchAttributes != null
                && searchAttributes.getState() != null
                && searchAttributes.getState().getCustomFiltersMap() != null) {
            String resourceType = getResourceType(searchAttributes);

            // Applying sorters.
            if (sorter != null) {
                sorter.applyOrder(resourceType, context, searchCriteria);
            }
        }
    }

    private String getResourceType(SearchAttributes searchAttributes) {
        String resourceTypeFilterOption =
                searchAttributes.getState().getCustomFiltersMap().get("resourceTypeFilter");

        // Identification of resource type.
        String resourceType = Resource.class.getName();
        if (resourceTypeFilterOption != null) {
            resourceType = resourceTypeMap.get(resourceTypeFilterOption);
        }

        return resourceType;
    }
}
