/*
 * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (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.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.cms.dispatcher;

import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.cms.Article;
import com.arsdigita.cms.ImageAsset;
import com.arsdigita.cms.ImageAssetCollection;
import com.arsdigita.cms.util.GlobalizationUtil;
import com.arsdigita.dispatcher.DispatcherHelper;
import com.arsdigita.dispatcher.RequestContext;
import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.domain.DomainObjectFactory;
import com.arsdigita.kernel.ACSObject;
import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.DataQuery;
import com.arsdigita.persistence.OID;
import com.arsdigita.persistence.SessionManager;
import com.arsdigita.toolbox.ui.OIDParameter;
import com.arsdigita.versioning.Transaction;

import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;


/**
 * A resource handler which streams out a blob from the database.
 *
 * @author Stanislav Freidin (sfreidin@arsdigita.com)
 * @author Michael Pih (pihman@arsdigita.com)
 * @version $Revision: #19 $ $DateTime: 2004/04/07 16:07:11 $
 */
public class StreamImage extends ResourceHandlerImpl {

    public static final String versionId = "$Id: //cms/dev/src/com/arsdigita/cms/dispatcher/StreamImage.java#19 $ by $Author: dennis $, $DateTime: 2004/04/07 16:07:11 $";

    public static final String IMAGE_ID = "image_id";
    public static final String OID_PARAM = "oid";

    // the transactionID and objectID allow us to rollback to a specific
    // version of an image.  If we only have a transactionID and
    // the item is its own master then we can also roll it back
    public static final String TRANSACTION_ID = "transID";
    public static final String OBJECT_ID = "objectID";

    private BigDecimalParameter m_imageId;
    private OIDParameter m_oid;
    private BigDecimalParameter m_transactionID;
    private BigDecimalParameter m_objectID;

    private static final Logger s_log =
        Logger.getLogger(StreamImage.class);

    /**
     * Construct the resource handler
     */
    public StreamImage() {
        m_imageId = new BigDecimalParameter(IMAGE_ID);
        m_oid = new OIDParameter(OID_PARAM);
        m_transactionID = new BigDecimalParameter(TRANSACTION_ID);
        m_objectID = new BigDecimalParameter(OBJECT_ID);
    }

    /**
     * Streams an image from the database.
     *
     * @param request The servlet request object
     * @param response the servlet response object
     * @param actx The request context
     */
    public void dispatch(HttpServletRequest request,
                         HttpServletResponse response,
                         RequestContext actx)
        throws IOException, ServletException {

        // Fetch and validate the image ID.
        OID oid = (OID)m_oid.transformValue(request);
        BigDecimal imageId = (BigDecimal) m_imageId.transformValue(request);
        if ( imageId == null && oid == null ) {
            throw new ServletException(IMAGE_ID + " or " + OID_PARAM + " is required.");
        } else if ( imageId != null && oid != null ) {
            throw new ServletException(IMAGE_ID + " or " + OID_PARAM + " must not both be specified.");
        }
        if (oid == null) {
            oid = new OID(ImageAsset.BASE_DATA_OBJECT_TYPE, imageId);
        }
        BigDecimal transactionID =
            (BigDecimal) m_transactionID.transformValue(request);
        BigDecimal objectID =
            (BigDecimal) m_objectID.transformValue(request);
        Transaction transaction = null;
        Article article = null;
        // XXX: add back rollback
        /*if (transactionID != null) {
            try {
                transaction =
                    new Transaction(transactionID);
                // we have a transaction so let's see if we have an article
                if (objectID != null) {
                    article = new Article(objectID);
                    article.rollBackTo(transaction);
                }
            } catch (DataObjectNotFoundException e) {
                s_log.warn("Unable to locate transaction " + transactionID);
                // this is non-critical so we just continue
            }
            }*/

        ImageAsset image = null;
        String mimeType = null;

        if (article == null) {
            try {
                image = (ImageAsset) DomainObjectFactory.newInstance(oid);
            
            } catch (DataObjectNotFoundException nfe) {
                if (s_log.isInfoEnabled()) {
                    s_log.info("no ImageAsset with oid " + oid);
                }
                throw new ServletException
                    ((String) GlobalizationUtil.globalize
                     ("cms.dispatcher.could_not_find_imageasset").localize() +
                     oid);
            }

        } else {
            ImageAssetCollection col = article.getImages();
            col.addEqualsFilter(ACSObject.ID, imageId);
            if (col.next()) {
                image = col.getImage();
                col.close();
            } else {
                s_log.error("failed to retrieve ImageAsset: " + imageId);
                throw new ServletException
                    ((String) GlobalizationUtil.globalize
                     ("cms.dispatcher.failed_to_retrieve_imageasset").localize() +
                     imageId);
            }

        }


        if ( image.getMimeType() == null ) {
            s_log.error("MIME type for ImageAsset not found; id = " + imageId);
            throw new ServletException
                ("Failed to retrieve MIME type for ImageAsset: " + imageId);
        }

        if ("live".equals(image.getVersion())) {
            DispatcherHelper.cacheForWorld(response);
        } else {
            DispatcherHelper.cacheDisable( response );
        }

        // Not until permissions are properly assigned to assets
        //checkUserAccess(request, response, actx, image);

        response.setContentType(image.getMimeType().getMimeType());
        // Stream the blob.
        OutputStream out = response.getOutputStream();
        image.writeBytes(out);
        out.close();
    }
}
