/************************************************************************
 *
 *  GraphicConverterImpl.java
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *  Copyright: 2002-2007 by Henrik Just
 *
 *  All Rights Reserved.
 * 
 *  Version 0.5 (2007-04-12)
 *
 */
 
package writer2latex.filter;

// Java uno helper class
import com.sun.star.lib.uno.adapter.ByteArrayToXInputStreamAdapter;

// UNO classes
import com.sun.star.beans.PropertyValue;
import com.sun.star.graphic.XGraphic;
import com.sun.star.graphic.XGraphicProvider;
import com.sun.star.io.XInputStream;
import com.sun.star.io.XOutputStream;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.uno.XComponentContext;
import com.sun.star.uno.UnoRuntime;

import java.io.InputStream;
import java.io.OutputStream;

import writer2latex.api.GraphicConverter;
import writer2latex.office.MIMETypes;

public class GraphicConverterImpl implements GraphicConverter {

    // Signatures for start and end in exp
    private byte[] psStart;
    private byte[] psEnd;
    
    private XGraphicProvider xGraphicProvider;
	
    public GraphicConverterImpl(XComponentContext xComponentContext) {
        try {
            // Get the XGraphicProvider interface of the GraphicProvider service
            XMultiComponentFactory xMCF = xComponentContext.getServiceManager();
            Object graphicProviderObject = xMCF.createInstanceWithContext("com.sun.star.graphic.GraphicProvider", xComponentContext);
            xGraphicProvider = (XGraphicProvider) UnoRuntime.queryInterface(XGraphicProvider.class, graphicProviderObject);
        }
        catch (com.sun.star.uno.Exception ex) {
            System.err.println("Failed to get XGraphicProvider object");
            xGraphicProvider = null;
        }
        try {
            psStart = "%!PS-Adobe".getBytes("US-ASCII");
            psEnd = "%%EOF".getBytes("US-ASCII");
        }
        catch (java.io.UnsupportedEncodingException ex) {
            // US-ASCII *is* supported :-)
        }
    }
	
    public boolean supportsFormat(String sMime) {
        // Note: EPS is write only!
        return MIMETypes.PNG.equals(sMime) || MIMETypes.JPEG.equals(sMime) ||
               MIMETypes.GIF.equals(sMime) || MIMETypes.TIFF.equals(sMime) ||
               MIMETypes.BMP.equals(sMime) || MIMETypes.WMF.equals(sMime) ||
               MIMETypes.SVM.equals(sMime) || MIMETypes.EPS.equals(sMime);
    }
	
    public byte[] convert(byte[] source, String sSourceMime, String sTargetMime) {
        // It seems that the GraphicProvider can only create proper eps if
        // the source is a vector format, hence
        if (MIMETypes.EPS.equals(sTargetMime)) {
            if (!MIMETypes.WMF.equals(sSourceMime) && !MIMETypes.SVM.equals(sSourceMime)) {
                return null;
            }
        }

        ByteArrayToXInputStreamAdapter xSource = new ByteArrayToXInputStreamAdapter(source);
        ByteArrayXStream xTarget = new ByteArrayXStream();
        try {
            // Read the source
            PropertyValue[] sourceProps = new PropertyValue[1];
            sourceProps[0]       = new PropertyValue();
            sourceProps[0].Name  = "InputStream";
            sourceProps[0].Value = xSource;
            XGraphic result = xGraphicProvider.queryGraphic(sourceProps);

            // Store as new type
            PropertyValue[] targetProps = new PropertyValue[2];
            targetProps[0]       = new PropertyValue();
            targetProps[0].Name  = "MimeType";
            targetProps[0].Value = sTargetMime;
            targetProps[1]       = new PropertyValue();
            targetProps[1].Name  = "OutputStream";
            targetProps[1].Value = xTarget; 
            xGraphicProvider.storeGraphic(result,targetProps);


            // Close the output and return the result
            xTarget.closeOutput();
            xTarget.flush();
            if (MIMETypes.EPS.equals(sTargetMime)) {
                return cleanEps(xTarget.getBuffer());
            }
            else {
                return xTarget.getBuffer();
            }
        }
        catch (com.sun.star.io.IOException e) {
            return null;
        }
        catch (com.sun.star.lang.IllegalArgumentException e) {
            return null;
        }
        catch (com.sun.star.lang.WrappedTargetException e) {
            return null;
        }
        catch (Throwable e) {
            return null;
        }
    } 
	
    private byte[] cleanEps(byte[] blob) {
        int n = blob.length;

        int nStart = 0;
        for (int i=0; i<n; i++) {
            if (match(blob,psStart,i)) {
                nStart=i;
                break;
            }
        }

        int nEnd = n;
        for (int i=nStart; i<n; i++) {
            if (match(blob,psEnd,i)) {
                nEnd=i+psEnd.length;
                break;
            }
        }
		
        byte[] newBlob = new byte[nEnd-nStart];
        System.arraycopy(blob,nStart,newBlob,0,nEnd-nStart);
        return newBlob;        
    }
	
    private boolean match(byte[] blob, byte[] sig, int nStart) {
        int n = sig.length;
        if (nStart+n>=blob.length) { return false; }
        for (int i=0; i<n; i++) {
            if (blob[nStart+i]!=sig[i]) { return false; }
        }
        return true;
    }


}

