/*
 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.glass.ui.ios;

import com.sun.glass.ui.Clipboard;
import com.sun.glass.ui.Pixels;
import com.sun.glass.ui.SystemClipboard;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.HashMap;

/**
 * System (copy/paste) UIPasteboard wrapper class.
 */
class IosSystemClipboard extends SystemClipboard {

    static final String FILE_SCHEME = "file";
    static final private String BAD_URI_MSG = "bad URI in com.sun.glass.ui.ios.IosSystemClipboard for file: ";
    static final private String BAD_URL_MSG = "bad URL in com.sun.glass.ui.ios.IosSystemClipboard for file: ";

    long seed = 0;

    final IosPasteboard pasteboard;

    public IosSystemClipboard(String name) {
        super(name);
        if (name.equals(Clipboard.SYSTEM) == true) {
            this.pasteboard = new IosPasteboard(IosPasteboard.General);
        } else {
            this.pasteboard = new IosPasteboard(name);
        }
    }

    @Override
    protected boolean isOwner() {
        return (this.seed == this.pasteboard.getSeed());
    }

    @Override
    protected void pushToSystem(HashMap<String, Object> data, int supportedActions) {
        HashMap<String,Object> itemFirst = null; // used to handle paste as one item if we can
        HashMap<String,Object> itemList[] = null; // special case: multiple items for handling urls 10.6 style

        java.util.Set keys = data.keySet();
        java.util.Iterator iterator = keys.iterator();

        while (iterator.hasNext() == true) {
            String mime = (String)iterator.next();
            Object object = data.get(mime);

            if (object != null) {
                if (mime.equals(URI_TYPE) == true) {
                    // synthesize list of urls as seperate pasteboard items
                    String list = (String)object;
                    String split[] = list.split("\n");
                    int count = 0;
                    for (int i=0; i<split.length; i++) {
                        String string = split[i];
                        if (string.startsWith("#") == false) {
                            // exclude comments: http://www.ietf.org/rfc/rfc2483.txt
                            count++;
                        }
                    }

                    if (count > 0) {
                        itemList = new HashMap[count];
                        count = 0;
                        for (int i=0; i<split.length; i++) {
                            String file = split[i];
                            if (file.startsWith("#") == false) {
                                // exclude comments: http://www.ietf.org/rfc/rfc2483.txt
                                URI uri = createUri(file, IosSystemClipboard.BAD_URI_MSG);
                                String utf = IosPasteboard.UtfUrl;
                                if (uri.getScheme() == null)
                                {
                                    utf = IosPasteboard.UtfFileUrl;
                                    uri = createUri(IosSystemClipboard.FILE_SCHEME, uri.getPath(), IosSystemClipboard.BAD_URI_MSG);
                                }
                                itemList[count] = new HashMap();
                                itemList[count].put(utf, uri.toASCIIString());
                                count++;
                            }
                        }
                    }
                } else if (mime.equals(RAW_IMAGE_TYPE) == true) {
                    Pixels pixels = (Pixels)object;
                    if (itemFirst == null) {
                        itemFirst = new HashMap();
                    }
                    itemFirst.put(mimeToUtf(mime), pixels);
                } else if ((mime.equals(TEXT_TYPE) == true) ||
                        (mime.equals(HTML_TYPE) == true) ||
                        (mime.equals(RTF_TYPE) == true)) {
                    if (object instanceof String) {
                        String string = (String)object;
                        if (itemFirst == null) {
                            itemFirst = new HashMap();
                        }
                        itemFirst.put(mimeToUtf(mime), string);
                    } else {
                        // http://javafx-jira.kenai.com/browse/RT-14593
                        // temporary code, DelayedCallback trips over this
                        // by reusing (incorrectly) text mime type
                        System.err.println("DelayedCallback not implemented yet: RT-14593");
                        Thread.dumpStack();
                    }
                } else if (mime.equals(FILE_LIST_TYPE)) {
                    // handle FILE_LIST_TYPE last to know whether to handle it as urls (10.6) or file list (10.5)
                    // depending on whether urls have been already explicitly set or not
                    String files[] = (String[])object;
                    if (data.get(URI_TYPE) == null) {
                        // special case no explicit urls found - synthesize urls (Ios OS 10.6 style)
                        itemList = new HashMap[files.length];
                        for (int i=0; i<files.length; i++) {
                            String file = files[i];
                            URI uri = createUri(file, IosSystemClipboard.BAD_URI_MSG);
                            String utf = IosPasteboard.UtfUrl;
                            if (uri.getScheme() == null)
                            {
                                utf = IosPasteboard.UtfFileUrl;
                                uri = createUri(IosSystemClipboard.FILE_SCHEME, uri.getPath(), IosSystemClipboard.BAD_URI_MSG);
                            }
                            itemList[i] = new HashMap();
                            itemList[i].put(utf, uri.toASCIIString());
                        }
                    }
                } else {
                    // custom client mime type - pass through (RT-14592)
                    if (itemFirst == null) {
                        itemFirst = new HashMap();
                    }
                    itemFirst.put(mimeToUtf(mime), serialize(object));
                }
            }
        }

        if (itemFirst != null) {
            if (itemList == null) {
                itemList = new HashMap[1];
                itemList[0] = itemFirst;
            } else {
                HashMap temp = itemList[0];
                itemList[0] = itemFirst;
                iterator = temp.keySet().iterator();
                while (iterator.hasNext() == true) {
                    String utf = (String)iterator.next();
                    Object object = temp.get(utf);
                    itemList[0].put(utf, object);
                }
            }
        }

        if (itemList != null) {
            this.seed = this.pasteboard.putItems(itemList, supportedActions);
        }
    }

    @Override
    protected void pushTargetActionToSystem(int actionDone) {

    }

    @Override
    protected Object popFromSystem(String mimeType) {
        Object object = null;

        String[][] utfs = this.pasteboard.getUTFs();
        if (mimeType.equals(URI_TYPE) == true) {
            if (utfs != null) {
                java.util.ArrayList<String> list = new java.util.ArrayList<String>();
                for (int i=0; i<utfs.length; i++) {
                    String url = this.pasteboard.getItemStringForUTF(i, mimeToUtf(URI_TYPE));

                    if (url != null) {
                        list.add(url);
                        break;
                    }
                }
                if (list.size() > 0) {
                    object = list.get(0);
                }
            }
        } else if (mimeType.equals(RAW_IMAGE_TYPE) == true) {
            if (utfs != null) {
                java.util.ArrayList<Pixels> list = new java.util.ArrayList<Pixels>();
                for (int i=0; i<utfs.length; i++) {
                    Object data = this.pasteboard.getItemAsRawImage(i);
                    if (data != null) {
                        Pixels pixels = getPixelsForRawImage((byte[])data);
                        list.add(pixels);
                        break;
                    }
                }
                if (list.size() > 0) {
                    object = list.get(0);
                }
            }
        } else if ((mimeType.equals(TEXT_TYPE) == true) ||
                        (mimeType.equals(HTML_TYPE) == true) ||
                            (mimeType.equals(RTF_TYPE) == true)) {
            if (utfs != null) {
                java.util.ArrayList<String> list = new java.util.ArrayList<String>();
                for (int i=0; i<utfs.length; i++) {
                    String item = this.pasteboard.getItemStringForUTF(i, mimeToUtf(mimeType));
                    if (item != null) {
                        list.add(item);
                        break;
                    }
                }
                if (list.size() > 0) {
                    object = list.get(0);
                }
            }
        } else if (mimeType.equals(FILE_LIST_TYPE) == true) {
            // synthesize the list from individual URLs
            if (utfs != null) {
                java.util.ArrayList<String> list = new java.util.ArrayList<String>();
                for (int i=0; i<utfs.length; i++) {
                    String file = this.pasteboard.getItemStringForUTF(i, IosPasteboard.UtfFileUrl); // explicitly ask for urls
                    if (file != null) {
                        URL url = createUrl(file, IosSystemClipboard.BAD_URL_MSG);
                        list.add(url.getPath());
                    }
                }
                if (list.size() > 0) {
                    object = new String[list.size()];
                    list.toArray((String[])object);
                }
            }
        } else {
            if (utfs != null) {
                java.util.ArrayList<ByteBuffer> list = new java.util.ArrayList<ByteBuffer>();
                for (int i=0; i<utfs.length; i++) {
                    byte data[] = this.pasteboard.getItemBytesForUTF(i, mimeToUtf(mimeType));
                    if (data != null) {
                        // http://javafx-jira.kenai.com/browse/RT-14592
                        // custom data - currently we wrap it up in ByteBuffer
                        ByteBuffer bb = ByteBuffer.wrap(data);
                        list.add(bb);
                        break;
                    }
                }
                if (list.size() > 0) {
                    object = list.get(0);
                }
            }
        }
        return object;
    }

    @Override
    protected int supportedSourceActionsFromSystem() {
        return this.pasteboard.getAllowedOperation();
    }


    @Override
    protected String[] mimesFromSystem() {
        String[][] all = this.pasteboard.getUTFs();

        java.util.ArrayList<String> mimes = new java.util.ArrayList<String>();

        if (all != null) {
            for (int i=0; i<all.length; i++) {
                String[] utfs = all[i];
                if (utfs != null) {
                    for (int j=0; j<utfs.length; j++) {
                        String utf = utfs[j];
                        String mime = utfToMime(utf);
                        if ((mime != null) && (mimes.contains(mime) == false)) {
                            mimes.add(mime);
                        }
                    }
                }
            }
        }

        String[] strings = new String[mimes.size()];
        mimes.toArray(strings);

        return strings;
    }

    static private HashMap utm = null;
    private synchronized String utfToMime(String utf) {
        if (IosSystemClipboard.utm == null) {
            IosSystemClipboard.utm = new HashMap(6);
            IosSystemClipboard.utm.put(IosPasteboard.UtfString, TEXT_TYPE);
            IosSystemClipboard.utm.put(IosPasteboard.UtfHtml, HTML_TYPE);
            IosSystemClipboard.utm.put(IosPasteboard.UtfRtf, RTF_TYPE);
            IosSystemClipboard.utm.put(IosPasteboard.UtfUrl, URI_TYPE);
            IosSystemClipboard.utm.put(IosPasteboard.UtfFileUrl, FILE_LIST_TYPE);
            IosSystemClipboard.utm.put(IosPasteboard.UtfTiff, RAW_IMAGE_TYPE);
            IosSystemClipboard.utm.put(IosPasteboard.UtfPng, RAW_IMAGE_TYPE);
        }
        if (IosSystemClipboard.utm.containsKey(utf) == true) {
            return (String)IosSystemClipboard.utm.get(utf);
        } else {
            return utf; //utf.replace('.', '/');
        }
    }

    static private HashMap mtu = null;
    private synchronized String mimeToUtf(String mime) {
        if (IosSystemClipboard.mtu == null) {
            IosSystemClipboard.mtu = new HashMap(4);
            IosSystemClipboard.mtu.put(TEXT_TYPE, IosPasteboard.UtfString);
            IosSystemClipboard.mtu.put(HTML_TYPE, IosPasteboard.UtfHtml);
            IosSystemClipboard.mtu.put(RTF_TYPE, IosPasteboard.UtfRtf);
            IosSystemClipboard.mtu.put(URI_TYPE, IosPasteboard.UtfUrl);
            IosSystemClipboard.mtu.put(FILE_LIST_TYPE, IosPasteboard.UtfFileUrl);
            // pass RAW_IMAGE_TYPE through - do NOT substitute with UtfTiff or UtfPng!
        }
        if (IosSystemClipboard.mtu.containsKey(mime) == true) {
            return (String)IosSystemClipboard.mtu.get(mime);
        } else {
            return mime; //mime.replace('/', '.');
        }
    }

    private URI createUri(String path, String message) {
        URI uri = null;
        try {
            uri = new URI(path);
        } catch (URISyntaxException ex) {
            System.err.println(message+path);
        }
        return uri;
    }

    private URI createUri(String scheme, String path, String message) {
        URI uri = null;
        try {
            uri = new URI(scheme, null, path, null);
        } catch (URISyntaxException ex) {
            System.err.println(message+path);
        }
        return uri;
    }

    private URL createUrl(String path, String message) {
        URL url = null;
        try {
            url = new URL(path);
        } catch (MalformedURLException ex) {
            System.err.println(message+path);
        }
        return url;
    }

    private byte[] serialize(Object object) {
        if (object instanceof String) {
            String string = (String)object;
            return string.getBytes();
        } else if (object instanceof ByteBuffer) {
            ByteBuffer buffer = (ByteBuffer)object;
            return buffer.array();
        } else {
            throw new RuntimeException("can not handle " + object);
        }
    }
}
