/*
 * 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/>.
 */

/**
 * UserAndRoleManagementServiceImpl.java
 *
 * This file was auto-generated from WSDL
 * by the Apache Axis 1.3 Oct 05, 2005 (05:23:37 EDT) WSDL2Java emitter.
 */

package com.jaspersoft.jasperserver.ws.axis2.authority;

import com.jaspersoft.jasperserver.ws.authority.*;
import com.jaspersoft.jasperserver.api.metadata.user.service.ObjectPermissionService;
import com.jaspersoft.jasperserver.api.metadata.user.domain.ObjectPermission;
import com.jaspersoft.jasperserver.api.metadata.common.service.RepositoryService;
import com.jaspersoft.jasperserver.api.metadata.common.domain.Resource;
import com.jaspersoft.jasperserver.api.common.domain.ExecutionContext;
import com.jaspersoft.jasperserver.api.common.domain.impl.ExecutionContextImpl;
import com.jaspersoft.jasperserver.api.logging.audit.context.AuditContext;
import com.jaspersoft.jasperserver.api.logging.audit.domain.AuditEvent;
import org.apache.axis.AxisFault;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.i18n.LocaleContextHolder;

import java.util.*;

public class PermissionsManagementServiceImpl implements PermissionsManagementService {

    protected ObjectPermissionService objectPermissionService;

    protected RepositoryService repositoryService;
    protected AuditContext auditContext;

    protected void createPermissionAuditEvent(final String auditEventType) {
        auditContext.doInAuditContext(new AuditContext.AuditContextCallback() {
            public void execute() {
                auditContext.createAuditEvent(auditEventType);
            }
        });
    }

    protected void closePermissionAuditEvent(String auditEventType) {
        auditContext.doInAuditContext(auditEventType, new AuditContext.AuditContextCallbackWithEvent() {
            public void execute(AuditEvent auditEvent) {
                auditContext.closeAuditEvent(auditEvent);
            }
        });
    }

    public WSObjectPermission[] getPermissionsForObject(String targetURI) throws AxisFault {
        // checking administrable access
        if (!objectPermissionService.isObjectAdministrable(makeExecutionContext(), targetURI)) {
            throw new AxisFault("Access is denied");
        }
        Resource res = repositoryService.getResource(makeExecutionContext(), targetURI);
        if (res == null) {
            res = repositoryService.getFolder(makeExecutionContext(), targetURI);

            if (res == null) {
                throw new AxisFault("There is no resource or folder for target URI \"" + targetURI + "\"");
            }
        }

        List objectPermissionsForObject = objectPermissionService.getObjectPermissionsForObject(makeExecutionContext(),
                res);

        return PermissionsTranslator.toWSTenantArray(objectPermissionsForObject);
    }

    public WSObjectPermission putPermission(WSObjectPermission objectPermission) throws AxisFault {
        changePermissionConsistencyCheck(objectPermission);

        ObjectPermission op = objectPermissionService.newObjectPermission(makeExecutionContext());
        PermissionsTranslator.populateObjectPermission(objectPermission, op);
        ObjectPermission existingObjectPermission =
                objectPermissionService.getObjectPermission(makeExecutionContext(), op);
        String auditEventType;

        if (existingObjectPermission == null) {
            auditEventType = "createPermission";
        } else {
            auditEventType = "updatePermission";
        }

        createPermissionAuditEvent(auditEventType);
        objectPermissionService.putObjectPermission(makeExecutionContext(), op);
        closePermissionAuditEvent(auditEventType);

        return PermissionsTranslator.toWSObjectPermission(
                objectPermissionService.getObjectPermission(makeExecutionContext(), op));
    }

    public void deletePermission(WSObjectPermission objectPermission) throws AxisFault {
        changePermissionConsistencyCheck(objectPermission);

        ObjectPermission op = objectPermissionService.newObjectPermission(makeExecutionContext());
        PermissionsTranslator.populateObjectPermission(objectPermission, op);

        createPermissionAuditEvent("deletePermission");
        objectPermissionService.deleteObjectPermission(makeExecutionContext(), op);
        closePermissionAuditEvent("deletePermission");
    }

    protected void changePermissionConsistencyCheck(WSObjectPermission objectPermission) throws AxisFault {
        if (StringUtils.isBlank(objectPermission.getUri())) {
            throw new AxisFault("URI is blank");
        }

        // Permission recepient check
        if (objectPermission.getPermissionRecipient() == null) {
            throw new AxisFault("Permission recipient is null");
        }

        if (isPermissionForRootRessource(objectPermission)) {
            throw new AxisFault("Setting/changing/deleting permissions for root URI is forbidden");
        }
    }

    protected boolean isPermissionForRootRessource(WSObjectPermission objectPermission) {
        return ("repo:/".equals(objectPermission.getUri()) || "/".equals(objectPermission.getUri()));
    }

    public void setObjectPermissionService(ObjectPermissionService objectPermissionService) {
        this.objectPermissionService = objectPermissionService;
    }

    public void setRepositoryService(RepositoryService repositoryService) {
        this.repositoryService = repositoryService;
    }

    public void setAuditContext(AuditContext auditContext) {
        this.auditContext = auditContext;
    }

    protected ExecutionContext makeExecutionContext() {
        ExecutionContextImpl executionContext = new ExecutionContextImpl();
        executionContext.setLocale(getLocale());
        return executionContext;
    }

    protected Locale getLocale() {
        return LocaleContextHolder.getLocale();
    }
}
