package com.atlassian.confluence.rpc.soap.services;

import com.atlassian.confluence.rpc.soap.beans.RemoteAttachment;
import com.atlassian.confluence.rpc.NotPermittedException;
import com.atlassian.confluence.rpc.RemoteException;
import com.atlassian.confluence.pages.AttachmentManager;
import com.atlassian.confluence.pages.Attachment;
import com.atlassian.confluence.pages.PageManager;
import com.atlassian.confluence.core.ContentEntityManager;
import com.atlassian.confluence.core.ContentEntityObject;
import com.atlassian.confluence.security.PermissionManager;
import com.atlassian.confluence.security.Permission;
import com.atlassian.confluence.user.AuthenticatedUserThreadLocal;
import com.atlassian.core.util.FileUtils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ByteArrayOutputStream;

/**
 * Implementation of remote methods for handling attachments.
 */
public class AttachmentsSoapService
{
    private AttachmentManager attachmentManager;
    private ContentEntityManager contentEntityManager;
    private PermissionManager permissionManager;

    /**
     * @deprecated available for backward compatibility.
     */
    public RemoteAttachment addAttachment(RemoteAttachment remoteAttachment, byte[] attachmentData) throws NotPermittedException, RemoteException
    {
        return addAttachment(remoteAttachment.getPageId(), remoteAttachment, attachmentData);
    }

    public RemoteAttachment addAttachment(long contentId, RemoteAttachment remoteAttachment, byte[] attachmentData) throws NotPermittedException, RemoteException
    {
        ContentEntityObject ceo = getCEO(contentId);
        if (!permissionManager.hasCreatePermission(AuthenticatedUserThreadLocal.getUser(), ceo, Attachment.class))
        {
            throw new NotPermittedException("You do not have the permissions to perform this action");
        }
        Attachment previousVersion = attachmentManager.getAttachment(ceo, remoteAttachment.getFileName());
        Attachment attachment;
        if (previousVersion != null)
        {
            try
            {
                attachment = previousVersion;
                previousVersion = (Attachment)previousVersion.clone();
            }
            catch (CloneNotSupportedException cnse)
            {
                throw new RemoteException(cnse);
            }
        }
        else
        {
            attachment = new Attachment();
            ceo.addAttachment(attachment);
        }
        attachment.setComment(remoteAttachment.getComment());
        attachment.setContentType(remoteAttachment.getContentType());
        attachment.setContent(ceo);
        attachment.setFileName(remoteAttachment.getFileName());
        attachment.setFileSize(attachmentData.length);

        try
        {
            attachmentManager.saveAttachment(attachment, previousVersion, new ByteArrayInputStream(attachmentData));
        }
        catch (IOException ioe)
        {
            throw new RemoteException("Error saving attachment", ioe);
        }

        Attachment newAttachment = attachmentManager.getAttachment(ceo, attachment.getFileName());
        return new RemoteAttachment(newAttachment);  //To change body of created methods use File | Settings | File Templates.
    }

    public RemoteAttachment getAttachment(long contentId, String fileName, int version) throws NotPermittedException, RemoteException
    {
        ContentEntityObject ceo = getCEO(contentId);
        Attachment attachment = getExistingAttachment(ceo, fileName, version);
        if (attachment == null)
        {

        }
        if (!permissionManager.hasPermission(AuthenticatedUserThreadLocal.getUser(), Permission.VIEW, attachment))
        {
            throw new NotPermittedException("You do not have the permissions to perform this action");
        }
        return new RemoteAttachment(attachment);
    }

    public byte[] getAttachmentData(long contentId, String fileName, int version) throws NotPermittedException, RemoteException
    {
        ContentEntityObject ceo = getCEO(contentId);
        Attachment attachment = getExistingAttachment(ceo, fileName, version);
        if (!permissionManager.hasPermission(AuthenticatedUserThreadLocal.getUser(), Permission.VIEW, attachment))
        {
            throw new NotPermittedException("You do not have the permissions to perform this action");
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream((int)attachment.getFileSize());
        try
        {
            FileUtils.copy(attachmentManager.getAttachmentData(attachment),baos);
            baos.close();
        }
        catch (IOException ioe)
        {
            throw new RemoteException("Error reading attachment contents", ioe);
        }
        return baos.toByteArray();
    }

    public boolean removeAttachment(long contentId, String fileName) throws NotPermittedException, RemoteException
    {
        ContentEntityObject ceo = getCEO(contentId);
        Attachment attachment = getExistingCurrentAttachment(ceo, fileName);
        if (!permissionManager.hasPermission(AuthenticatedUserThreadLocal.getUser(), Permission.REMOVE, attachment))
        {
            throw new NotPermittedException("You do not have the permissions to perform this action");
        }
        attachmentManager.removeAttachmentFromServer(attachment);
        return true;
    }

    public boolean moveAttachment(long contentId, String name, long newContentId, String newName) throws RemoteException, NotPermittedException
    {
        ContentEntityObject existingCeo = getCEO(contentId);
        Attachment attachment = getExistingCurrentAttachment(existingCeo, name);
        ContentEntityObject newCeo = getCEO(newContentId);
        if (!permissionManager.hasPermission(AuthenticatedUserThreadLocal.getUser(), Permission.REMOVE, attachment)
                ||
             !permissionManager.hasCreatePermission(AuthenticatedUserThreadLocal.getUser(), newCeo, Attachment.class))
        {
            throw new NotPermittedException("You do not have the permissions to perform this action");
        }
        attachmentManager.moveAttachment(attachment, newName, newCeo);
        return true;
    }

    private ContentEntityObject getCEO(long id) throws RemoteException
    {
        ContentEntityObject ceo = contentEntityManager.getById(id);
        if (ceo == null)
        {
            throw new RemoteException("No content with id " + id + " exists.");
        }
        return ceo;
    }

    private Attachment getExistingAttachment(ContentEntityObject ceo, String fileName, int version) throws RemoteException
    {
        Attachment attachment = attachmentManager.getAttachment(ceo, fileName, version);
        if (attachment == null)
        {
            throw new RemoteException("No attachment on content with id " + ceo.getId() + ", name '" + fileName + "' and version " + version + " exists.");
        }
        return attachment;
    }

    private Attachment getExistingCurrentAttachment(ContentEntityObject ceo, String fileName) throws RemoteException
    {
        Attachment attachment = attachmentManager.getAttachment(ceo, fileName);
        if (attachment == null)
        {
            throw new RemoteException("No attachment on content with id " + ceo.getId() + ", name '" + fileName + "' exists.");
        }
        return attachment;
    }

    public void setAttachmentManager(AttachmentManager attachmentManager)
    {
        this.attachmentManager = attachmentManager;
    }

    public void setContentEntityManager(ContentEntityManager contentEntityManager)
    {
        this.contentEntityManager = contentEntityManager;
    }

    public void setPermissionManager(PermissionManager permissionManager)
    {
        this.permissionManager = permissionManager;
    }
}
