/*
 * 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.service.impl;

import com.jaspersoft.jasperserver.api.JSException;
import com.jaspersoft.jasperserver.api.metadata.common.service.impl.RepositorySecurityChecker;
import com.jaspersoft.jasperserver.api.metadata.common.domain.Resource;
import com.jaspersoft.jasperserver.api.metadata.view.domain.FilterCriteria;
import com.jaspersoft.jasperserver.api.metadata.user.service.ObjectPermissionService;
import com.jaspersoft.jasperserver.api.JSDuplicateResourceException;
import com.jaspersoft.jasperserver.search.service.ResourceService;
import com.jaspersoft.jasperserver.search.service.ChildrenLoaderService;
import com.jaspersoft.jasperserver.search.common.ResourceDetails;
import com.jaspersoft.jasperserver.search.common.SchedulingChecker;

import java.util.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ResourceServiceImpl extends BaseService implements ResourceService {

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

    private RepositorySecurityChecker securityChecker;
    protected ObjectPermissionService permissionService;
    private SchedulingChecker schedulingChecker;
    private Map<String, ChildrenLoaderService> childrenLoaders;
    private List<String> deleteOrder;

    public ResourceDetails update(String uri, String label, String description) {
        String parentUri = uri.substring(0, uri.lastIndexOf("/"));

        FilterCriteria criteria = FilterCriteria.createFilter();
        criteria.addFilterElement(FilterCriteria.createParentFolderFilter(parentUri));

        Resource resource = repositoryService.getResource(null, uri);
        if (!label.equalsIgnoreCase(resource.getLabel()) ||
                !description.equalsIgnoreCase(resource.getDescription())) {

            resource.setLabel(label);
            resource.setDescription(description);

            repositoryService.saveResource(null, resource);
        }

        return getResourceDetails(repositoryService.getResource(null, uri));
    }

    public void delete(final List<Resource> resources) {
        Collections.sort(resources, new Comparator<Resource>() {
            public int compare(Resource o1, Resource o2) {
                int index1 = deleteOrder.indexOf(o1.getResourceType());
                int index2 = deleteOrder.indexOf(o2.getResourceType());
                return (index1 < index2 ? -1 : (index1 == index2 ? 0 : 1));
            }
        });

        for (Resource resource : resources) {
            repositoryService.deleteResource(null, resource.getURIString());
        }
    }

    public void copy(Set<String> resourceUris, String destinationFolderUri) {
        Map<String, Resource> resourceMap = getResourceMap(resourceUris);

        if (!isLabelsUnique(resourceMap) || isObjectsLabelsExist(destinationFolderUri, getLabels(resourceMap))) {
            throw new JSException("jsexception.search.duplicate.label", new Object[]{"", destinationFolderUri});
        }

        while (getResourcesWithUniqueName(resourceMap).size() > 0) {
            Map<String, Resource> resources = getResourcesWithUniqueName(resourceMap);
            Set<String> uris = resources.keySet();
            repositoryService.copyResources(null, uris.toArray(new String[uris.size()]), destinationFolderUri);

            for (String key : resources.keySet()) {
                resourceMap.remove(key);
            }
        }
    }

    private Set<String> getLabels(Map<String, Resource> resourceMap) {
        Set<String> result = new HashSet<String>();

        for (Resource resource : resourceMap.values()) {
            result.add(resource.getLabel());
        }

        return result;
    }

    public void move(Set<String> resourceUris, String destinationFolderUri) {
        Map<String, Resource> resourceMap = getResourceMap(resourceUris);

        if (!isLabelsUnique(resourceMap) || isObjectsLabelsExist(destinationFolderUri, getLabels(resourceMap))) {
            throw new JSException("jsexception.search.duplicate.label", new Object[]{"", destinationFolderUri});
        }

        if (resourceMap.size() != getResourcesWithUniqueName(resourceMap).size()) {
            throw new JSException("jsexception.search.duplicate.name", new Object[]{"", destinationFolderUri});
        }
        
        for (String uri : resourceMap.keySet()) {
            repositoryService.moveResource(null, uri, destinationFolderUri);
        }
    }

    public ResourceDetails getResourceDetails(Resource resource) {
        ResourceDetails resourceDetails = new ResourceDetails(resource);

        if (securityChecker != null) {
//            resourceDetails.setReadable(securityChecker.isResourceReadable(resource.getURIString()));
            resourceDetails.setReadable(true);
            resourceDetails.setEditable(securityChecker.isEditable(resource));
            resourceDetails.setRemovable(securityChecker.isRemovable(resource));
            resourceDetails.setAdministrable(permissionService.isObjectAdministrable(null, resource));

            resourceDetails.setScheduled(schedulingChecker.isScheduled(null, resource));
        } else {
            if (log.isDebugEnabled()) { log.debug("Repository security checker is null!"); }
        }

        if (schedulingChecker != null) {
            resourceDetails.setScheduled(schedulingChecker.isScheduled(null, resource));
        } else {
            if (log.isDebugEnabled()) { log.debug("Scheduling checker is null!"); }
        }

        ChildrenLoaderService childrenLoaderService = childrenLoaders.get(resource.getResourceType());

        if (childrenLoaderService != null) {
            resourceDetails.setHasChildren(childrenLoaderService.hasChildren(resourceDetails.getURIString()));
        } else {
            resourceDetails.setHasChildren(false);
        }

        return resourceDetails;
    }

    public void setSecurityChecker(RepositorySecurityChecker securityChecker) {
        this.securityChecker = securityChecker;
    }

    public void setDeleteOrder(List<String> deleteOrder) {
        this.deleteOrder = deleteOrder;
    }

    public void setPermissionService(ObjectPermissionService permissionService) {
        this.permissionService = permissionService;
    }

    public void setSchedulingChecker(SchedulingChecker schedulingChecker) {
        this.schedulingChecker = schedulingChecker;
    }

    public void setChildrenLoaders(Map<String, ChildrenLoaderService> childrenLoaders) {
        this.childrenLoaders = childrenLoaders;
    }    
}
