gt: 			if (targetNode != null) {
context: /*******************************************************************************
   * Copyright (c) 2004, 2010 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.wst.css.ui.internal.contentassist;
  
  
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Iterator;
  import java.util.List;
  
  import org.eclipse.wst.css.core.internal.CSSCorePlugin;
  import org.eclipse.wst.css.core.internal.metamodel.CSSMMDescriptor;
  import org.eclipse.wst.css.core.internal.metamodel.CSSMMFunction;
  import org.eclipse.wst.css.core.internal.metamodel.CSSMMNode;
  import org.eclipse.wst.css.core.internal.metamodel.CSSMMNumber;
  import org.eclipse.wst.css.core.internal.metamodel.CSSMMProperty;
  import org.eclipse.wst.css.core.internal.metamodel.CSSMMUnit;
  import org.eclipse.wst.css.core.internal.metamodel.util.CSSFunctionID;
  import org.eclipse.wst.css.core.internal.metamodel.util.CSSMetaModelUtil;
  import org.eclipse.wst.css.core.internal.parserz.CSSRegionContexts;
  import org.eclipse.wst.css.core.internal.preferences.CSSCorePreferenceNames;
  import org.eclipse.wst.css.core.internal.provisional.document.ICSSNode;
  import org.eclipse.wst.css.core.internal.provisional.document.ICSSPrimitiveValue;
  import org.eclipse.wst.css.core.internal.provisional.document.ICSSStyleDeclItem;
  import org.eclipse.wst.css.core.internal.util.CSSUtil;
  import org.eclipse.wst.css.core.internal.util.RegionIterator;
  import org.eclipse.wst.css.ui.internal.image.CSSImageType;
  import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
  import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
  import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
  import org.w3c.dom.css.CSSFontFaceRule;
  
  class CSSProposalGeneratorForDeclarationValue extends CSSProposalGenerator {
  
  	private static final String IMPORTANT = "!important"; //$NON-NLS-1$
  	private boolean fUseUpperCase;
  	private boolean fAppendSemiColon;
  
  	/**
  	 * CSSProposalGeneratorForDeclarationValue constructor comment.
  	 * 
  	 */
  	CSSProposalGeneratorForDeclarationValue(CSSContentAssistContext context) {
  		super(context);
  		fUseUpperCase = CSSCorePlugin.getDefault().getPluginPreferences().getInt(CSSCorePreferenceNames.CASE_PROPERTY_VALUE) == CSSCorePreferenceNames.UPPER;
  	}
  
  	/**
  	 *  
  	 */
  	private void addFunction(List candidates, CSSMMFunction prop) {
  		String text = prop.toString();
  		if (!isMatch(text)) {
  			return;
  		}
  
  		int cursorPos = 0;
  		StringBuffer buf = new StringBuffer();
  		if (prop.getName().equals(CSSFunctionID.F_URI)) {
  			StringAndOffset sao = generateURI();
  			buf.append(sao.fString);
  			cursorPos = sao.fOffset;
  		} else {
  			buf.append(prop.toString());
  			cursorPos = buf.length();
  			StringAndOffset sao = generateParenthesis();
  			buf.append(sao.fString);
  			cursorPos += sao.fOffset;
  		}
  
  		text = buf.toString();
  		text = (fUseUpperCase) ? text.toUpperCase() : text.toLowerCase();
  
  		CSSCACandidate item = new CSSCACandidate();
  		item.setReplacementString(text);
  		item.setCursorPosition(cursorPos);
  		item.setDisplayString(text);
  		item.setMMNode(prop);
  		item.setImageType(CSSImageType.VALUE_FUNCTION);
  		appendSemiColon(item);
  		candidates.add(item);
  	}
  
  	/**
  	 *  
  	 */
  	private void addNumber(List candidates, CSSMMNumber prop) {
  		String fullText = fContext.getTextToReplace();
  		// skip number
  		int unitIndex = -1;
  		for (int i = 0; i < fullText.length(); i++) {
  			if (Character.isDigit(fullText.charAt(i))) {
  				unitIndex = i + 1;
  			} else {
  				break;
  			}
  		}
  
  		String unitSubText = ""; //$NON-NLS-1$
  		String numSubText = ""; //$NON-NLS-1$
  		if (0 <= unitIndex) {
  			numSubText = fullText.substring(0, unitIndex);
  			if (unitIndex < fullText.length()) {
  				unitSubText = fullText.substring(unitIndex);
  			}
  		} else {
  			unitSubText = fullText;
  		}
  
  		Iterator i = prop.getDescendants();
  		while (i.hasNext()) {
  			CSSMMUnit unit = (CSSMMUnit) i.next();
  			String unitString = unit.getUnitString();
  			if ((0 < unitSubText.length() && unitString.indexOf(unitSubText) != 0) || (0 < numSubText.length() && unitString.equals("#"))) { //$NON-NLS-1$
  				continue;
  			}
  
  			String text = numSubText + unitString;
  			text = (fUseUpperCase) ? text.toUpperCase() : text.toLowerCase();
  			CSSCACandidate item = new CSSCACandidate();
  			item.setReplacementString(text);
  			if (0 < numSubText.length() || text.equals("#")) { //$NON-NLS-1$
  				item.setCursorPosition(text.length());
  			} else {
  				item.setCursorPosition(0);
  			}
  			item.setDisplayString(text);
  			item.setImageType(CSSImageType.VALUE_NUMBER);
  			appendSemiColon(item);
  			candidates.add(item);
  		}
  	}
  
  	/**
  	 *  
  	 */
  	private void checkSemiColon() {
  		fAppendSemiColon = false;
  
  		ITextRegion targetRegion = fContext.getTargetRegion();
  		if (targetRegion != null && targetRegion.getType() != CSSRegionContexts.CSS_DECLARATION_DELIMITER) {
  			// find trailing ":" or ";"
  			// if ":" before ";" is found, add ";"
  			RegionIterator iterator = fContext.getRegionIterator();
  			IStructuredDocumentRegion container = iterator.getStructuredDocumentRegion();
  			while (iterator.hasNext()) {
  				ITextRegion region = iterator.next();
  				if (iterator.getStructuredDocumentRegion() != container) {
  					break;
  				}
  				if (region.getType() == CSSRegionContexts.CSS_DECLARATION_SEPARATOR) {
  					fAppendSemiColon = true;
  					break;
  				}
  			}
  			if (!fAppendSemiColon) {
  				// second chance:
  				// leading IStructuredDocumentRegion is not ";"
  				IStructuredDocumentRegion nextStructuredDocumentRegion = CSSUtil.findNextSignificantNode(container);
  				if (CSSUtil.getStructuredDocumentRegionType(nextStructuredDocumentRegion) != CSSRegionContexts.CSS_DECLARATION_DELIMITER) {
  					fAppendSemiColon = true;
  				}
  			}
  		}
  	}
  
  	/**
  	 *  
  	 */
  	private void appendSemiColon(CSSCACandidate item) {
  		if (fAppendSemiColon) {
  			String replacementString = item.getReplacementString();
  			item.setReplacementString(replacementString + ";"); //$NON-NLS-1$
  			int cursorPosition = item.getCursorPosition();
  			if (replacementString.length() <= cursorPosition) {
  				// cursorpos is tail of string
  				cursorPosition++;
  				item.setCursorPosition(cursorPosition);
  			}
  		}
  	}
  
  	/**
  	 *  
  	 */
  	private void addSemiColon(List candidates) {
  		ICSSNode targetNode = fContext.getTargetNode();
  		if (targetNode instanceof ICSSStyleDeclItem) {
  			ICSSNode firstChild = targetNode.getFirstChild();
  			if (firstChild == null) {
  				return;
  			}
  			if (firstChild instanceof IndexedRegion) {
  				int startOffset = ((IndexedRegion) firstChild).getStartOffset();
  				if (fContext.getCursorPos() <= startOffset) {
  					return;
  				}
  			}
  		}
  
  		boolean bAddCloser = false;
  
  		ITextRegion targetRegion = fContext.getTargetRegion();
  		if (targetRegion != null && targetRegion.getType() != CSSRegionContexts.CSS_DECLARATION_DELIMITER) {
  			// find trailing ":" or ";"
  			// if ":" before ";" is found, add ";"
  			RegionIterator iterator = fContext.getRegionIterator();
  			IStructuredDocumentRegion container = iterator.getStructuredDocumentRegion();
  			while (iterator.hasNext()) {
  				ITextRegion region = iterator.next();
  				if (iterator.getStructuredDocumentRegion() != container) {
  					break;
  				}
  				if (region.getType() == CSSRegionContexts.CSS_DECLARATION_SEPARATOR) {
  					bAddCloser = true;
  					break;
  				}
  			}
  			if (!bAddCloser) {
  				// second chance:
  				// leading IStructuredDocumentRegion is not ";"
  				IStructuredDocumentRegion nextStructuredDocumentRegion = CSSUtil.findNextSignificantNode(container);
  				if (CSSUtil.getStructuredDocumentRegionType(nextStructuredDocumentRegion) != CSSRegionContexts.CSS_DECLARATION_DELIMITER) {
  					bAddCloser = true;
  				}
  			}
  		}
  
  		if (bAddCloser) {
  			CSSCACandidate item = new CSSCACandidate();
  			String text = fContext.getTextToReplace() + ";";//$NON-NLS-1$
  			item.setReplacementString(text);
  			item.setCursorPosition(text.length());
  			item.setDisplayString(";");//$NON-NLS-1$
  			item.setImageType(null);
  			candidates.add(item);
  		}
  	}
  
  	/**
  	 *  
  	 */
  	private void addString(List candidates, String text) {
  		if (!isMatch(text)) {
  			return;
  		}
  
  		text = (fUseUpperCase) ? text.toUpperCase() : text.toLowerCase();
  
  		CSSCACandidate item = new CSSCACandidate();
  		item.setReplacementString(text);
  		item.setCursorPosition(text.length());
  		item.setDisplayString(text);
  		item.setImageType(CSSImageType.VALUE_STRING);
  		appendSemiColon(item);
  		candidates.add(item);
  	}
  
  	private void addImportant(List candidates) {
  		ICSSNode targetNode = fContext.getTargetNode();
  		while (targetNode instanceof ICSSPrimitiveValue) {
  			targetNode = targetNode.getParentNode();
  		}
  		if (!(targetNode instanceof ICSSStyleDeclItem)) {
  			return;
  		}
  		// 1. has no priority region
  		// 2. cursor position is after of last child
  		// 3. normal isMatch method
  		String priority = ((ICSSStyleDeclItem) targetNode).getPriority();
  		if (priority == null || priority.length() == 0) {
  			ICSSNode lastChild = targetNode.getLastChild();
  			if (lastChild instanceof IndexedRegion) {
  				int startOffset = ((IndexedRegion) lastChild).getStartOffset();
  				//	int endOffset = ((IndexedRegion)lastChild).getEndOffset();
  				if (startOffset < fContext.getCursorPos() && isMatch(IMPORTANT)) {
  					CSSCACandidate item = new CSSCACandidate();
  					item.setReplacementString(IMPORTANT);
  					item.setCursorPosition(IMPORTANT.length());
  					item.setDisplayString(IMPORTANT);
  					item.setImageType(CSSImageType.VALUE_STRING);
  					appendSemiColon(item);
  					candidates.add(item);
  				}
  			}
  		}
  	}
  
  	/**
  	 * getCandidates method comment.
  	 */
  	protected Iterator getCandidates() {
  		List candidates = new ArrayList();
  
  		checkSemiColon(); // check should add semi-colon or not
  
  		String name = getPropertyName();
  		if (name != null) {
  			CSSMetaModelUtil util = new CSSMetaModelUtil(fContext.getMetaModel());
  			Iterator i = Collections.EMPTY_LIST.iterator();
  			if (isFontFaceRule()) {
  				CSSMMDescriptor desc = util.getDescriptor(name);
  				if (desc != null) {
  					i = desc.getValues();
  				}
  			} else {
  				CSSMMProperty prop = util.getProperty(name);
  				if (prop != null) {
  					i = prop.getValues();
  				}
  			}
  			while (i.hasNext()) {
  				CSSMMNode val = (CSSMMNode) i.next();
  				String valueType = val.getType();
  				if (valueType == CSSMMNode.TYPE_KEYWORD) {
  					addString(candidates, val.toString());
  				} else if (valueType == CSSMMNode.TYPE_NUMBER) {
  					addNumber(candidates, (CSSMMNumber) val);
  				} else if (valueType == CSSMMNode.TYPE_FUNCTION) {
  					addFunction(candidates, (CSSMMFunction) val);
  				}
  			}
  		}
  
  		addImportant(candidates);
  		addSemiColon(candidates);
  
  		return candidates.iterator();
  	}
  
  	/**
  	 * @return java.lang.String
  	 */
  	private String getPropertyName() {
  		ICSSNode targetNode = fContext.getTargetNode();
  		while (targetNode instanceof ICSSPrimitiveValue) {
  			targetNode = targetNode.getParentNode();
  		}
  		if (targetNode instanceof ICSSStyleDeclItem) {
  			return ((ICSSStyleDeclItem) targetNode).getPropertyName();
  		} else {
  			return null;
  		}
  	}
  
  	/**
  	 *  
  	 */
  	private boolean isFontFaceRule() {
  		ICSSNode targetNode = fContext.getTargetNode();
  		while (targetNode instanceof ICSSPrimitiveValue) {
  			targetNode = targetNode.getParentNode();
  		}
  		if (targetNode instanceof ICSSStyleDeclItem) {
  			targetNode = targetNode.getParentNode(); // get Declaration
  