/*******************************************************************************
 * Copyright (c) 2000, 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.ui.console;

import java.util.HashMap;

import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPositionCategoryException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.swt.graphics.Font;
import org.eclipse.ui.internal.console.ConsoleDocument;
import org.eclipse.ui.internal.console.ConsoleHyperlinkPosition;
import org.eclipse.ui.internal.console.ConsolePatternMatcher;
import org.eclipse.ui.part.IPageBookViewPage;

/**
 * An abstract text console that supports regular expression matching and
 * hyperlinks.
 * <p>
 * Pattern match listeners can be registered with a console programmatically
 * or via the <code>org.eclipse.ui.console.consolePatternMatchListeners</code>
 * extension point.
 * </p>
 * <p>
 * Clients may subclass this class. Subclasses must provide a document partitioner.
 * </p>
 * @since 3.1
 */
public abstract class TextConsole extends AbstractConsole {

    /**
     * The current width of the console. Used for fixed width consoles.
     * A value of <=0 means does not have a fixed width.
     */
    private int fConsoleWidth;
    /**
     * The current tab width
     */
    private int fTabWidth;
    /** 
	 * The font used by this console
	 */
    private Font fFont;    
    /**
     * The Console's regular expression pattern matcher
     */
    private ConsolePatternMatcher fPatternMatcher;
    
    /**
     * The Console's document
     */
    private ConsoleDocument fDocument;
    
   /**
    * indication that the console's partitioner is not expecting more input
    */
    private boolean fPartitionerFinished = false;
    
    /**
     * Indication that the console's pattern matcher has finished.
     * (all matches have been found and all listeners notified)
     */
    private boolean fMatcherFinished = false;
    
    /**
     * indication that the console output complete property has been fired
     */
    private boolean fCompleteFired = false;

    
    /**
     * Map of client defined attributes
     */
    private HashMap fAttributes = new HashMap();
    
    private IConsoleManager fConsoleManager = ConsolePlugin.getDefault().getConsoleManager();
    
   
    /* (non-Javadoc)
     * @see org.eclipse.ui.console.AbstractConsole#dispose()
     */
    protected void dispose() {
        super.dispose();
        fFont = null;
		synchronized(fAttributes) {
		    fAttributes.clear();
		}
    }
    /**
     * Constructs a console with the given name, image descriptor, and lifecycle
     * 
     * @param name name to display for this console
     * @param consoleType console type identifier or <code>null</code>
     * @param imageDescriptor image to display for this console or <code>null</code>
     * @param autoLifecycle whether lifecycle methods should be called automatically
     *  when this console is added/removed from the console manager
     */
    public TextConsole(String name, String consoleType, ImageDescriptor imageDescriptor, boolean autoLifecycle) {
        super(name, consoleType, imageDescriptor, autoLifecycle);
        fDocument = new ConsoleDocument();
        fDocument.addPositionCategory(ConsoleHyperlinkPosition.HYPER_LINK_CATEGORY);
        fPatternMatcher = new ConsolePatternMatcher(this);
        fDocument.addDocumentListener(fPatternMatcher);
        fTabWidth = IConsoleConstants.DEFAULT_TAB_SIZE;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.console.IConsole#createPage(org.eclipse.ui.console.IConsoleView)
     */
    public IPageBookViewPage createPage(IConsoleView view) {
        return new TextConsolePage(this, view);
    }
    
	/**
	 * Returns this console's document.
     * <p>
     * Note that a console may or may not support direct manipulation of its document.
     * For example, an I/O console document and its partitions are produced from the
     * streams connected to it, and clients are not intended to modify the document's
     * contents.
     * </p>
	 * 
	 * @return this console's document
	 */
    public IDocument getDocument() {
        return fDocument;
    }
    
    /**
     * Returns the current width of this console. A value of zero of less 
     * indicates this console has no fixed width.
     * 
     * @return the current width of this console
     */
    public int getConsoleWidth() {
        return fConsoleWidth;
    }
    
    /**
     * Sets the width of this console in characters. Any value greater than zero
     * will cause this console to have a fixed width.
     * 
     * @param width the width to make this console. Values of 0 or less imply
     * the console does not have any fixed width.
     */
    public void setConsoleWidth(int width) {
        if (fConsoleWidth != width) {
            int old = fConsoleWidth;
            fConsoleWidth = width;
            
            firePropertyChange(this, IConsoleConstants.P_CONSOLE_WIDTH, new Integer(old), new Integer(fConsoleWidth));
        }
    }

	/**
	 * Sets the tab width used in this console.
	 * 
	 * @param newTabWidth the tab width 
	 */
    public void setTabWidth(final int newTabWidth) {
        if (fTabWidth != newTabWidth) {
            final int oldTabWidth = fTabWidth;
            fTabWidth = newTabWidth;
            ConsolePlugin.getStandardDisplay().asyncExec(new Runnable() {
                public void run() {
                    firePropertyChange(TextConsole.this, IConsoleConstants.P_TAB_SIZE, new Integer(oldTabWidth), new Integer(fTabWidth));           
                }
            });
        }
    }
    
	/**
	 * Returns the tab width used in this console.
	 * 
	 * @return tab width used in this console
	 */
    public int getTabWidth() {
        return fTabWidth;
    }
    
    /**
	 * Returns the font used by this console. Must be called in the UI thread.
	 * 
	 * @return font used by this console
	 */
    public Font getFont() {
        if (fFont == null) {
            fFont = getDefaultFont();
        }
        return fFont;
    }
    
    /**
     * Returns the default text font.
     * 
     * @return the default text font
     */
    private Font getDefaultFont() {
        return JFaceResources.getFont(JFaceResources.TEXT_FONT);
    }
    
	/**
	 * Sets the font used by this console. Specify <code>null</code> to use
	 * the default text font.
	 * 
	 * @param newFont font, or <code>null</code> to indicate the default font
	 */
    public void setFont(Font newFont) {
        // ensure font is initialized
        getFont();
        // translate null to default font
        if (newFont == null) {
            newFont = getDefaultFont();
        }
        // fire property change if required
        if (!fFont.equals(newFont)) {
            Font old = fFont;
            fFont = newFont;
            firePropertyChange(this, IConsoleConstants.P_FONT, old, fFont);
        }
    }
	
    /**
     * Clears the console.
     * <p>
     * Since a console may or may not support direct manipulation
     * of its document's contents, this method should be called to clear a text console's
     * document. The default implementation sets this console's document content
     * to the empty string directly. Subclasses should override as required.
     * </p>
     */
    public void clearConsole() {
        IDocument document = getDocument();
        if (document != null) {
            document.set(""); //$NON-NLS-1$
        }
    }

    /**
     * Returns the console's document partitioner.
     * @return The console's document partitioner
     */
    protected abstract IConsoleDocumentPartitioner getPartitioner();
    
    /**
     * Returns all hyperlinks in this console.
     * 
     * @return all hyperlinks in this console
     */
    public IHyperlink[] getHyperlinks() {
        try {
            Position[] positions = getDocument().getPositions(ConsoleHyperlinkPosition.HYPER_LINK_CATEGORY);
            IHyperlink[] hyperlinks = new IHyperlink[positions.length];
            for (int i = 0; i < positions.length; i++) {
                ConsoleHyperlinkPosition position = (ConsoleHyperlinkPosition) positions[i];
                hyperlinks[i] = position.getHyperLink();
            }
            return hyperlinks;
        } catch (BadPositionCategoryException e) {
            return new IHyperlink[0];
        }
    }
    
    /**
     * Returns the hyperlink at the given offset of <code>null</code> if none.
     * 
     * @param offset offset for which a hyperlink is requested
     * @return the hyperlink at the given offset of <code>null</code> if none
     */
    public IHyperlink getHyperlink(int offset) {
        try {
        	IDocument document = getDocument();
        	if (document != null) {
	            Position[] positions = document.getPositions(ConsoleHyperlinkPosition.HYPER_LINK_CATEGORY);
	            Position position = findPosition(offset, positions);
	            if (position instanceof ConsoleHyperlinkPosition) {
	                return ((ConsoleHyperlinkPosition) position).getHyperLink();
	            }
        	}
        } catch (BadPositionCategoryException e) {
        }        
        return null;
    }

	/**
	 * Binary search for the position at a given offset.
	 *
	 * @param offset the offset whose position should be found
	 * @return the position containing the offset, or <code>null</code>
	 */
	private Position findPosition(int offset, Position[] positions) {
		
		if (positions.length == 0)
			return null;
			
		int left= 0;
		int right= positions.length -1;
		int mid= 0;
		Position position= null;
		
		while (left < right) {
			
			mid= (left + right) / 2;
				
			position= positions[mid];
			if (offset < position.getOffset()) {
				if (left == mid)
					right= left;
				else
					right= mid -1;
			} else if (offset > (position.getOffset() + position.getLength() - 1)) {
				if (right == mid)
					left= right;
				else
					left= mid  +1;
			} else {
				left= right= mid;
			}
		}
		
		position= positions[left];
		if (offset >= position.getOffset() && (offset < (position.getOffset() + position.getLength()))) {
			return position;
		}
		return null;
	}

    /**
     * Adds the given pattern match listener to this console. The listener will
     * be connected and receive match notifications. Has no effect if an identical
     * listener has already been added.
     * 
     * @param listener the listener to add
     */
    public void addPatternMatchListener(IPatternMatchListener listener) {
        fPatternMatcher.addPatternMatchListener(listener);
    }
    
    /**
     * Removes the given pattern match listener from this console. The listener will be
     * disconnected and will no longer receive match notifications. Has no effect
     * if the listener was not previously added.
     * 
     * @param listener the pattern match listener to remove
     */
    public void removePatternMatchListener(IPatternMatchListener listener) {
        fPatternMatcher.removePatternMatchListener(listener);
    }    
    
    
    /**
     * Job scheduling rule that prevent the job from running if the console's PatternMatcher
     * is active.
     */
    private class MatcherSchedulingRule implements ISchedulingRule {
        public boolean contains(ISchedulingRule rule) {
            return rule == this;
        }

        public boolean isConflicting(ISchedulingRule rule) {
            if (contains(rule)) {
                return true;
            }
            if (rule != this && rule instanceof MatcherSchedulingRule) {
                return (((MatcherSchedulingRule)rule).getConsole() == TextConsole.this);   
            }
            return false;
        }
        
        public TextConsole getConsole() {
            return TextConsole.this;
        }
    }
    
    /**
     * Returns a scheduling rule which can be used to prevent jobs from running
     * while this console's pattern matcher is active.
     * <p>
     * Although this scheduling rule prevents jobs from running at the same time as
     * pattern matching jobs for this console, it does not enforce any ordering of jobs.
     * Since 3.2, pattern matching jobs belong to the job family identified by the console
     * object that matching is occurring on. To ensure a job runs after all scheduled pattern
     * matching is complete, clients must join on this console's job family.
     * </p>
     * @return a scheduling rule which can be used to prevent jobs from running
     * while this console's pattern matcher is active
     */
    public ISchedulingRule getSchedulingRule() {
        return new MatcherSchedulingRule();
    }
    
    /**
     * This console's partitioner should call this method when it is not expecting any new data
     * to be appended to the document. 
     */
    public void partitionerFinished() {
        fPatternMatcher.forceFinalMatching();
        fPartitionerFinished  = true;
        checkFinished();
    }
    
    /**
     * Called by this console's pattern matcher when matching is complete.
     * <p>
     * Clients should not call this method.
     * <p>
     */
    public void matcherFinished() {
        fMatcherFinished = true;
        fDocument.removeDocumentListener(fPatternMatcher);
        checkFinished();
    }
    
    /**
     * Fires the console output complete property change event.
     */
    private synchronized void checkFinished() {
        if (!fCompleteFired && fPartitionerFinished && fMatcherFinished ) {
            fCompleteFired = true;
            firePropertyChange(this, IConsoleConstants.P_CONSOLE_OUTPUT_COMPLETE, null, null);
        }
    }
    
    /**
     * Adds a hyperlink to this console.
     * 
     * @param hyperlink the hyperlink to add
     * @param offset the offset in the console document at which the hyperlink should be added
     * @param length the length of the text which should be hyperlinked
     * @throws BadLocationException if the specified location is not valid.
     */
    public void addHyperlink(IHyperlink hyperlink, int offset, int length) throws BadLocationException {
        IDocument document = getDocument();
		ConsoleHyperlinkPosition hyperlinkPosition = new ConsoleHyperlinkPosition(hyperlink, offset, length); 
		try {
			document.addPosition(ConsoleHyperlinkPosition.HYPER_LINK_CATEGORY, hyperlinkPosition);
            fConsoleManager.refresh(this);
		} catch (BadPositionCategoryException e) {
			ConsolePlugin.log(e);
		} 
    }
    
    /**
     * Returns the region assocaited with the given hyperlink.
     * 
     * @param link hyperlink
     * @return the region associated witht the hyperlink or null if the hyperlink is not found.
     */
    public IRegion getRegion(IHyperlink link) {
		try {
		    IDocument doc = getDocument();
		    if (doc != null) {
				Position[] positions = doc.getPositions(ConsoleHyperlinkPosition.HYPER_LINK_CATEGORY);
				for (int i = 0; i < positions.length; i++) {
					ConsoleHyperlinkPosition position = (ConsoleHyperlinkPosition)positions[i];
					if (position.getHyperLink().equals(link)) {
						return new Region(position.getOffset(), position.getLength());
					}
				}
		    }
		} catch (BadPositionCategoryException e) {
		}
		return null;
    }
    
    /**
     * Returns the attribue associated with the specified key.
     * 
     * @param key attribute key
     * @return the attribue associated with the specified key
     */
    public Object getAttribute(String key) {
        synchronized (fAttributes) {
            return fAttributes.get(key);
        }
    }
    
    /**
     * Sets an attribute value. Intended for client data.
     * 
     * @param key attribute key
     * @param value attribute value
     */
    public void setAttribute(String key, Object value) {
        synchronized(fAttributes) {
            fAttributes.put(key, value);
        }
    }
}
