/*
 * Copyright 1999-2004 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id$ */
 
package org.apache.fop.pdf;

// Java
import java.io.IOException;
import java.io.OutputStream;

/* modified by JKT to integrate with 0.12.0 */
/* modified by Eric SCHAEFFER to integrate with 0.13.0 */

/**
 * PDF XObject
 *
 * A derivative of the PDF Object, is a PDF Stream that has not only a
 * dictionary but a stream of image data.
 * The dictionary just provides information like the stream length.
 * This outputs the image dictionary and the image data.
 * This is used as a reference for inserting the same image in the
 * document in another place.
 */
public class PDFXObject extends AbstractPDFStream {
    
    private PDFImage pdfimage;
    private int xnum;

    /**
     * create an XObject with the given number and name and load the
     * image in the object
     *
     * @param xnumber the pdf object X number
     * @param img the pdf image that contains the image data
     */
    public PDFXObject(int xnumber, PDFImage img) {
        super();
        this.xnum = xnumber;
        pdfimage = img;
    }

    /**
     * Get the xnumber for this pdf object.
     *
     * @return the PDF XObject number
     */
    public int getXNumber() {
        return this.xnum;
    }

    /**
     * Output the image as PDF.
     * This sets up the image dictionary and adds the image data stream.
     *
     * @param stream the output stream to write the data
     * @throws IOException if there is an error writing the data
     * @return the length of the data written
     */
    protected int output(OutputStream stream) throws IOException {
        int length = super.output(stream);
        
        // let it gc
        // this object is retained as a reference to inserting
        // the same image but the image data is no longer needed
        pdfimage = null;
        return length;
    }

    /**
     * @see org.apache.fop.pdf.AbstractPDFStream#buildStreamDict(String)
     */
    protected String buildStreamDict(String lengthEntry) {
        String dictEntries = getFilterList().buildFilterDictEntries();
        if (pdfimage.isPS()) {
            return buildDictionaryFromPS(lengthEntry, dictEntries);
        } else {
            return buildDictionaryFromImage(lengthEntry, dictEntries);
        }
    }
    
    private String buildDictionaryFromPS(String lengthEntry, 
                                         String dictEntries) {
        StringBuffer sb = new StringBuffer(128);
        sb.append(getObjectID());
        sb.append("<</Type /XObject\n");
        sb.append("/Subtype /PS\n");
        sb.append("/Length " + lengthEntry);

        sb.append(dictEntries);
        sb.append("\n>>\n");
        return sb.toString();
    }

    private String buildDictionaryFromImage(String lengthEntry,
                                            String dictEntries) {
        StringBuffer sb = new StringBuffer(128);
        sb.append(getObjectID());
        sb.append("<</Type /XObject\n");
        sb.append("/Subtype /Image\n");
        sb.append("/Name /Im" + xnum + "\n");
        sb.append("/Length " + lengthEntry + "\n");
        sb.append("/Width " + pdfimage.getWidth() + "\n");
        sb.append("/Height " + pdfimage.getHeight() + "\n");
        sb.append("/BitsPerComponent " + pdfimage.getBitsPerPixel() + "\n");

        PDFICCStream pdfICCStream = pdfimage.getICCStream();
        if (pdfICCStream != null) {
            sb.append("/ColorSpace [/ICCBased "
                + pdfICCStream.referencePDF() + "]\n");
        } else {
            PDFColorSpace cs = pdfimage.getColorSpace();
            sb.append("/ColorSpace /" + cs.getColorSpacePDFString()
                  + "\n");
        }

        /* PhotoShop generates CMYK values that's inverse,
           this will invert the values - too bad if it's not
           a PhotoShop image...
         */
        if (pdfimage.getColorSpace().getColorSpace()
                == PDFColorSpace.DEVICE_CMYK) {
            sb.append("/Decode [ 1.0 0.0 1.0 0.0 1.0 0.0 1.1 0.0 ]\n");
        }

        if (pdfimage.isTransparent()) {
            PDFColor transp = pdfimage.getTransparentColor();
            sb.append("/Mask [" 
                + transp.red255() + " "
                + transp.red255() + " " 
                + transp.green255() + " " 
                + transp.green255() + " "
                + transp.blue255() + " " 
                + transp.blue255() + "]\n");
        }
        String ref = pdfimage.getSoftMask();
        if (ref != null) {
            sb.append("/SMask " + ref + "\n");
        }

        sb.append(dictEntries);
        sb.append("\n>>\n");
        return sb.toString();
    }
    
    /**
     * @see org.apache.fop.pdf.PDFStream#outputRawStreamData(OutputStream)
     */
    protected void outputRawStreamData(OutputStream out) throws IOException {
        pdfimage.outputContents(out);
    }

    /**
     * @see org.apache.fop.pdf.AbstractPDFStream#getSizeHint()
     */
    protected int getSizeHint() throws IOException {
        return 0;
    }

    /**
     * @see org.apache.fop.pdf.AbstractPDFStream#prepareImplicitFilters()
     */
    protected void prepareImplicitFilters() {
        if (pdfimage.isDCT()) {
            getFilterList().ensureDCTFilterInPlace();
        }
    }
    
    /**
     * This sets up the default filters for XObjects. It uses the PDFImage
     * instance to determine what default filters to apply.
     * @see org.apache.fop.pdf.AbstractPDFStream#setupFilterList()
     */
    protected void setupFilterList() {
        if (!getFilterList().isInitialized()) {
            getFilterList().addDefaultFilters(
                getDocumentSafely().getFilterMap(), 
                pdfimage.getFilterHint());
        }
        super.setupFilterList();
    }
    

}
