package org.apache.harmony.awt.datatransfer;
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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.
 */
/** 
 * @author Pavel Dolgov
 * @version $Revision$
 */


import java.awt.Graphics;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.SystemFlavorMap;
import java.awt.datatransfer.Transferable;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Reader;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Convertor from {@link java.awt.datatransfer.Transferable} to 
 * {@link org.apache.harmony.awt.datatransfer.DataProvider}
 */
public class DataSource implements DataProvider {

    // Cached data from transferable object
    private DataFlavor[] flavors;
    private List<String> nativeFormats;
    
    protected final Transferable contents;
    
    public DataSource(Transferable contents) {
        this.contents = contents;
    }

    private boolean isHtmlFlavor(DataFlavor f) {
        return "html".equalsIgnoreCase(f.getSubType()); //$NON-NLS-1$
    }
    
    protected DataFlavor[] getDataFlavors() {
        if (flavors == null) {
            flavors = contents.getTransferDataFlavors();
        }
        return flavors;
    }
    
    public String[] getNativeFormats() {
        return getNativeFormatsList().toArray(new String[0]);
    }
    
    public List<String> getNativeFormatsList() {
        if (nativeFormats == null) {
            DataFlavor[] flavors = getDataFlavors();
            nativeFormats = getNativesForFlavors(flavors);
        }

        return nativeFormats;
    }
    
    private static List<String> getNativesForFlavors(DataFlavor[] flavors) {
        ArrayList<String> natives = new ArrayList<String>();
        
        SystemFlavorMap flavorMap = 
            (SystemFlavorMap)SystemFlavorMap.getDefaultFlavorMap();
        
        for (int i = 0; i < flavors.length; i++) {
            List<String> list = flavorMap.getNativesForFlavor(flavors[i]);
            for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
                String nativeFormat = it.next();
                if (!natives.contains(nativeFormat)) {
                    natives.add(nativeFormat);
                }
            }
        }
        return natives;
    }
    
    private String getTextFromReader(Reader r) throws IOException {
        StringBuilder buffer = new StringBuilder();
        char chunk[] = new char[1024];
        int len;
        while ((len = r.read(chunk)) > 0) {
            buffer.append(chunk, 0, len);
        }
        return buffer.toString();
    }
    
    private String getText(boolean htmlOnly) {
        DataFlavor[] flavors = contents.getTransferDataFlavors();
        for (int i = 0; i < flavors.length; i++) {
            DataFlavor f = flavors[i];
            if (!f.isFlavorTextType()) {
                continue;
            }
            if (htmlOnly && !isHtmlFlavor(f)) {
                continue;
            }
            try {
                if (String.class.isAssignableFrom(
                        f.getRepresentationClass())) {
                    return (String)contents.getTransferData(f);
                }
                Reader r = f.getReaderForText(contents);
                return getTextFromReader(r);
            } catch (Exception e) {}
        }
        return null;
    }

    public String getText() {
        return getText(false);
    }

    public String[] getFileList() {
        try {
            List<?> list = (List<?>) contents.getTransferData(DataFlavor.javaFileListFlavor);
            return list.toArray(new String[list.size()]);
        } catch (Exception e) {
            return null;
        }
    }

    public String getURL() {
        try {
            URL url = (URL)contents.getTransferData(urlFlavor);
            return url.toString();
        } catch (Exception e) {}
        try {
            URL url = (URL)contents.getTransferData(uriFlavor);
            return url.toString();
        } catch (Exception e) {}
        try {
            URL url = new URL(getText());
            return url.toString();
        } catch (Exception e) {}
        return null;
    }

    public String getHTML() {
        return getText(true);
    }
    
    public RawBitmap getRawBitmap() {
        DataFlavor[] flavors = contents.getTransferDataFlavors();

        for (int i = 0; i < flavors.length; i++) {
            DataFlavor f = flavors[i];
            Class<?> c = f.getRepresentationClass();
            if (c != null && Image.class.isAssignableFrom(c) && 
                    (f.isMimeTypeEqual(DataFlavor.imageFlavor) || 
                            f.isFlavorSerializedObjectType())) {
                try {
                    Image im = (Image)contents.getTransferData(f);
                    return getImageBitmap(im);
                } catch (Throwable ex) {
                    continue;
                }
            }
        }
        return null;
    }
    
    private RawBitmap getImageBitmap(Image im) {
        if (im instanceof BufferedImage) {
            BufferedImage bi = (BufferedImage)im;
            if (bi.getType() == BufferedImage.TYPE_INT_RGB) {
                return getImageBitmap32(bi);
            }
        }
        int width = im.getWidth(null);
        int height = im.getHeight(null);
        if (width <= 0 || height <= 0) {
            return null;
        }
        BufferedImage bi = 
            new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics gr = bi.getGraphics();
        gr.drawImage(im, 0, 0, null);
        gr.dispose();
        return getImageBitmap32(bi);
    }

    private RawBitmap getImageBitmap32(BufferedImage bi) {
        int buffer[] = new int[bi.getWidth() * bi.getHeight()];
        DataBufferInt data = (DataBufferInt)bi.getRaster().getDataBuffer();
        int bufferPos = 0;
        int bankCount = data.getNumBanks();
        int offsets[] = data.getOffsets();
        for (int i = 0; i < bankCount; i++) {
            int[] fragment = data.getData(i);
            System.arraycopy(fragment, offsets[i], buffer, bufferPos, 
                    fragment.length - offsets[i]);
            bufferPos += fragment.length - offsets[i];
        }
        return new RawBitmap(bi.getWidth(), bi.getHeight(), bi.getWidth(), 
                32, 0xFF0000, 0xFF00, 0xFF, buffer);
    }

    public byte[] getSerializedObject(Class<?> clazz) {
        try {
            DataFlavor f = new DataFlavor(clazz, null);
            Serializable s = (Serializable)contents.getTransferData(f);
            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
            new ObjectOutputStream(bytes).writeObject(s);
            return bytes.toByteArray();
        } catch (Throwable e) {
            return null;
        }
    }

    public boolean isNativeFormatAvailable(String nativeFormat) {
        return getNativeFormatsList().contains(nativeFormat);
    }
}
