/**
 * Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Eclipse Public License (EPL).
 * Please see the license.txt included with this distribution for details.
 * Any modifications to this file must keep this entire header intact.
 */
package org.python.pydev.shared_interactive_console.console.ui.internal;

import org.eclipse.jface.text.IDocument;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Display;
import org.python.pydev.shared_core.log.Log;
import org.python.pydev.shared_interactive_console.console.ui.ScriptConsolePartitioner;
import org.python.pydev.shared_interactive_console.console.ui.ScriptStyleRange;

/**
 * Helper to add text to the clipboard.
 *
 * @author Fabio
 */
public class ClipboardHandler {

    /**
     * Adds text from the given document to the clipboard, but without the text related to the prompt
     * (gotten from the document partitioner).
     * 
     * @param doc the document from where the text should be gotten
     * @param selectedRange the range selected for saving
     * @param clipboardType the type of the clipboard (see constants in clipboard)
     * @param display the display to be used
     */
    public void putIntoClipboard(IDocument doc, Point selectedRange, int clipboardType, Display display) {

        Clipboard clipboard = new Clipboard(display);
        try {
            TextTransfer plainTextTransfer = TextTransfer.getInstance();

            String plainText = getPlainText(doc, selectedRange);
            if (plainText.length() == 0) {
                return;
            }

            String[] data = new String[] { plainText };
            Transfer[] types = new Transfer[] { plainTextTransfer };

            try {
                clipboard.setContents(data, types, clipboardType);
            } catch (SWTError error) {
                // Copy to clipboard failed. This happens when another application 
                // is accessing the clipboard while we copy. Ignore the error.
                // Fixes 1GDQAVN
                // Rethrow all other errors. Fixes bug 17578.
                if (error.code != DND.ERROR_CANNOT_SET_CLIPBOARD) {
                    throw error;
                }
            }
        } finally {
            clipboard.dispose();
        }
    }

    /**
     * @return the text in the given range that's related to actual code / output (but not the prompt)
     */
    public String getPlainText(IDocument doc, Point selectedRange) {
        StringBuffer plainText = new StringBuffer();

        ScriptConsolePartitioner scriptConsolePartitioner = (ScriptConsolePartitioner) doc.getDocumentPartitioner();
        ScriptStyleRange[] ranges = scriptConsolePartitioner.getStyleRanges(selectedRange.x, selectedRange.y);
        if (ranges.length == 0) {
            return "";
        }

        try {
            int currentRange = 0;
            int minOffset = selectedRange.x;
            int maxOffset = selectedRange.x + selectedRange.y;

            //note: we must iterate through the document and not through the ranges because
            //new lines can have no range associated.
            for (int i = minOffset; i < maxOffset; i++) {
                char c = doc.getChar(i);
                if (c == '\r' || c == '\n') {
                    //new lines should be added for any style.
                    plainText.append(c);
                } else {
                    ScriptStyleRange current = null;
                    while (true) {
                        if (currentRange >= ranges.length) {
                            break;
                        }
                        current = ranges[currentRange];
                        if (current.start <= i && i < current.start + current.length) {
                            break;
                        }
                        currentRange++;
                    }
                    if (current == null) {
                        continue;
                    }
                    if (current.scriptType == ScriptStyleRange.PROMPT) {
                        continue;
                    }
                    plainText.append(c);
                }
            }

        } catch (Exception e) {
            Log.log(e);
        }
        return plainText.toString();
    }

}
