Index: Scribe.java
===================================================================
--- Scribe.java	(.../trunk/eclipseformatter/Scribe.java)	(revision 49)
+++ Scribe.java	(.../branches/ef-changed/eclipseformatter/CodeFormatterVisitor.java)	(revision 49)
@@ -1,5 +1,11 @@
+/*
+ * This file has been modified to allow the code
+ * formatter to insert curly braces {}.
+ * See http://kruithof.xs4all.nl//eclipseform/eclipsewithbraces.html
+ * for more info.
+ */
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2002, 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
@@ -10,1554 +16,5276 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.formatter;
 
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Map;
 
 import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.core.compiler.InvalidInputException;
+import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
-import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
+import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression;
+import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
+import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.ArrayReference;
+import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.AssertStatement;
+import org.eclipse.jdt.internal.compiler.ast.Assignment;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
+import org.eclipse.jdt.internal.compiler.ast.Block;
+import org.eclipse.jdt.internal.compiler.ast.BreakStatement;
+import org.eclipse.jdt.internal.compiler.ast.CaseStatement;
+import org.eclipse.jdt.internal.compiler.ast.CastExpression;
+import org.eclipse.jdt.internal.compiler.ast.CharLiteral;
+import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
+import org.eclipse.jdt.internal.compiler.ast.Clinit;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.CompoundAssignment;
+import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ContinueStatement;
+import org.eclipse.jdt.internal.compiler.ast.DoStatement;
+import org.eclipse.jdt.internal.compiler.ast.DoubleLiteral;
+import org.eclipse.jdt.internal.compiler.ast.EmptyStatement;
+import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
+import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.FieldReference;
+import org.eclipse.jdt.internal.compiler.ast.FloatLiteral;
+import org.eclipse.jdt.internal.compiler.ast.ForStatement;
+import org.eclipse.jdt.internal.compiler.ast.ForeachStatement;
+import org.eclipse.jdt.internal.compiler.ast.IfStatement;
+import org.eclipse.jdt.internal.compiler.ast.ImportReference;
+import org.eclipse.jdt.internal.compiler.ast.Initializer;
+import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression;
+import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
+import org.eclipse.jdt.internal.compiler.ast.LabeledStatement;
+import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.LongLiteral;
+import org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation;
+import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
+import org.eclipse.jdt.internal.compiler.ast.MessageSend;
+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
+import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
+import org.eclipse.jdt.internal.compiler.ast.StringLiteralConcatenation;
+import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
+import org.eclipse.jdt.internal.compiler.ast.OR_OR_Expression;
+import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
+import org.eclipse.jdt.internal.compiler.ast.PostfixExpression;
+import org.eclipse.jdt.internal.compiler.ast.PrefixExpression;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
+import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.Statement;
+import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
+import org.eclipse.jdt.internal.compiler.ast.SuperReference;
+import org.eclipse.jdt.internal.compiler.ast.SwitchStatement;
+import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement;
+import org.eclipse.jdt.internal.compiler.ast.ThisReference;
+import org.eclipse.jdt.internal.compiler.ast.ThrowStatement;
+import org.eclipse.jdt.internal.compiler.ast.TrueLiteral;
+import org.eclipse.jdt.internal.compiler.ast.TryStatement;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.ast.UnaryExpression;
+import org.eclipse.jdt.internal.compiler.ast.WhileStatement;
+import org.eclipse.jdt.internal.compiler.ast.Wildcard;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
+import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
 import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil;
-import org.eclipse.jdt.internal.core.util.RecordedParsingInformation;
 import org.eclipse.jdt.internal.formatter.align.Alignment;
 import org.eclipse.jdt.internal.formatter.align.AlignmentException;
-import org.eclipse.text.edits.MultiTextEdit;
-import org.eclipse.text.edits.ReplaceEdit;
+import org.eclipse.jdt.internal.formatter.comment.CommentRegion;
 import org.eclipse.text.edits.TextEdit;
 
 /**
- * This class is responsible for dumping formatted source
+ * This class is responsible for formatting a valid java source code.
  * @since 2.1
  */
-public class Scribe {
-	private static final String EMPTY_STRING = ""; //$NON-NLS-1$
+/*
+   <extension
+         id="org.eclipse.jdt.core.newformatter.codeformatter"
+         name="org.eclipse.jdt.core.newformatter.codeformatter"
+         point="org.eclipse.jdt.core.codeFormatter">
+      <codeFormatter
+            class="org.eclipse.jdt.internal.formatter.CodeFormatterVisitor">
+      </codeFormatter>
+   </extension>
+*/
+public class CodeFormatterVisitor extends ASTVisitor {
 
-	private static final int INITIAL_SIZE = 100;
-	
-	private boolean checkLineWrapping;
-	/** one-based column */
-	public int column;
-	private int[][] commentPositions;
+	public static class MultiFieldDeclaration extends FieldDeclaration {
 		
-	// Most specific alignment. 
-	public Alignment currentAlignment;
-	public int currentToken;
+		FieldDeclaration[] declarations;
+		
+		MultiFieldDeclaration(FieldDeclaration[] declarations){
+			this.declarations = declarations;
+			this.modifiers = declarations[0].modifiers; 
+		}
+	}
 	
-	// edits management
-	private OptimizedReplaceEdit[] edits;
-	public int editsIndex;
-	
-	public CodeFormatterVisitor formatter;
-	public int indentationLevel;	
-	public int lastNumberOfNewLines;
-	public int line;
-	
-	private int[] lineEnds;
-	private String lineSeparator;
-	public Alignment memberAlignment;
-	public boolean needSpace = false;
-	
-	public int nlsTagCounter;
-	public int pageWidth;
-	public boolean pendingSpace = false;
+	public static boolean DEBUG = false;
+	private static final int NO_MODIFIERS = 0;
+	/*
+	 * Set of expected tokens type for a single type reference.
+	 * This array needs to be SORTED.
+	 */
+	private static final int[] SINGLETYPEREFERENCE_EXPECTEDTOKENS = new int[] {
+		TerminalTokens.TokenNameIdentifier,
+		TerminalTokens.TokenNameboolean,
+		TerminalTokens.TokenNamebyte,
+		TerminalTokens.TokenNamechar,
+		TerminalTokens.TokenNamedouble,
+		TerminalTokens.TokenNamefloat,
+		TerminalTokens.TokenNameint,
+		TerminalTokens.TokenNamelong,
+		TerminalTokens.TokenNameshort,
+		TerminalTokens.TokenNamevoid
+	};
+	private static final int[] CLOSING_GENERICS_EXPECTEDTOKENS = new int[] {
+		TerminalTokens.TokenNameRIGHT_SHIFT,
+		TerminalTokens.TokenNameUNSIGNED_RIGHT_SHIFT,
+		TerminalTokens.TokenNameGREATER
+	};
+	private int chunkKind;
+	public int lastLocalDeclarationSourceStart;
+	private Scanner localScanner;
+	public DefaultCodeFormatterOptions preferences;
+	public Scribe scribe;
 
-	public Scanner scanner;
-	public int scannerEndPosition;
-	public int tabLength;	
-	public int indentationSize;	
-	private int textRegionEnd;
-	private int textRegionStart;
-	public int tabChar;
-	public int numberOfIndentations;
-	private boolean useTabsOnlyForLeadingIndents;
-
-    /** indent empty lines*/
-    private final boolean indentEmptyLines;
-    
-	Scribe(CodeFormatterVisitor formatter, Map settings, int offset, int length, CodeSnippetParsingUtil codeSnippetParsingUtil) {
+	public CodeFormatterVisitor(DefaultCodeFormatterOptions preferences, Map settings, int offset, int length, CodeSnippetParsingUtil codeSnippetParsingUtil) {
 		if (settings != null) {
-			Object sourceLevelOption = settings.get(JavaCore.COMPILER_SOURCE);
+			Object assertModeSetting = settings.get(JavaCore.COMPILER_SOURCE);
 			long sourceLevel = ClassFileConstants.JDK1_3;
-			if (JavaCore.VERSION_1_4.equals(sourceLevelOption)) {
+			if (JavaCore.VERSION_1_4.equals(assertModeSetting)) {
 				sourceLevel = ClassFileConstants.JDK1_4;
-			} else if (JavaCore.VERSION_1_5.equals(sourceLevelOption)) {
+			} else if (JavaCore.VERSION_1_5.equals(assertModeSetting)) {
 				sourceLevel = ClassFileConstants.JDK1_5;
-			}
-			this.scanner = new Scanner(true, true, false/*nls*/, sourceLevel/*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
+			}		
+			this.localScanner = new Scanner(true, false, false/*nls*/, sourceLevel/*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
 		} else {
-			this.scanner = new Scanner(true, true, false/*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
+			this.localScanner = new Scanner(true, false, false/*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
 		}
-		this.formatter = formatter;
-		this.pageWidth = formatter.preferences.page_width;
-		this.tabLength = formatter.preferences.tab_size;
-		this.indentationLevel= 0; // initialize properly
-		this.numberOfIndentations = 0;
-		this.useTabsOnlyForLeadingIndents = formatter.preferences.use_tabs_only_for_leading_indentations;
-        this.indentEmptyLines = formatter.preferences.indent_empty_lines;
-		this.tabChar = formatter.preferences.tab_char;
-		if (this.tabChar == DefaultCodeFormatterOptions.MIXED) {
-			this.indentationSize = formatter.preferences.indentation_size;
-		} else {
-			this.indentationSize = this.tabLength;
-		}
-		this.lineSeparator = formatter.preferences.line_separator;
-		this.indentationLevel = formatter.preferences.initial_indentation_level * this.indentationSize;
-		this.textRegionStart = offset;
-		this.textRegionEnd = offset + length - 1;
-		if (codeSnippetParsingUtil != null) {
-			final RecordedParsingInformation information = codeSnippetParsingUtil.recordedParsingInformation;
-			if (information != null) {
-				this.lineEnds = information.lineEnds;
-				this.commentPositions = information.commentPositions;
-			}
-		}
-		reset();
+		
+		this.preferences = preferences;
+		this.scribe = new Scribe(this, settings, offset, length, codeSnippetParsingUtil);
 	}
 	
-	private final void addDeleteEdit(int start, int end) {
-		if (this.edits.length == this.editsIndex) {
-			// resize
-			resize();
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#acceptProblem(org.eclipse.jdt.core.compiler.IProblem)
+	 */
+	public void acceptProblem(IProblem problem) {
+		super.acceptProblem(problem);
+	}
+
+	private BinaryExpressionFragmentBuilder buildFragments(BinaryExpression binaryExpression, BlockScope scope) {
+		BinaryExpressionFragmentBuilder builder = new BinaryExpressionFragmentBuilder();
+
+		switch((binaryExpression.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) {
+			case OperatorIds.MULTIPLY :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameMULTIPLY));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.PLUS :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNamePLUS));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.DIVIDE :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameDIVIDE));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.REMAINDER :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameREMAINDER));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.XOR :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameXOR));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.MINUS :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameMINUS));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.OR :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameOR));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.AND :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameAND));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.AND_AND :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameAND_AND));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.OR_OR :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameOR_OR));
+				binaryExpression.right.traverse(builder, scope);
+				break;
 		}
-		addOptimizedReplaceEdit(start, end - start + 1, EMPTY_STRING);
+
+		return builder;
 	}
 
-	public final void addInsertEdit(int insertPosition, String insertedString) {
-		if (this.edits.length == this.editsIndex) {
-			// resize
-			resize();
+	private CascadingMethodInvocationFragmentBuilder buildFragments(MessageSend messageSend, BlockScope scope) {
+		CascadingMethodInvocationFragmentBuilder builder = new CascadingMethodInvocationFragmentBuilder();
+
+		messageSend.traverse(builder, scope);
+		return builder;
+	}	
+	public boolean checkChunkStart(int kind) {
+		if (this.chunkKind != kind) {
+			this.chunkKind = kind;
+			return true;
 		}
-		addOptimizedReplaceEdit(insertPosition, 0, insertedString);
+		return false;
 	}
+	
+	private boolean commentStartsBlock(int start, int end) {
+		this.localScanner.resetTo(start, end);
+		try {
+			if (this.localScanner.getNextToken() ==  TerminalTokens.TokenNameLBRACE) {
+				switch(this.localScanner.getNextToken()) {
+					case TerminalTokens.TokenNameCOMMENT_BLOCK :
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+					case TerminalTokens.TokenNameCOMMENT_LINE :
+						return true;
+				}
+			}
+		} catch(InvalidInputException e) {
+			// ignore
+		}
+		return false;
+	}
 
-	private final void addOptimizedReplaceEdit(int offset, int length, String replacement) {
-		if (this.editsIndex > 0) {
-			// try to merge last two edits
-			final OptimizedReplaceEdit previous = this.edits[this.editsIndex-1];
-			final int previousOffset = previous.offset;
-			final int previousLength = previous.length;
-			final int endOffsetOfPreviousEdit = previousOffset + previousLength;
-			final int replacementLength = replacement.length();
-			final String previousReplacement = previous.replacement;
-			final int previousReplacementLength = previousReplacement.length();
-			if (previousOffset == offset && previousLength == length && (replacementLength == 0 || previousReplacementLength == 0)) {
-				if (this.currentAlignment != null) {
-					final Location location = this.currentAlignment.location;
-					if (location.editsIndex == this.editsIndex) {
-						location.editsIndex--;
-						location.textEdit = previous;
+	private ASTNode[] computeMergedMemberDeclarations(ASTNode[] nodes){
+		ArrayList mergedNodes = new ArrayList();
+		for (int i = 0, max = nodes.length; i < max; i++) {
+			ASTNode currentNode = nodes[i];
+			if (currentNode instanceof FieldDeclaration) {
+				FieldDeclaration currentField = (FieldDeclaration) currentNode;
+				if (mergedNodes.size() == 0) {
+					// first node
+					mergedNodes.add(currentNode);
+				} else {
+					// we need to check if the previous merged node is a field declaration
+					ASTNode previousMergedNode = (ASTNode) mergedNodes.get(mergedNodes.size() - 1);
+					if (previousMergedNode instanceof MultiFieldDeclaration) {
+						// we merge the current node
+						MultiFieldDeclaration multiFieldDeclaration = (MultiFieldDeclaration) previousMergedNode;
+						int length = multiFieldDeclaration.declarations.length;
+						System.arraycopy(multiFieldDeclaration.declarations, 0, multiFieldDeclaration.declarations= new FieldDeclaration[length+1], 0, length);
+						multiFieldDeclaration.declarations[length] = currentField;
+					} else if (previousMergedNode instanceof FieldDeclaration) {
+						// need to check we need to create a multiple field declaration
+						if (currentField.declarationSourceStart == ((FieldDeclaration) previousMergedNode).declarationSourceStart) {
+							// we create a multi field declaration
+							mergedNodes.set(mergedNodes.size() - 1, new MultiFieldDeclaration(new FieldDeclaration[]{ (FieldDeclaration)previousMergedNode, currentField}));
+						} else {
+							mergedNodes.add(currentNode);
+						}
+					} else {
+						mergedNodes.add(currentNode);
 					}
 				}
-				this.editsIndex--;
-				return;
+			} else {
+				mergedNodes.add(currentNode);
 			}
-			if (endOffsetOfPreviousEdit == offset) {
-				if (length != 0) {
-					if (replacementLength != 0) {
-						this.edits[this.editsIndex - 1] = new OptimizedReplaceEdit(previousOffset, previousLength + length, previousReplacement + replacement);
-					} else if (previousLength + length == previousReplacementLength) {
-						// check the characters. If they are identical, we can get rid of the previous edit
-						boolean canBeRemoved = true;
-						loop: for (int i = previousOffset; i < previousOffset + previousReplacementLength; i++) {
-							if (scanner.source[i] != previousReplacement.charAt(i - previousOffset)) {
-								this.edits[this.editsIndex - 1] = new OptimizedReplaceEdit(previousOffset, previousReplacementLength, previousReplacement);
-								canBeRemoved = false;
-								break loop;
-							}
+		}
+		if (mergedNodes.size() != nodes.length) {
+			ASTNode[] result = new ASTNode[mergedNodes.size()];
+			mergedNodes.toArray(result);
+			return result;
+		} else {
+			return nodes;
+		}
+	}
+	
+	private ASTNode[] computeMergedMemberDeclarations(TypeDeclaration typeDeclaration){
+		
+		int fieldIndex = 0, fieldCount = (typeDeclaration.fields == null) ? 0 : typeDeclaration.fields.length;
+		FieldDeclaration field = fieldCount == 0 ? null : typeDeclaration.fields[fieldIndex];
+		int fieldStart = field == null ? Integer.MAX_VALUE : field.declarationSourceStart;
+
+		int methodIndex = 0, methodCount = (typeDeclaration.methods == null) ? 0 : typeDeclaration.methods.length;
+		AbstractMethodDeclaration method = methodCount == 0 ? null : typeDeclaration.methods[methodIndex];
+		int methodStart = method == null ? Integer.MAX_VALUE : method.declarationSourceStart;
+
+		int typeIndex = 0, typeCount = (typeDeclaration.memberTypes == null) ? 0 : typeDeclaration.memberTypes.length;
+		TypeDeclaration type = typeCount == 0 ? null : typeDeclaration.memberTypes[typeIndex];
+		int typeStart = type == null ? Integer.MAX_VALUE : type.declarationSourceStart;
+	
+		final int memberLength = fieldCount+methodCount+typeCount;
+		ASTNode[] members = new ASTNode[memberLength];
+		if (memberLength != 0) {
+			int index = 0;
+			int previousFieldStart = -1;
+			do {
+				if (fieldStart < methodStart && fieldStart < typeStart) {
+					if (field.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
+						// filter out enum constants
+						previousFieldStart = fieldStart;
+						if (++fieldIndex < fieldCount) { // find next field if any
+							fieldStart = (field = typeDeclaration.fields[fieldIndex]).declarationSourceStart;
+						} else {
+							fieldStart = Integer.MAX_VALUE;
 						}
-						if (canBeRemoved) {
-							if (this.currentAlignment != null) {
-								final Location location = this.currentAlignment.location;
-								if (location.editsIndex == this.editsIndex) {
-									location.editsIndex--;
-									location.textEdit = previous;
-								}
-							}
-							this.editsIndex--;
+						continue;
+					}
+					// next member is a field
+					if (fieldStart == previousFieldStart){ 
+						ASTNode previousMember = members[index - 1];
+						if (previousMember instanceof MultiFieldDeclaration) {
+							MultiFieldDeclaration multiField = (MultiFieldDeclaration) previousMember;
+							int length = multiField.declarations.length;
+							System.arraycopy(multiField.declarations, 0, multiField.declarations=new FieldDeclaration[length+1], 0, length);
+							multiField.declarations[length] = field;
+						} else {
+							members[index - 1] = new MultiFieldDeclaration(new FieldDeclaration[]{ (FieldDeclaration)previousMember, field});
 						}
 					} else {
-						this.edits[this.editsIndex - 1] = new OptimizedReplaceEdit(previousOffset, previousLength + length, previousReplacement);
+						members[index++] = field;					
 					}
+					previousFieldStart = fieldStart;
+					if (++fieldIndex < fieldCount) { // find next field if any
+						fieldStart = (field = typeDeclaration.fields[fieldIndex]).declarationSourceStart;
+					} else {
+						fieldStart = Integer.MAX_VALUE;
+					}
+				} else if (methodStart < fieldStart && methodStart < typeStart) {
+					// next member is a method
+					if (!method.isDefaultConstructor() && !method.isClinit()) {
+						members[index++] = method;					
+					}
+					if (++methodIndex < methodCount) { // find next method if any
+						methodStart = (method = typeDeclaration.methods[methodIndex]).declarationSourceStart;
+					} else {
+						methodStart = Integer.MAX_VALUE;
+					}
 				} else {
-					if (replacementLength != 0) {
-						this.edits[this.editsIndex - 1] = new OptimizedReplaceEdit(previousOffset, previousLength, previousReplacement + replacement);
+					// next member is a type
+					members[index++] = type;
+					if (++typeIndex < typeCount) { // find next type if any
+						typeStart = (type = typeDeclaration.memberTypes[typeIndex]).declarationSourceStart;
+					} else {
+						typeStart = Integer.MAX_VALUE;
 					}
 				}
-			} else {
-				this.edits[this.editsIndex++] = new OptimizedReplaceEdit(offset, length, replacement);
+			} while ((fieldIndex < fieldCount) || (typeIndex < typeCount) || (methodIndex < methodCount));
+			
+			if (members.length != index) {
+				System.arraycopy(members, 0, members=new ASTNode[index], 0, index);
 			}
+		}
+		return members;
+	}
+	
+	private boolean dumpBinaryExpression(
+		BinaryExpression binaryExpression,
+		int operator,
+		BlockScope scope) {
+
+		final int numberOfParens = (binaryExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(binaryExpression, numberOfParens);
+		}	
+		BinaryExpressionFragmentBuilder builder = buildFragments(binaryExpression, scope);
+		final int fragmentsSize = builder.size();
+		
+		if ((builder.realFragmentsSize() > 1 || builder.size() > 4) && numberOfParens == 0) {
+			this.scribe.printComment();
+			Alignment binaryExpressionAlignment = this.scribe.createAlignment("binaryExpressionAlignment", this.preferences.alignment_for_binary_expression, Alignment.R_OUTERMOST, fragmentsSize, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+			this.scribe.enterAlignment(binaryExpressionAlignment);
+			boolean ok = false;
+			ASTNode[] fragments = builder.fragments();
+			int[] operators = builder.operators();
+			do {
+				try {
+					for (int i = 0; i < fragmentsSize - 1; i++) {
+						ASTNode fragment = fragments[i];
+						fragment.traverse(this, scope);
+						this.scribe.printTrailingComment();
+						if (this.scribe.lastNumberOfNewLines == 1) {
+							// a new line has been inserted by printTrailingComment()
+							this.scribe.indentationLevel = binaryExpressionAlignment.breakIndentationLevel;
+						}
+						this.scribe.alignFragment(binaryExpressionAlignment, i);
+						this.scribe.printNextToken(operators[i], this.preferences.insert_space_before_binary_operator);
+						if (operators[i] == TerminalTokens.TokenNameMINUS && isNextToken(TerminalTokens.TokenNameMINUS)) {
+							// the next character is a minus (unary operator)
+							this.scribe.space();
+						}
+						if (this.preferences.insert_space_after_binary_operator) {
+							this.scribe.space();
+						}
+					}
+					fragments[fragmentsSize - 1].traverse(this, scope);
+					this.scribe.printTrailingComment();
+					ok = true;
+				} catch(AlignmentException e){
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);		
+			this.scribe.exitAlignment(binaryExpressionAlignment, true);
 		} else {
-			this.edits[this.editsIndex++] = new OptimizedReplaceEdit(offset, length, replacement);
+			binaryExpression.left.traverse(this, scope);
+			this.scribe.printNextToken(operator, this.preferences.insert_space_before_binary_operator);
+			if (operator == TerminalTokens.TokenNameMINUS && isNextToken(TerminalTokens.TokenNameMINUS)) {
+				// the next character is a minus (unary operator)
+				this.scribe.space();
+			}
+			if (this.preferences.insert_space_after_binary_operator) {
+				this.scribe.space();
+			}
+			binaryExpression.right.traverse(this, scope);
+		}	
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(binaryExpression, numberOfParens);
 		}
+		return false;
 	}
+
+	private boolean dumpEqualityExpression(
+		BinaryExpression binaryExpression,
+		int operator,
+		BlockScope scope) {
 	
-	public final void addReplaceEdit(int start, int end, String replacement) {
-		if (this.edits.length == this.editsIndex) {
-			// resize
-			resize();
+		final int numberOfParens = (binaryExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+	
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(binaryExpression, numberOfParens);
+		}	
+		binaryExpression.left.traverse(this, scope);
+		this.scribe.printNextToken(operator, this.preferences.insert_space_before_binary_operator);
+		if (this.preferences.insert_space_after_binary_operator) {
+			this.scribe.space();
 		}
-		addOptimizedReplaceEdit(start,  end - start + 1, replacement);
+		binaryExpression.right.traverse(this, scope);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(binaryExpression, numberOfParens);
+		}
+		return false;
 	}
 
-	public void alignFragment(Alignment alignment, int fragmentIndex){
-		alignment.fragmentIndex = fragmentIndex;
-		alignment.checkColumn();
-		alignment.performFragmentEffect();
+	private final TextEdit failedToFormat() {
+		if (DEBUG) {
+			System.out.println("COULD NOT FORMAT \n" + this.scribe.scanner); //$NON-NLS-1$
+			System.out.println(this.scribe);
+		}
+		return null;
 	}
+
+	private void format(
+		AbstractMethodDeclaration methodDeclaration,
+		ClassScope scope,
+		boolean isChunkStart,
+		boolean isFirstClassBodyDeclaration) {
+
+		if (isFirstClassBodyDeclaration) {
+			int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+			if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
+			}
+		} else {
+			final int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+			if (newLineBeforeChunk > 0) {
+				this.scribe.printEmptyLines(newLineBeforeChunk);
+			}
+		}
+		final int newLinesBeforeMethod = this.preferences.blank_lines_before_method;
+		if (newLinesBeforeMethod > 0 && !isFirstClassBodyDeclaration) {
+			this.scribe.printEmptyLines(newLinesBeforeMethod);
+		} else if (this.scribe.line != 0 || this.scribe.column != 1) {
+			this.scribe.printNewLine();
+		}
+		methodDeclaration.traverse(this, scope);
+	}
+
+	private void format(FieldDeclaration fieldDeclaration, ASTVisitor visitor, MethodScope scope, boolean isChunkStart, boolean isFirstClassBodyDeclaration) {
+		
+		if (isFirstClassBodyDeclaration) {
+			int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+			if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
+			}
+		} else {
+			int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+			if (newLineBeforeChunk > 0) {
+				this.scribe.printEmptyLines(newLineBeforeChunk);
+			}
+			final int newLinesBeforeField = this.preferences.blank_lines_before_field;
+			if (newLinesBeforeField > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeField);
+			}
+		}
+		Alignment memberAlignment = this.scribe.getMemberAlignment();
 	
-	public void checkNLSTag(int sourceStart) {
-		if (hasNLSTag(sourceStart)) {
-			this.nlsTagCounter++;
+        this.scribe.printComment();
+		this.scribe.printModifiers(fieldDeclaration.annotations, this);
+		this.scribe.space();
+		/*
+		 * Field type
+		 */
+		fieldDeclaration.type.traverse(this, scope);
+		
+		/*
+		 * Field name
+		 */
+		this.scribe.alignFragment(memberAlignment, 0);
+	
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true);
+	
+		/*
+		 * Check for extra dimensions
+		 */
+		int extraDimensions = getDimensions();
+		if (extraDimensions != 0) {
+			 for (int i = 0; i < extraDimensions; i++) {
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			 }
 		}
+	
+		/*
+		 * Field initialization
+		 */
+		final Expression initialization = fieldDeclaration.initialization;
+		if (initialization != null) {
+			this.scribe.alignFragment(memberAlignment, 1);
+			this.scribe.printNextToken(TerminalTokens.TokenNameEQUAL, this.preferences.insert_space_before_assignment_operator);
+			if (this.preferences.insert_space_after_assignment_operator) {
+				this.scribe.space();
+			}
+			Alignment assignmentAlignment = this.scribe.createAlignment("fieldDeclarationAssignmentAlignment", this.preferences.alignment_for_assignment, Alignment.R_OUTERMOST, 1, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+			this.scribe.enterAlignment(assignmentAlignment);
+			boolean ok = false;
+			do {
+				try {
+					this.scribe.alignFragment(assignmentAlignment, 0);
+					initialization.traverse(this, scope);
+					ok = true;
+				} catch(AlignmentException e){
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);		
+			this.scribe.exitAlignment(assignmentAlignment, true);			
+		}
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+
+		if (memberAlignment != null) {
+			this.scribe.alignFragment(memberAlignment, 2);
+			this.scribe.printTrailingComment();
+		} else {
+			this.scribe.space();
+			this.scribe.printTrailingComment();
+		}
 	}
-	public void consumeNextToken() {
-		printComment();
+	
+	private void format(MultiFieldDeclaration multiFieldDeclaration, ASTVisitor visitor, MethodScope scope, boolean isChunkStart, boolean isFirstClassBodyDeclaration) {
+	
+		if (isFirstClassBodyDeclaration) {
+			int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+			if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
+			}
+		} else {
+			int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+			if (newLineBeforeChunk > 0) {
+				this.scribe.printEmptyLines(newLineBeforeChunk);
+			}
+			final int newLinesBeforeField = this.preferences.blank_lines_before_field;
+			if (newLinesBeforeField > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeField);
+			}
+		}
+		Alignment fieldAlignment = this.scribe.getMemberAlignment();
+	
+        this.scribe.printComment();
+		this.scribe.printModifiers(multiFieldDeclaration.annotations, this);
+		this.scribe.space();
+	
+		multiFieldDeclaration.declarations[0].type.traverse(this, scope);
+	
+		final int multipleFieldDeclarationsLength = multiFieldDeclaration.declarations.length;
+
+		Alignment multiFieldDeclarationsAlignment =this.scribe.createAlignment(
+				"multiple_field",//$NON-NLS-1$
+				this.preferences.alignment_for_multiple_fields,
+				multipleFieldDeclarationsLength - 1,
+				this.scribe.scanner.currentPosition);
+		this.scribe.enterAlignment(multiFieldDeclarationsAlignment);
+	
+		boolean ok = false;
+		do {
+			try {
+				for (int i = 0, length = multipleFieldDeclarationsLength; i < length; i++) {
+					FieldDeclaration fieldDeclaration = multiFieldDeclaration.declarations[i];
+					/*
+					 * Field name
+					 */
+					if (i == 0) {
+						this.scribe.alignFragment(fieldAlignment, 0);
+						this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true);
+					} else {
+						this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, false);
+					}
+			
+					/*
+					 * Check for extra dimensions
+					 */
+					int extraDimensions = getDimensions();
+					if (extraDimensions != 0) {
+						 for (int index = 0; index < extraDimensions; index++) {
+						 	this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+						 	this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+						 }
+					}
+				
+					/*
+					 * Field initialization
+					 */
+					final Expression initialization = fieldDeclaration.initialization;
+					if (initialization != null) {
+						if (i == 0) {
+							this.scribe.alignFragment(fieldAlignment, 1);
+						}
+						this.scribe.printNextToken(TerminalTokens.TokenNameEQUAL, this.preferences.insert_space_before_assignment_operator);
+						if (this.preferences.insert_space_after_assignment_operator) {
+							this.scribe.space();
+						}
+						initialization.traverse(this, scope);
+					}
+					
+					if (i != length - 1) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_multiple_field_declarations);
+						this.scribe.printTrailingComment();
+						this.scribe.alignFragment(multiFieldDeclarationsAlignment, i);
+
+						if (this.preferences.insert_space_after_comma_in_multiple_field_declarations) {
+							this.scribe.space();
+						}
+					} else {
+						this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+						this.scribe.alignFragment(fieldAlignment, 2);
+						this.scribe.printTrailingComment();
+					}
+				}
+				ok = true;
+			} catch (AlignmentException e) {
+				this.scribe.redoAlignment(e);
+			}
+		} while (!ok);
+		this.scribe.exitAlignment(multiFieldDeclarationsAlignment, true);				
+	}
+	
+	/**
+	 * @see org.eclipse.jdt.core.formatter.CodeFormatter#format(int, String, int, int, int, String)
+	 */
+	public TextEdit format(String string, ASTNode[] nodes) {
+		// reset the scribe
+		this.scribe.reset();
+		
+		long startTime = System.currentTimeMillis();
+
+		final char[] compilationUnitSource = string.toCharArray();
+		
+		this.localScanner.setSource(compilationUnitSource);
+		this.scribe.initializeScanner(compilationUnitSource);
+
+		if (nodes == null) {
+			return null;
+		}
+
+		this.lastLocalDeclarationSourceStart = -1;
 		try {
-			this.currentToken = this.scanner.getNextToken();
-			addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-		} catch (InvalidInputException e) {
-			throw new AbortFormatting(e);
+			formatClassBodyDeclarations(nodes);
+		} catch(AbortFormatting e){
+			return failedToFormat();
 		}
+		if (DEBUG){
+			System.out.println("Formatting time: " + (System.currentTimeMillis() - startTime));  //$NON-NLS-1$
+		}
+		return this.scribe.getRootEdit();
 	}
-	public Alignment createAlignment(String name, int mode, int count, int sourceRestart){
-		return createAlignment(name, mode, Alignment.R_INNERMOST, count, sourceRestart);
+
+	/**
+	 * @see org.eclipse.jdt.core.formatter.CodeFormatter#format(int, String, int, int, int, String)
+	 */
+	public TextEdit format(String string, CompilationUnitDeclaration compilationUnitDeclaration) {
+		// reset the scribe
+		this.scribe.reset();
+		
+		if (compilationUnitDeclaration == null || compilationUnitDeclaration.ignoreFurtherInvestigation) {
+			return failedToFormat();
+		}
+
+		long startTime = System.currentTimeMillis();
+
+		final char[] compilationUnitSource = string.toCharArray();
+		
+		this.localScanner.setSource(compilationUnitSource);
+		this.scribe.initializeScanner(compilationUnitSource);
+
+		this.lastLocalDeclarationSourceStart = -1;
+		try {
+			compilationUnitDeclaration.traverse(this, compilationUnitDeclaration.scope);
+		} catch(AbortFormatting e){
+			return failedToFormat();
+		}
+		if (DEBUG){
+			System.out.println("Formatting time: " + (System.currentTimeMillis() - startTime));  //$NON-NLS-1$
+		}
+		return this.scribe.getRootEdit();
 	}
 
-	public Alignment createAlignment(String name, int mode, int count, int sourceRestart, boolean adjust){
-		return createAlignment(name, mode, Alignment.R_INNERMOST, count, sourceRestart, adjust);
+	/**
+	 * @see org.eclipse.jdt.core.formatter.CodeFormatter#format(int, String, int, int, int, String)
+	 */
+	public TextEdit format(String string, ConstructorDeclaration constructorDeclaration) {
+		// reset the scribe
+		this.scribe.reset();
+		
+		long startTime = System.currentTimeMillis();
+
+		final char[] compilationUnitSource = string.toCharArray();
+		
+		this.localScanner.setSource(compilationUnitSource);
+		this.scribe.initializeScanner(compilationUnitSource);
+
+		if (constructorDeclaration == null) {
+			return null;
+		}
+
+		this.lastLocalDeclarationSourceStart = -1;
+		try {
+			ExplicitConstructorCall explicitConstructorCall = constructorDeclaration.constructorCall;
+			if (explicitConstructorCall != null && !explicitConstructorCall.isImplicitSuper()) {
+				explicitConstructorCall.traverse(this, null);
+			}
+			Statement[] statements = constructorDeclaration.statements;
+			if (statements != null) {
+				formatStatements(null, statements, false);
+			}
+			if (hasComments()) {
+				this.scribe.printNewLine();
+			}
+			this.scribe.printComment();
+		} catch(AbortFormatting e){
+			return failedToFormat();
+		}
+		if (DEBUG){
+			System.out.println("Formatting time: " + (System.currentTimeMillis() - startTime));  //$NON-NLS-1$
+		}
+		return this.scribe.getRootEdit();
 	}
+
+	/**
+	 * @see org.eclipse.jdt.core.formatter.CodeFormatter#format(int, String, int, int, int, String)
+	 */
+	public TextEdit format(String string, Expression expression) {
+		// reset the scribe
+		this.scribe.reset();
+		
+		long startTime = System.currentTimeMillis();
+
+		final char[] compilationUnitSource = string.toCharArray();
+		
+		this.localScanner.setSource(compilationUnitSource);
+		this.scribe.initializeScanner(compilationUnitSource);
+
+		if (expression == null) {
+			return null;
+		}
+
+		this.lastLocalDeclarationSourceStart = -1;
+		try {
+			expression.traverse(this, (BlockScope) null);
+			this.scribe.printComment();
+		} catch(AbortFormatting e){
+			return failedToFormat();
+		}
+		if (DEBUG){
+			System.out.println("Formatting time: " + (System.currentTimeMillis() - startTime));  //$NON-NLS-1$
+		}
+		return this.scribe.getRootEdit();
+	}
 	
-	public Alignment createAlignment(String name, int mode, int tieBreakRule, int count, int sourceRestart){
-		return createAlignment(name, mode, tieBreakRule, count, sourceRestart, this.formatter.preferences.continuation_indentation, false);
-	}
+	/**
+	 * @see org.eclipse.jdt.core.formatter.CodeFormatter#format(int, String, int, int, int, String)
+	 */
+	public TextEdit format(String string, CommentRegion region) {
+		// reset the scribe
+		this.scribe.reset();
+		
+		if (region == null) {
+			return failedToFormat();
+		}
 
-	public Alignment createAlignment(String name, int mode, int count, int sourceRestart, int continuationIndent, boolean adjust){
-		return createAlignment(name, mode, Alignment.R_INNERMOST, count, sourceRestart, continuationIndent, adjust);
+		long startTime = 0;
+		if (DEBUG){
+			startTime = System.currentTimeMillis();
+		}
+
+		final char[] compilationUnitSource = string.toCharArray();
+		
+		this.scribe.initializeScanner(compilationUnitSource);
+
+		TextEdit result = null;
+		try {
+			result = region.format(this.preferences.initial_indentation_level, true);
+		} catch(AbortFormatting e){
+			return failedToFormat();
+		}
+		if (DEBUG){
+			System.out.println("Formatting time: " + (System.currentTimeMillis() - startTime));  //$NON-NLS-1$
+		}
+		return result;
 	}
 
-	public Alignment createAlignment(String name, int mode, int tieBreakRule, int count, int sourceRestart, int continuationIndent, boolean adjust){
-		Alignment alignment = new Alignment(name, mode, tieBreakRule, this, count, sourceRestart, continuationIndent);
-		// adjust break indentation
-		if (adjust && this.memberAlignment != null) {
-			Alignment current = this.memberAlignment;
-			while (current.enclosing != null) {
-				current = current.enclosing;
+	private void format(TypeDeclaration typeDeclaration){
+        /*
+         * Print comments to get proper line number
+         */
+        this.scribe.printComment();
+        final int line = this.scribe.line; 
+        
+        this.scribe.printModifiers(typeDeclaration.annotations, this);
+		/*
+		 * Type name
+		 */
+        switch(TypeDeclaration.kind(typeDeclaration.modifiers)) {
+        	case TypeDeclaration.CLASS_DECL :
+				this.scribe.printNextToken(TerminalTokens.TokenNameclass, true); 
+        		break;
+        	case TypeDeclaration.INTERFACE_DECL :
+				this.scribe.printNextToken(TerminalTokens.TokenNameinterface, true); 
+        		break;
+        	case TypeDeclaration.ENUM_DECL :
+				this.scribe.printNextToken(TerminalTokens.TokenNameenum, true); 
+        		break;
+        	case TypeDeclaration.ANNOTATION_TYPE_DECL :
+				this.scribe.printNextToken(TerminalTokens.TokenNameAT, this.preferences.insert_space_before_at_in_annotation_type_declaration);
+				this.scribe.printNextToken(TerminalTokens.TokenNameinterface, this.preferences.insert_space_after_at_in_annotation_type_declaration); 
+        		break;
+        }
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true); 
+
+		TypeParameter[] typeParameters = typeDeclaration.typeParameters;
+		if (typeParameters != null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_parameters); 
+			if (this.preferences.insert_space_after_opening_angle_bracket_in_type_parameters) {
+				this.scribe.space();
 			}
-			if ((current.mode & Alignment.M_MULTICOLUMN) != 0) {
-				final int indentSize = this.indentationSize;
-				switch(current.chunkKind) {
-					case Alignment.CHUNK_METHOD :
-					case Alignment.CHUNK_TYPE :
-						if ((mode & Alignment.M_INDENT_BY_ONE) != 0) {
-							alignment.breakIndentationLevel = this.indentationLevel + indentSize;
+			int length = typeParameters.length;
+			for (int i = 0; i < length - 1; i++) {
+				typeParameters[i].traverse(this, typeDeclaration.scope);
+				this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_parameters);
+				if (this.preferences.insert_space_after_comma_in_type_parameters) {
+					this.scribe.space();
+				}				
+			}
+			typeParameters[length - 1].traverse(this, typeDeclaration.scope);
+			if (isClosingGenericToken()) {
+				this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_parameters); 
+			}
+			if (this.preferences.insert_space_after_closing_angle_bracket_in_type_parameters) {
+				this.scribe.space();
+			}
+		}
+		/* 
+		 * Superclass 
+		 */
+		final TypeReference superclass = typeDeclaration.superclass;
+		if (superclass != null) {
+			Alignment superclassAlignment =this.scribe.createAlignment(
+					"superclass", //$NON-NLS-1$
+					this.preferences.alignment_for_superclass_in_type_declaration,
+					2,
+					this.scribe.scanner.currentPosition);
+			this.scribe.enterAlignment(superclassAlignment);
+			boolean ok = false;
+			do {
+				try {
+					this.scribe.alignFragment(superclassAlignment, 0);
+					this.scribe.printNextToken(TerminalTokens.TokenNameextends, true);
+					this.scribe.alignFragment(superclassAlignment, 1);
+					this.scribe.space();
+					superclass.traverse(this, typeDeclaration.scope);
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(superclassAlignment, true); 
+		}
+
+		/* 
+		 * Super Interfaces 
+		 */
+		final TypeReference[] superInterfaces = typeDeclaration.superInterfaces;
+		if (superInterfaces != null) {
+			int alignment_for_superinterfaces;
+			int kind = TypeDeclaration.kind(typeDeclaration.modifiers);
+			switch(kind) {
+				case TypeDeclaration.ENUM_DECL :
+					alignment_for_superinterfaces = this.preferences.alignment_for_superinterfaces_in_enum_declaration;
+					break;
+				default:
+					alignment_for_superinterfaces = this.preferences.alignment_for_superinterfaces_in_type_declaration;
+					break;
+			}
+			int superInterfaceLength = superInterfaces.length;
+			Alignment interfaceAlignment =this.scribe.createAlignment(
+					"superInterfaces",//$NON-NLS-1$
+					alignment_for_superinterfaces,
+					superInterfaceLength+1,  // implements token is first fragment
+					this.scribe.scanner.currentPosition);
+			this.scribe.enterAlignment(interfaceAlignment);
+			boolean ok = false;
+			do {
+				try {
+					this.scribe.alignFragment(interfaceAlignment, 0);
+					if (kind == TypeDeclaration.INTERFACE_DECL) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameextends, true);
+					} else  {
+						this.scribe.printNextToken(TerminalTokens.TokenNameimplements, true);
+					}
+					for (int i = 0; i < superInterfaceLength; i++) {
+						if (i > 0) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_superinterfaces);
+							this.scribe.printTrailingComment();
+							this.scribe.alignFragment(interfaceAlignment, i+1);
+							if (this.preferences.insert_space_after_comma_in_superinterfaces) {
+								this.scribe.space();
+							}
+							superInterfaces[i].traverse(this, typeDeclaration.scope);
 						} else {
-							alignment.breakIndentationLevel = this.indentationLevel + continuationIndent * indentSize;
+							this.scribe.alignFragment(interfaceAlignment, i+1);
+							this.scribe.space();
+							superInterfaces[i].traverse(this, typeDeclaration.scope);
 						}
-						alignment.update();
+					}
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(interfaceAlignment, true);
+		}
+
+		/*
+		 * Type body
+		 */
+		String class_declaration_brace;
+		boolean space_before_opening_brace;
+		int kind = TypeDeclaration.kind(typeDeclaration.modifiers);
+		switch(kind) {
+			case TypeDeclaration.ENUM_DECL :
+				class_declaration_brace = this.preferences.brace_position_for_enum_declaration;
+				space_before_opening_brace = this.preferences.insert_space_before_opening_brace_in_enum_declaration;
+				break;
+			case TypeDeclaration.ANNOTATION_TYPE_DECL :
+				class_declaration_brace = this.preferences.brace_position_for_annotation_type_declaration;
+				space_before_opening_brace =  this.preferences.insert_space_before_opening_brace_in_annotation_type_declaration;
+				break;
+			default:
+				class_declaration_brace = this.preferences.brace_position_for_type_declaration;
+				space_before_opening_brace = this.preferences.insert_space_before_opening_brace_in_type_declaration;
+				break;
+		}
+        formatLeftCurlyBrace(line, class_declaration_brace);
+		formatTypeOpeningBrace(class_declaration_brace, space_before_opening_brace, typeDeclaration);
+		
+		boolean indent_body_declarations_compare_to_header;
+		switch(kind) {
+			case TypeDeclaration.ENUM_DECL :
+				indent_body_declarations_compare_to_header = this.preferences.indent_body_declarations_compare_to_enum_declaration_header;
+				break;
+			case TypeDeclaration.ANNOTATION_TYPE_DECL :
+				// TODO (olivier) might want to add an option for annotation type
+				indent_body_declarations_compare_to_header = this.preferences.indent_body_declarations_compare_to_type_header;
+				break;
+			default:
+				indent_body_declarations_compare_to_header = this.preferences.indent_body_declarations_compare_to_type_header;
+				break;
+		}		
+		if (indent_body_declarations_compare_to_header) {
+			this.scribe.indent();
+		}
+		
+		if (kind == TypeDeclaration.ENUM_DECL) {
+			FieldDeclaration[] fieldDeclarations = typeDeclaration.fields;
+			boolean hasConstants = false;
+			if (fieldDeclarations != null) {
+				int length = fieldDeclarations.length;
+				int enumConstantsLength = 0;
+				for (int i = 0; i < length; i++) {
+					FieldDeclaration fieldDeclaration = fieldDeclarations[i];
+					if (fieldDeclaration.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
+						enumConstantsLength++;
+					} else {
 						break;
-					case Alignment.CHUNK_FIELD :
-						if ((mode & Alignment.M_INDENT_BY_ONE) != 0) {
-							alignment.breakIndentationLevel = current.originalIndentationLevel + indentSize;
-						} else {
-							alignment.breakIndentationLevel = current.originalIndentationLevel + continuationIndent * indentSize;
+					}
+				}
+				hasConstants = enumConstantsLength != 0;
+				if (enumConstantsLength > 1) {
+					Alignment enumConstantsAlignment = this.scribe.createAlignment(
+							"enumConstants",//$NON-NLS-1$
+							this.preferences.alignment_for_enum_constants,
+							enumConstantsLength,
+							this.scribe.scanner.currentPosition,
+							0, // we don't want to indent enum constants when splitting to a new line
+							false);
+					this.scribe.enterAlignment(enumConstantsAlignment);
+					boolean ok = false;
+					do {
+						try {
+							for (int i = 0; i < enumConstantsLength; i++) {
+								this.scribe.alignFragment(enumConstantsAlignment, i);
+								FieldDeclaration fieldDeclaration = fieldDeclarations[i];
+								fieldDeclaration.traverse(this, typeDeclaration.initializerScope);
+								if (isNextToken(TerminalTokens.TokenNameCOMMA)) {
+									this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_enum_declarations);
+									if (this.preferences.insert_space_after_comma_in_enum_declarations) {
+										this.scribe.space();
+									}
+									this.scribe.printTrailingComment();
+									if (fieldDeclaration.initialization instanceof QualifiedAllocationExpression) {
+										this.scribe.printNewLine();
+									}
+								}
+							}
+							ok = true;
+						} catch (AlignmentException e) {
+							this.scribe.redoAlignment(e);
 						}
-						alignment.update();
-						break;
+					} while (!ok);
+					this.scribe.exitAlignment(enumConstantsAlignment, true);
+				} else {
+					FieldDeclaration fieldDeclaration = fieldDeclarations[0];
+					fieldDeclaration.traverse(this, typeDeclaration.initializerScope);
+					if (isNextToken(TerminalTokens.TokenNameCOMMA)) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_enum_declarations);
+						if (this.preferences.insert_space_after_comma_in_enum_declarations) {
+							this.scribe.space();
+						}
+						this.scribe.printTrailingComment();
+						if (fieldDeclaration.initialization instanceof QualifiedAllocationExpression) {
+							this.scribe.printNewLine();
+						}
+					}
 				}
+			}
+			if (isNextToken(TerminalTokens.TokenNameSEMICOLON)) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+				this.scribe.printTrailingComment();
+			}
+			if (hasConstants) {
+				this.scribe.printNewLine();	
+			}
+		}
+
+		formatTypeMembers(typeDeclaration);
+		
+		if (indent_body_declarations_compare_to_header) {
+			this.scribe.unIndent();
+		}
+		
+		switch(kind) {
+			case TypeDeclaration.ENUM_DECL :
+				if (this.preferences.insert_new_line_in_empty_enum_declaration) {
+					this.scribe.printNewLine();
+				}
+				break;
+			case TypeDeclaration.ANNOTATION_TYPE_DECL :
+				// TODO (olivier) might want an option for annotation type
+				if (this.preferences.insert_new_line_in_empty_type_declaration) {
+					this.scribe.printNewLine();
+				}
+				break;
+			default :
+				if (this.preferences.insert_new_line_in_empty_type_declaration) {
+					this.scribe.printNewLine();
+				}
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE);
+		this.scribe.printTrailingComment();
+		if (class_declaration_brace.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+			this.scribe.unIndent();
+		}
+		if (hasComments()) {
+			this.scribe.printNewLine();
+		}
+	}
+
+	private void format(
+		TypeDeclaration memberTypeDeclaration,
+		ClassScope scope,
+		boolean isChunkStart,
+		boolean isFirstClassBodyDeclaration) {
+
+		if (isFirstClassBodyDeclaration) {
+			int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+			if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
+			}
+		} else {
+			int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+			if (newLineBeforeChunk > 0) {
+				this.scribe.printEmptyLines(newLineBeforeChunk);
+			}
+			final int newLinesBeforeMember = this.preferences.blank_lines_before_member_type;
+			if (newLinesBeforeMember > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeMember);
+			}
+		}
+		memberTypeDeclaration.traverse(this, scope);
+	}
+	
+	private void formatAnonymousTypeDeclaration(TypeDeclaration typeDeclaration) {
+		/*
+		 * Type body
+		 */
+		String anonymous_type_declaration_brace_position = this.preferences.brace_position_for_anonymous_type_declaration;
+		
+		formatTypeOpeningBrace(anonymous_type_declaration_brace_position, this.preferences.insert_space_before_opening_brace_in_anonymous_type_declaration, typeDeclaration);
+		
+		this.scribe.indent();
+
+		formatTypeMembers(typeDeclaration);
+
+		this.scribe.unIndent();
+		if (this.preferences.insert_new_line_in_empty_anonymous_type_declaration) {
+			this.scribe.printNewLine();
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE);
+		if (anonymous_type_declaration_brace_position.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+			this.scribe.unIndent();
+		}
+	}
+	
+	/**
+	 * @param block
+	 * @param scope
+	 * @param block_brace_position
+	 */
+	private void formatBlock(Block block, BlockScope scope, String block_brace_position, boolean insertSpaceBeforeOpeningBrace) {
+		formatOpeningBrace(block_brace_position, insertSpaceBeforeOpeningBrace);
+		final Statement[] statements = block.statements;
+		if (statements != null) {
+			this.scribe.printNewLine();
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.indent();
+			}
+			formatStatements(scope, statements, true);
+			this.scribe.printComment();
+	
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.unIndent();
+			}
+		} else if (this.preferences.insert_new_line_in_empty_block) {
+			this.scribe.printNewLine();
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.indent();
+			}
+			this.scribe.printComment();
+	
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.unIndent();
+			}
+		} else {
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.indent();
+			}
+			this.scribe.printComment();
+	
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.unIndent();
+			}
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE);
+		this.scribe.printTrailingComment();
+		if (DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(block_brace_position)) {
+			this.scribe.unIndent();
+		}
+	}
+
+	private void formatCascadingMessageSends(CascadingMethodInvocationFragmentBuilder builder, BlockScope scope) {
+		int size = builder.size();
+		MessageSend[] fragments = builder.fragments();
+		Expression fragment = fragments[0].receiver;
+		int startingPositionInCascade = 1;
+		if (!fragment.isImplicitThis()) {
+			fragment.traverse(this, scope);
+		} else {
+			MessageSend currentMessageSend = fragments[1];
+			final int numberOfParens = (currentMessageSend.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+			if (numberOfParens > 0) {
+				manageOpeningParenthesizedExpression(currentMessageSend, numberOfParens);
+			}
+			ASTNode[] arguments = currentMessageSend.arguments;
+			TypeReference[] typeArguments = currentMessageSend.typeArguments;
+			if (typeArguments != null) {
+					this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_arguments); 
+					if (this.preferences.insert_space_after_opening_angle_bracket_in_type_arguments) {
+						this.scribe.space();
+					}
+					int length = typeArguments.length;
+					for (int i = 0; i < length - 1; i++) {
+						typeArguments[i].traverse(this, scope);
+						this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_arguments);
+						if (this.preferences.insert_space_after_comma_in_type_arguments) {
+							this.scribe.space();
+						}				
+					}
+					typeArguments[length - 1].traverse(this, scope);
+					if (isClosingGenericToken()) {
+						this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_arguments); 
+					}
+					if (this.preferences.insert_space_after_closing_angle_bracket_in_type_arguments) {
+						this.scribe.space();
+					}
+			}
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier); // selector
+			this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_method_invocation);
+			if (arguments != null) {
+				if (this.preferences.insert_space_after_opening_paren_in_method_invocation) {
+					this.scribe.space();
+				}
+				int argumentLength = arguments.length;
+				Alignment argumentsAlignment = this.scribe.createAlignment(
+						"messageArguments", //$NON-NLS-1$
+						this.preferences.alignment_for_arguments_in_method_invocation,
+						Alignment.R_OUTERMOST,
+						argumentLength,
+						this.scribe.scanner.currentPosition);
+				this.scribe.enterAlignment(argumentsAlignment);
+				boolean okForArguments = false;
+				do {
+					try {
+						for (int j = 0; j < argumentLength; j++) {
+							if (j > 0) {
+								this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_method_invocation_arguments);
+								this.scribe.printTrailingComment();
+							}
+							this.scribe.alignFragment(argumentsAlignment, j);
+							if (j > 0 && this.preferences.insert_space_after_comma_in_method_invocation_arguments) {
+								this.scribe.space();
+							}
+							arguments[j].traverse(this, scope);
+						}
+						okForArguments = true;
+					} catch (AlignmentException e) {
+						this.scribe.redoAlignment(e);
+					}
+				} while (!okForArguments);
+				this.scribe.exitAlignment(argumentsAlignment, true);
+				this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_method_invocation);
 			} else {
-				switch(current.mode & Alignment.SPLIT_MASK) {
-					case Alignment.M_COMPACT_SPLIT :
-					case Alignment.M_COMPACT_FIRST_BREAK_SPLIT :
-					case Alignment.M_NEXT_PER_LINE_SPLIT :
-					case Alignment.M_NEXT_SHIFTED_SPLIT :
-					case Alignment.M_ONE_PER_LINE_SPLIT :
-						final int indentSize = this.indentationSize;
-						switch(current.chunkKind) {
-							case Alignment.CHUNK_METHOD :
-							case Alignment.CHUNK_TYPE :
-								if ((mode & Alignment.M_INDENT_BY_ONE) != 0) {
-									alignment.breakIndentationLevel = this.indentationLevel + indentSize;
-								} else {
-									alignment.breakIndentationLevel = this.indentationLevel + continuationIndent * indentSize;
+				this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_between_empty_parens_in_method_invocation);
+			}
+			if (numberOfParens > 0) {
+				manageClosingParenthesizedExpression(currentMessageSend, numberOfParens);
+			}
+			startingPositionInCascade = 2;
+		}
+		Alignment cascadingMessageSendAlignment =
+			this.scribe.createAlignment(
+				"cascadingMessageSendAlignment", //$NON-NLS-1$
+				this.preferences.alignment_for_selector_in_method_invocation,
+				Alignment.R_INNERMOST,
+				size,
+				this.scribe.scanner.currentPosition);
+		this.scribe.enterAlignment(cascadingMessageSendAlignment);
+		boolean ok = false;
+		do {
+			try {
+				this.scribe.alignFragment(cascadingMessageSendAlignment, 0);
+				this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+				for (int i = startingPositionInCascade; i < size; i++) {
+					MessageSend currentMessageSend = fragments[i];
+					final int numberOfParens = (currentMessageSend.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+					if (numberOfParens > 0) {
+						manageOpeningParenthesizedExpression(currentMessageSend, numberOfParens);
+					}
+					TypeReference[] typeArguments = currentMessageSend.typeArguments;
+					if (typeArguments != null) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_arguments); 
+							if (this.preferences.insert_space_after_opening_angle_bracket_in_type_arguments) {
+								this.scribe.space();
+							}
+							int length = typeArguments.length;
+							for (int j = 0; j < length - 1; j++) {
+								typeArguments[j].traverse(this, scope);
+								this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_arguments);
+								if (this.preferences.insert_space_after_comma_in_type_arguments) {
+									this.scribe.space();
+								}				
+							}
+							typeArguments[length - 1].traverse(this, scope);
+							if (isClosingGenericToken()) {
+								this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_arguments); 
+							}
+							if (this.preferences.insert_space_after_closing_angle_bracket_in_type_arguments) {
+								this.scribe.space();
+							}
+					}
+					ASTNode[] arguments = currentMessageSend.arguments;
+					this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier); // selector
+					this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_method_invocation);
+					if (arguments != null) {
+						if (this.preferences.insert_space_after_opening_paren_in_method_invocation) {
+							this.scribe.space();
+						}
+						int argumentLength = arguments.length;
+						Alignment argumentsAlignment = this.scribe.createAlignment(
+								"messageArguments", //$NON-NLS-1$
+								this.preferences.alignment_for_arguments_in_method_invocation,
+								Alignment.R_OUTERMOST,
+								argumentLength,
+								this.scribe.scanner.currentPosition);
+						this.scribe.enterAlignment(argumentsAlignment);
+						boolean okForArguments = false;
+						do {
+							try {
+								for (int j = 0; j < argumentLength; j++) {
+									if (j > 0) {
+										this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_method_invocation_arguments);
+										this.scribe.printTrailingComment();
+									}
+									this.scribe.alignFragment(argumentsAlignment, j);
+									if (j > 0 && this.preferences.insert_space_after_comma_in_method_invocation_arguments) {
+										this.scribe.space();
+									}
+									arguments[j].traverse(this, scope);
 								}
-								alignment.update();
-								break;
-							case Alignment.CHUNK_FIELD :
-								if ((mode & Alignment.M_INDENT_BY_ONE) != 0) {
-									alignment.breakIndentationLevel = current.originalIndentationLevel + indentSize;
-								} else {
-									alignment.breakIndentationLevel = current.originalIndentationLevel + continuationIndent * indentSize;
+								okForArguments = true;
+							} catch (AlignmentException e) {
+								this.scribe.redoAlignment(e);
+							}
+						} while (!okForArguments);
+						this.scribe.exitAlignment(argumentsAlignment, true);
+						this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_method_invocation);
+					} else {
+						this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_between_empty_parens_in_method_invocation);
+					}
+					if (numberOfParens > 0) {
+						manageClosingParenthesizedExpression(currentMessageSend, numberOfParens);
+					}
+					if (i < size - 1) {
+						this.scribe.alignFragment(cascadingMessageSendAlignment, i);
+						this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+					}
+				}
+				ok = true;
+			} catch(AlignmentException e){
+				this.scribe.redoAlignment(e);
+			}
+		} while (!ok);		
+		this.scribe.exitAlignment(cascadingMessageSendAlignment, true);
+	}
+	
+	/*
+	 * Merged traversal of member (types, fields, methods)
+	 */
+	private void formatClassBodyDeclarations(ASTNode[] nodes) {
+		final int FIELD = 1, METHOD = 2, TYPE = 3;
+		this.scribe.lastNumberOfNewLines = 1;
+		ASTNode[] mergedNodes = computeMergedMemberDeclarations(nodes);
+		Alignment memberAlignment = this.scribe.createMemberAlignment("typeMembers", this.preferences.align_type_members_on_columns ? Alignment.M_MULTICOLUMN : Alignment.M_NO_ALIGNMENT, 4, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+		this.scribe.enterMemberAlignment(memberAlignment);
+		boolean isChunkStart = false;
+		boolean ok = false;
+		int startIndex = 0;
+		do {
+			try {
+				for (int i = startIndex, max = mergedNodes.length; i < max; i++) {
+					ASTNode member = mergedNodes[i];
+					if (member instanceof FieldDeclaration) {
+						isChunkStart = memberAlignment.checkChunkStart(FIELD, i, this.scribe.scanner.currentPosition);
+						if (member instanceof MultiFieldDeclaration){
+							MultiFieldDeclaration multiField = (MultiFieldDeclaration) member;
+							format(multiField, this, null, isChunkStart, i == 0);
+						} else if (member instanceof Initializer) {
+							int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+							if (newLineBeforeChunk > 0 && i != 0) {
+								this.scribe.printEmptyLines(newLineBeforeChunk);
+							} else if (i == 0) {
+								int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+								if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+									this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
 								}
-								alignment.update();
-								break;
+							}
+							Initializer initializer = (Initializer) member;
+							initializer.traverse(this, null);
+						} else {
+							FieldDeclaration field = (FieldDeclaration) member;
+							format(field, this, null, isChunkStart, i == 0);
 						}
-						break;
+					} else if (member instanceof AbstractMethodDeclaration) {
+						isChunkStart = memberAlignment.checkChunkStart(METHOD, i, this.scribe.scanner.currentPosition);
+						format((AbstractMethodDeclaration) member, null, isChunkStart, i == 0);
+					} else {
+						isChunkStart = memberAlignment.checkChunkStart(TYPE, i, this.scribe.scanner.currentPosition);
+						format((TypeDeclaration)member, null, isChunkStart, i == 0);
+					}
+					if (isNextToken(TerminalTokens.TokenNameSEMICOLON)) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+						this.scribe.printTrailingComment();
+					}
+					if (i != max - 1) {
+						this.scribe.printNewLine();
+					}
 				}
+				ok = true;
+			} catch(AlignmentException e){
+				startIndex = memberAlignment.chunkStartIndex;
+				this.scribe.redoMemberAlignment(e);
 			}
+		} while (!ok);		
+		this.scribe.exitMemberAlignment(memberAlignment);
+		if (hasComments()) {
+			this.scribe.printNewLine();
 		}
-		return alignment; 
+		this.scribe.printComment();
 	}
 
-	public Alignment createMemberAlignment(String name, int mode, int count, int sourceRestart) {
-		Alignment mAlignment = createAlignment(name, mode, Alignment.R_INNERMOST, count, sourceRestart);
-		mAlignment.breakIndentationLevel = this.indentationLevel;
-		return mAlignment;
+	private void formatEmptyTypeDeclaration(boolean isFirst) {
+		boolean hasSemiColon = isNextToken(TerminalTokens.TokenNameSEMICOLON);
+		while(isNextToken(TerminalTokens.TokenNameSEMICOLON)) {
+			this.scribe.printComment();
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+			this.scribe.printTrailingComment();
+		}
+		if (hasSemiColon && isFirst) {
+			this.scribe.printNewLine();
+		}
 	}
-	
-	public void enterAlignment(Alignment alignment){
-		alignment.enclosing = this.currentAlignment;
-		alignment.location.lastLocalDeclarationSourceStart = this.formatter.lastLocalDeclarationSourceStart;
-		this.currentAlignment = alignment;
+
+	private void formatGuardClauseBlock(Block block, BlockScope scope) {
+
+		this.scribe.printNextToken(TerminalTokens.TokenNameLBRACE, this.preferences.insert_space_before_opening_brace_in_block);
+		this.scribe.space();
+
+		final Statement[] statements = block.statements;
+		statements[0].traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, true);
+		this.scribe.printTrailingComment();
 	}
 
-	public void enterMemberAlignment(Alignment alignment) {
-		alignment.enclosing = this.memberAlignment;
-		alignment.location.lastLocalDeclarationSourceStart = this.formatter.lastLocalDeclarationSourceStart;
-		this.memberAlignment = alignment;
+    private void formatLeftCurlyBrace(final int line, final String bracePosition) {
+        /*
+         * deal with (quite unexpected) comments right before lcurly
+         */
+        this.scribe.printComment();
+        if (DefaultCodeFormatterConstants.NEXT_LINE_ON_WRAP.equals(bracePosition)
+                && (this.scribe.line > line || this.scribe.column >= this.preferences.page_width)) 
+        {
+            this.scribe.printNewLine();
+        }
+    }
+    
+	private void formatLocalDeclaration(LocalDeclaration localDeclaration, BlockScope scope, boolean insertSpaceBeforeComma, boolean insertSpaceAfterComma) {
+
+		if (!isMultipleLocalDeclaration(localDeclaration)) {
+			if (localDeclaration.modifiers != NO_MODIFIERS || localDeclaration.annotations != null) {
+		        this.scribe.printComment();
+				this.scribe.printModifiers(localDeclaration.annotations, this);
+				this.scribe.space();
+			}
+	
+			/*
+			 * Argument type 
+			 */		
+			if (localDeclaration.type != null) {
+				localDeclaration.type.traverse(this, scope);
+			}
+			/*
+			 * Print the argument name
+		 	*/
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true); 
+		} else {
+			/*
+			 * Print the argument name
+		 	*/
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, false); 
+		}
+		/*
+		 * Check for extra dimensions
+		 */
+		int extraDimensions = getDimensions();
+		if (extraDimensions != 0) {
+			 for (int index = 0; index < extraDimensions; index++) {
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			 }
+		}
+	
+		final Expression initialization = localDeclaration.initialization;
+		if (initialization != null) {
+			/*
+			 * Print the method name
+			 */	
+			this.scribe.printNextToken(TerminalTokens.TokenNameEQUAL, this.preferences.insert_space_before_assignment_operator);
+			if (this.preferences.insert_space_after_assignment_operator) {
+				this.scribe.space();
+			}
+			Alignment assignmentAlignment = this.scribe.createAlignment("localDeclarationAssignmentAlignment", this.preferences.alignment_for_assignment, Alignment.R_OUTERMOST, 1, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+			this.scribe.enterAlignment(assignmentAlignment);
+			boolean ok = false;
+			do {
+				try {
+					this.scribe.alignFragment(assignmentAlignment, 0);
+					initialization.traverse(this, scope);
+					ok = true;
+				} catch(AlignmentException e){
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);		
+			this.scribe.exitAlignment(assignmentAlignment, true);			
+		}
+
+		if (isPartOfMultipleLocalDeclaration()) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, insertSpaceBeforeComma); 
+			if (insertSpaceAfterComma) {
+				this.scribe.space();
+			}
+			this.scribe.printTrailingComment();
+		}
 	}
 
-	public void exitAlignment(Alignment alignment, boolean discardAlignment){
-		Alignment current = this.currentAlignment;
-		while (current != null){
-			if (current == alignment) break;
-			current = current.enclosing;
+	private void formatMessageSend(
+		MessageSend messageSend,
+		BlockScope scope,
+		Alignment messageAlignment) {
+
+		if (messageAlignment != null) {
+			this.scribe.alignFragment(messageAlignment, 0);
+			this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
 		}
-		if (current == null) {
-			throw new AbortFormatting("could not find matching alignment: "+alignment); //$NON-NLS-1$
+		TypeReference[] typeArguments = messageSend.typeArguments;
+		if (typeArguments != null) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_arguments); 
+				if (this.preferences.insert_space_after_opening_angle_bracket_in_type_arguments) {
+					this.scribe.space();
+				}
+				int length = typeArguments.length;
+				for (int i = 0; i < length - 1; i++) {
+					typeArguments[i].traverse(this, scope);
+					this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_arguments);
+					if (this.preferences.insert_space_after_comma_in_type_arguments) {
+						this.scribe.space();
+					}				
+				}
+				typeArguments[length - 1].traverse(this, scope);
+				if (isClosingGenericToken()) {
+					this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_arguments); 
+				}
+				if (this.preferences.insert_space_after_closing_angle_bracket_in_type_arguments) {
+					this.scribe.space();
+				}
 		}
-		this.indentationLevel = alignment.location.outputIndentationLevel;
-		this.numberOfIndentations = alignment.location.numberOfIndentations;
-		this.formatter.lastLocalDeclarationSourceStart = alignment.location.lastLocalDeclarationSourceStart;	
-		if (discardAlignment){ 
-			this.currentAlignment = alignment.enclosing;
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier); // selector
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_method_invocation);
+
+		final Expression[] arguments = messageSend.arguments;
+		if (arguments != null) {
+			if (this.preferences.insert_space_after_opening_paren_in_method_invocation) {
+				this.scribe.space();
+			}
+			int argumentsLength = arguments.length;
+			if (argumentsLength > 1) {
+				Alignment argumentsAlignment = this.scribe.createAlignment(
+						"messageArguments", //$NON-NLS-1$
+						this.preferences.alignment_for_arguments_in_method_invocation,
+						argumentsLength,
+						this.scribe.scanner.currentPosition);
+				this.scribe.enterAlignment(argumentsAlignment);
+				boolean ok = false;
+				do {
+					try {
+						for (int i = 0; i < argumentsLength; i++) {
+							if (i > 0) {
+								this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_method_invocation_arguments);
+								this.scribe.printTrailingComment();
+							}
+							this.scribe.alignFragment(argumentsAlignment, i);
+							if (i > 0 && this.preferences.insert_space_after_comma_in_method_invocation_arguments) {
+								this.scribe.space();
+							}
+							arguments[i].traverse(this, scope);
+						}
+						ok = true;
+					} catch (AlignmentException e) {
+						this.scribe.redoAlignment(e);
+					}
+				} while (!ok);
+				this.scribe.exitAlignment(argumentsAlignment, true);
+			} else {
+				for (int i = 0; i < argumentsLength; i++) {
+					if (i > 0) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_method_invocation_arguments);
+						this.scribe.printTrailingComment();
+					}
+					if (i > 0 && this.preferences.insert_space_after_comma_in_method_invocation_arguments) {
+						this.scribe.space();
+					}
+					arguments[i].traverse(this, scope);
+				}
+			}
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_method_invocation); 
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_between_empty_parens_in_method_invocation);
 		}
 	}
+
+	private void formatMethodArguments(
+			AbstractMethodDeclaration methodDeclaration, 
+			boolean spaceBeforeOpenParen, 
+			boolean spaceBetweenEmptyParameters,
+			boolean spaceBeforeClosingParen, 
+			boolean spaceBeforeFirstParameter, 
+			boolean spaceBeforeComma, 
+			boolean spaceAfterComma,
+			int methodDeclarationParametersAlignment) {
+				
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, spaceBeforeOpenParen); 
+		
+		final Argument[] arguments = methodDeclaration.arguments;
+		if (arguments != null) {
+			if (spaceBeforeFirstParameter) {
+				this.scribe.space();
+			}
+			int argumentLength = arguments.length;
+			Alignment argumentsAlignment = this.scribe.createAlignment(
+					"methodArguments",//$NON-NLS-1$
+					methodDeclarationParametersAlignment,
+					argumentLength,
+					this.scribe.scanner.currentPosition);
+			this.scribe.enterAlignment(argumentsAlignment);
+			boolean ok = false;
+			do {
+				try {
+					for (int i = 0; i < argumentLength; i++) {
+						if (i > 0) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, spaceBeforeComma);
+							this.scribe.printTrailingComment();
+						}
+						this.scribe.alignFragment(argumentsAlignment, i);
+						if (i > 0 && spaceAfterComma) {
+							this.scribe.space();
+						}
+						arguments[i].traverse(this, methodDeclaration.scope);
+					}
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(argumentsAlignment, true);
+		
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, spaceBeforeClosingParen); 
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, spaceBetweenEmptyParameters); 
+		}	
+	}
+
+	private void formatEnumConstantArguments(
+			FieldDeclaration enumConstant,
+			boolean spaceBeforeOpenParen, 
+			boolean spaceBetweenEmptyParameters,
+			boolean spaceBeforeClosingParen, 
+			boolean spaceBeforeFirstParameter, 
+			boolean spaceBeforeComma, 
+			boolean spaceAfterComma,
+			int methodDeclarationParametersAlignment) {
+				
+		if (!isNextToken(TerminalTokens.TokenNameLPAREN)) {
+			return;
+		}
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, spaceBeforeOpenParen); 
+		final Expression[] arguments = ((AllocationExpression) enumConstant.initialization).arguments;
+		if (arguments != null) {
+			int argumentLength = arguments.length;
+			Alignment argumentsAlignment = this.scribe.createAlignment(
+					"enumConstantArguments",//$NON-NLS-1$
+					methodDeclarationParametersAlignment,
+					argumentLength,
+					this.scribe.scanner.currentPosition);
+			this.scribe.enterAlignment(argumentsAlignment);
+			boolean ok = false;
+			do {
+				try {
+					if (spaceBeforeFirstParameter) {
+						this.scribe.space();
+					}
+					for (int i = 0; i < argumentLength; i++) {
+						if (i > 0) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, spaceBeforeComma);
+							this.scribe.printTrailingComment();
+						}
+						this.scribe.alignFragment(argumentsAlignment, i);
+						if (i > 0 && spaceAfterComma) {
+							this.scribe.space();
+						}
+						arguments[i].traverse(this, (BlockScope) null);
+					}
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(argumentsAlignment, true);
+		
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, spaceBeforeClosingParen); 
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, spaceBetweenEmptyParameters); 
+		}	
+	}
+
+	private void formatNecessaryEmptyStatement() {
+		if (this.preferences.put_empty_statement_on_new_line) {
+			this.scribe.printNewLine();
+			this.scribe.indent();
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+			this.scribe.printTrailingComment();
+			this.scribe.unIndent();
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+			this.scribe.printTrailingComment();
+		}
+	}
 	
-	public void exitMemberAlignment(Alignment alignment){
-		Alignment current = this.memberAlignment;
-		while (current != null){
-			if (current == alignment) break;
-			current = current.enclosing;
+	private void formatOpeningBrace(String bracePosition, boolean insertSpaceBeforeBrace) {
+	
+		if (DefaultCodeFormatterConstants.NEXT_LINE.equals(bracePosition)) {
+			this.scribe.printNewLine();
+		} else if (DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(bracePosition)) {
+			this.scribe.printNewLine();
+			this.scribe.indent();
 		}
-		if (current == null) {
-			throw new AbortFormatting("could not find matching alignment: "+alignment); //$NON-NLS-1$
+		this.scribe.printNextToken(TerminalTokens.TokenNameLBRACE, insertSpaceBeforeBrace);
+
+		this.scribe.printTrailingComment();
+	}
+	private void formatStatements(BlockScope scope, final Statement[] statements, boolean insertNewLineAfterLastStatement) {
+		int statementsLength = statements.length;
+		for (int i = 0; i < statementsLength; i++) {
+			final Statement statement = statements[i];
+			if (i > 0 && (statements[i - 1] instanceof EmptyStatement) && !(statement instanceof EmptyStatement)) {
+				this.scribe.printNewLine();
+			}
+			statement.traverse(this, scope);
+			if (statement instanceof Expression) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+				this.scribe.printTrailingComment();
+				if (i != statementsLength - 1) {
+					if (!(statement instanceof EmptyStatement) && !(statements[i + 1] instanceof EmptyStatement)) {
+						this.scribe.printNewLine();
+					}
+				} else if (i == statementsLength - 1 && insertNewLineAfterLastStatement) {
+					this.scribe.printNewLine();
+				}
+			} else if (statement instanceof LocalDeclaration) {
+				LocalDeclaration currentLocal = (LocalDeclaration) statement;
+				if (i < (statementsLength - 1)) {
+					/* 
+					 * We need to check that the next statement is a local declaration
+					 */
+					if (statements[i + 1] instanceof LocalDeclaration) {
+						LocalDeclaration nextLocal = (LocalDeclaration) statements[i + 1];
+						if (currentLocal.declarationSourceStart != nextLocal.declarationSourceStart) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+							this.scribe.printTrailingComment();
+							if (i != statementsLength - 1) {
+								if (!(statement instanceof EmptyStatement) && !(statements[i + 1] instanceof EmptyStatement)) {
+									this.scribe.printNewLine();
+								}
+							} else if (i == statementsLength - 1 && insertNewLineAfterLastStatement) {
+								this.scribe.printNewLine();
+							}
+						}
+					} else {
+						this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+						this.scribe.printTrailingComment();
+						if (i != statementsLength - 1) {
+							if (!(statement instanceof EmptyStatement) && !(statements[i + 1] instanceof EmptyStatement)) {
+								this.scribe.printNewLine();
+							}
+						} else if (i == statementsLength - 1 && insertNewLineAfterLastStatement) {
+							this.scribe.printNewLine();
+						}
+					}
+				} else {
+					this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+					this.scribe.printTrailingComment();
+					if (i != statementsLength - 1) {
+						if (!(statement instanceof EmptyStatement) && !(statements[i + 1] instanceof EmptyStatement)) {
+							this.scribe.printNewLine();
+						}
+					} else if (i == statementsLength - 1 && insertNewLineAfterLastStatement) {
+						this.scribe.printNewLine();
+					}
+				}
+			} else if (i != statementsLength - 1) {
+				if (!(statement instanceof EmptyStatement) && !(statements[i + 1] instanceof EmptyStatement)) {
+					this.scribe.printNewLine();
+				}
+			} else if (i == statementsLength - 1 && insertNewLineAfterLastStatement) {
+				this.scribe.printNewLine();
+			}
 		}
-		this.indentationLevel = current.location.outputIndentationLevel;
-		this.numberOfIndentations = current.location.numberOfIndentations;
-		this.formatter.lastLocalDeclarationSourceStart = alignment.location.lastLocalDeclarationSourceStart;	
-		this.memberAlignment = current.enclosing;
 	}
 	
-	public Alignment getAlignment(String name){
-		if (this.currentAlignment != null) {
-			return this.currentAlignment.getAlignment(name);
+	private void formatThrowsClause(
+		AbstractMethodDeclaration methodDeclaration,
+		boolean spaceBeforeComma,
+		boolean spaceAfterComma,
+		int alignmentForThrowsClause) {
+			
+		final TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions;
+		if (thrownExceptions != null) {
+			int thrownExceptionsLength = thrownExceptions.length;
+			Alignment throwsAlignment = this.scribe.createAlignment(
+					"throws",//$NON-NLS-1$
+					alignmentForThrowsClause,
+					thrownExceptionsLength, // throws is the first token
+					this.scribe.scanner.currentPosition);
+		
+			this.scribe.enterAlignment(throwsAlignment);
+			boolean ok = false;
+			do {
+				try {
+					this.scribe.alignFragment(throwsAlignment, 0);
+					this.scribe.printNextToken(TerminalTokens.TokenNamethrows, true); 
+		
+					for (int i = 0; i < thrownExceptionsLength; i++) {
+						if (i > 0) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, spaceBeforeComma);
+							this.scribe.printTrailingComment();
+							this.scribe.alignFragment(throwsAlignment, i);
+							if (spaceAfterComma) {
+								this.scribe.space();
+							}
+						} else {
+							this.scribe.space();
+						}
+						thrownExceptions[i].traverse(this, methodDeclaration.scope);
+					}
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(throwsAlignment, true);
 		}
-		return null;
 	}
-	
-	/** 
-	 * Answer actual indentation level based on true column position
-	 * @return int
+
+	/*
+	 * Merged traversal of member (types, fields, methods)
 	 */
-	public int getColumnIndentationLevel() {
-		return this.column - 1;
-	}	
+	private void formatTypeMembers(TypeDeclaration typeDeclaration) {
+		Alignment memberAlignment = this.scribe.createMemberAlignment("typeMembers", this.preferences.align_type_members_on_columns ? Alignment.M_MULTICOLUMN : Alignment.M_NO_ALIGNMENT, 3, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+		this.scribe.enterMemberAlignment(memberAlignment);
+		ASTNode[] members = computeMergedMemberDeclarations(typeDeclaration);
+		boolean isChunkStart = false;
+		boolean ok = false;
+		int startIndex = 0;
+		do {
+			try {
+				for (int i = startIndex, max = members.length; i < max; i++) {
+					ASTNode member = members[i];
+					if (member instanceof FieldDeclaration) {
+						isChunkStart = memberAlignment.checkChunkStart(Alignment.CHUNK_FIELD, i, this.scribe.scanner.currentPosition);
+						if (member instanceof MultiFieldDeclaration) {
+							MultiFieldDeclaration multiField = (MultiFieldDeclaration) member;
+							
+							if (multiField.isStatic()) {
+								format(multiField, this, typeDeclaration.staticInitializerScope, isChunkStart, i == 0);
+							} else {
+								format(multiField, this, typeDeclaration.initializerScope, isChunkStart, i == 0);
+							}					
+						} else if (member instanceof Initializer) {
+							int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+							if (newLineBeforeChunk > 0 && i != 0) {
+								this.scribe.printEmptyLines(newLineBeforeChunk);
+							} else if (i == 0) {
+								int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+								if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+									this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
+								}
+							}
+							Initializer initializer = (Initializer) member;
+							if (initializer.isStatic()) {
+								initializer.traverse(this, typeDeclaration.staticInitializerScope);
+							} else {
+								initializer.traverse(this, typeDeclaration.initializerScope);
+							}					
+						} else {
+							FieldDeclaration field = (FieldDeclaration) member;
+							if (field.isStatic()) {
+								format(field, this, typeDeclaration.staticInitializerScope, isChunkStart, i == 0);
+							} else {
+								format(field, this, typeDeclaration.initializerScope, isChunkStart, i == 0);
+							}					
+						}
+					} else if (member instanceof AbstractMethodDeclaration) {
+						isChunkStart = memberAlignment.checkChunkStart(Alignment.CHUNK_METHOD, i, this.scribe.scanner.currentPosition);
+						format((AbstractMethodDeclaration) member, typeDeclaration.scope, isChunkStart, i == 0);
+					} else if (member instanceof TypeDeclaration) {
+						isChunkStart = memberAlignment.checkChunkStart(Alignment.CHUNK_TYPE, i, this.scribe.scanner.currentPosition);
+						format((TypeDeclaration)member, typeDeclaration.scope, isChunkStart, i == 0);
+					}
+					if (isNextToken(TerminalTokens.TokenNameSEMICOLON)) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+						this.scribe.printTrailingComment();
+					}
+					this.scribe.printNewLine();
+					// realign to the proper value
+					if (this.scribe.memberAlignment != null) {
+						// select the last alignment
+						this.scribe.indentationLevel = this.scribe.memberAlignment.originalIndentationLevel;
+					}
+				}
+				ok = true;
+			} catch(AlignmentException e){
+				startIndex = memberAlignment.chunkStartIndex;
+				this.scribe.redoMemberAlignment(e);
+			}
+		} while (!ok);
+		this.scribe.printComment();
+		this.scribe.exitMemberAlignment(memberAlignment);
+	}
+
+	private void formatTypeOpeningBraceForEnumConstant(String bracePosition, boolean insertSpaceBeforeBrace, TypeDeclaration typeDeclaration) {
+		int fieldCount = (typeDeclaration.fields == null) ? 0 : typeDeclaration.fields.length;
+		int methodCount = (typeDeclaration.methods == null) ? 0 : typeDeclaration.methods.length;
+		int typeCount = (typeDeclaration.memberTypes == null) ? 0 : typeDeclaration.memberTypes.length;
 	
-	public final int getCommentIndex(int position) {
-		if (this.commentPositions == null)
-			return -1;
-		int length = this.commentPositions.length;
-		if (length == 0) {
-			return -1;
+		if (methodCount == 1 && typeDeclaration.methods[0].isDefaultConstructor()) {
+			methodCount = 0;
 		}
-		int g = 0, d = length - 1;
-		int m = 0;
-		while (g <= d) {
-			m = (g + d) / 2;
-			int bound = this.commentPositions[m][1];
-			if (bound < 0) {
-				bound = -bound;
+		final int memberLength = fieldCount + methodCount+typeCount;
+
+		boolean insertNewLine = memberLength > 0;
+		
+		if (!insertNewLine) {
+			if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {
+				insertNewLine = this.preferences.insert_new_line_in_empty_enum_constant;
 			}
-			if (bound < position) {
-				g = m + 1;
-			} else if (bound > position) {
-				d = m - 1;
+		}
+	
+		formatOpeningBrace(bracePosition, insertSpaceBeforeBrace);
+		
+		if (insertNewLine) {
+			this.scribe.printNewLine();
+		}
+	}
+	private void formatTypeOpeningBrace(String bracePosition, boolean insertSpaceBeforeBrace, TypeDeclaration typeDeclaration) {
+		int fieldCount = (typeDeclaration.fields == null) ? 0 : typeDeclaration.fields.length;
+		int methodCount = (typeDeclaration.methods == null) ? 0 : typeDeclaration.methods.length;
+		int typeCount = (typeDeclaration.memberTypes == null) ? 0 : typeDeclaration.memberTypes.length;
+	
+		if (methodCount == 1 && typeDeclaration.methods[0].isDefaultConstructor()) {
+			methodCount = 0;
+		}
+		final int memberLength = fieldCount + methodCount + typeCount;
+
+		boolean insertNewLine = memberLength > 0;
+		
+		if (!insertNewLine) {
+			if (TypeDeclaration.kind(typeDeclaration.modifiers) == TypeDeclaration.ENUM_DECL) {
+				insertNewLine = this.preferences.insert_new_line_in_empty_enum_declaration;
+			} else if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {
+				insertNewLine = this.preferences.insert_new_line_in_empty_anonymous_type_declaration;
 			} else {
-				return m;
+				insertNewLine = this.preferences.insert_new_line_in_empty_type_declaration;
 			}
 		}
-		return -(g + 1);
+	
+		formatOpeningBrace(bracePosition, insertSpaceBeforeBrace);
+		
+		if (insertNewLine) {
+			this.scribe.printNewLine();
+		}
 	}
+	private int getDimensions() {
 
-	public String getEmptyLines(int linesNumber) {
-		if (this.nlsTagCounter > 0) {
-			return EMPTY_STRING;
+		this.localScanner.resetTo(this.scribe.scanner.currentPosition, this.scribe.scannerEndPosition - 1);
+		int dimensions = 0;
+		try {
+			int token;
+			while ((token = this.localScanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
+				switch(token) {
+					case TerminalTokens.TokenNameRBRACKET:
+						dimensions++;
+						break;
+					case TerminalTokens.TokenNameCOMMENT_BLOCK :
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+					case TerminalTokens.TokenNameCOMMENT_LINE :
+					case TerminalTokens.TokenNameLBRACKET :
+						break;
+					default:
+						return dimensions;
+				}
+			}
+		} catch(InvalidInputException e) {
+			// ignore
 		}
-		StringBuffer buffer = new StringBuffer();
-		if (lastNumberOfNewLines == 0) {
-			linesNumber++; // add an extra line breaks
-			for (int i = 0; i < linesNumber; i++) {
-                if (indentEmptyLines) printIndentationIfNecessary(buffer);
-				buffer.append(this.lineSeparator);
+		return dimensions;
+	}
+
+	private boolean hasComments() {
+
+		this.localScanner.resetTo(this.scribe.scanner.startPosition, this.scribe.scannerEndPosition - 1);
+		try {
+			switch(this.localScanner.getNextToken()) {
+				case TerminalTokens.TokenNameCOMMENT_BLOCK :
+				case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+				case TerminalTokens.TokenNameCOMMENT_LINE :
+					return true;
 			}
-			lastNumberOfNewLines += linesNumber;
-			line += linesNumber;
-			column = 1;
-			needSpace = false;
-			this.pendingSpace = false;
-		} else if (lastNumberOfNewLines == 1) {
-			for (int i = 0; i < linesNumber; i++) {
-                if (indentEmptyLines) printIndentationIfNecessary(buffer);
-				buffer.append(this.lineSeparator);
+		} catch(InvalidInputException e) {
+			// ignore
+		}
+		return false;
+	}
+
+	private boolean isNextToken(int tokenName) {
+		this.localScanner.resetTo(this.scribe.scanner.currentPosition, this.scribe.scannerEndPosition - 1);
+		try {
+			int token = this.localScanner.getNextToken();
+			loop: while(true) {
+				switch(token) {
+					case TerminalTokens.TokenNameCOMMENT_BLOCK :
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+					case TerminalTokens.TokenNameCOMMENT_LINE :
+						token = this.localScanner.getNextToken();
+						continue loop;
+					default:
+						break loop;
+				}
 			}
-			lastNumberOfNewLines += linesNumber;
-			line += linesNumber;
-			column = 1;
-			needSpace = false;
-			this.pendingSpace = false;
-		} else {
-			if ((lastNumberOfNewLines - 1) >= linesNumber) {
-				// there is no need to add new lines
-				return EMPTY_STRING;
+			return  token == tokenName;
+		} catch(InvalidInputException e) {
+			// ignore
+		}
+		return false;
+	}
+
+	private boolean isClosingGenericToken() {
+		this.localScanner.resetTo(this.scribe.scanner.currentPosition, this.scribe.scannerEndPosition - 1);
+		try {
+			int token = this.localScanner.getNextToken();
+			loop: while(true) {
+				switch(token) {
+					case TerminalTokens.TokenNameCOMMENT_BLOCK :
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+					case TerminalTokens.TokenNameCOMMENT_LINE :
+						token = this.localScanner.getNextToken();
+						continue loop;
+					default:
+						break loop;
+				}
 			}
-			final int realNewLineNumber = linesNumber - lastNumberOfNewLines + 1;
-			for (int i = 0; i < realNewLineNumber; i++) {
-                if (indentEmptyLines) printIndentationIfNecessary(buffer);
-				buffer.append(this.lineSeparator);
+			switch(token) {
+				case TerminalTokens.TokenNameGREATER :
+				case TerminalTokens.TokenNameRIGHT_SHIFT :
+				case TerminalTokens.TokenNameUNSIGNED_RIGHT_SHIFT :
+					return true;
 			}
-			lastNumberOfNewLines += realNewLineNumber;
-			line += realNewLineNumber;
-			column = 1;
-			needSpace = false;
-			this.pendingSpace = false;
+		} catch(InvalidInputException e) {
+			// ignore
 		}
-		return String.valueOf(buffer);
+		return false;
 	}
 
-	public OptimizedReplaceEdit getLastEdit() {
-		if (this.editsIndex > 0) {
-			return this.edits[this.editsIndex - 1];
+	private boolean isGuardClause(Block block) {
+		return !commentStartsBlock(block.sourceStart, block.sourceEnd)
+				&& block.statements != null
+				&& block.statements.length == 1
+				&& (block.statements[0] instanceof ReturnStatement || block.statements[0] instanceof ThrowStatement);
+	}
+
+	private boolean isMultipleLocalDeclaration(LocalDeclaration localDeclaration) {
+
+		if (localDeclaration.declarationSourceStart == this.lastLocalDeclarationSourceStart) return true;
+		this.lastLocalDeclarationSourceStart = localDeclaration.declarationSourceStart;
+		return false;
+	}
+
+	private boolean isPartOfMultipleLocalDeclaration() {
+		this.localScanner.resetTo(this.scribe.scanner.currentPosition, this.scribe.scannerEndPosition - 1);
+		try {
+			int token;
+			while ((token = this.localScanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
+				switch(token) {
+					case TerminalTokens.TokenNameCOMMA ://90
+						return true;
+					case TerminalTokens.TokenNameCOMMENT_BLOCK :
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+					case TerminalTokens.TokenNameCOMMENT_LINE :
+						break;
+					default:
+						return false;
+				}
+			}
+		} catch(InvalidInputException e) {
+			// ignore
 		}
-		return null;
+		return false;
 	}
-	
-	public final int getLineEnd(int lineNumber) {
-		if (this.lineEnds == null) 
-			return -1;
-		if (lineNumber >= this.lineEnds.length + 1) 
-			return this.scannerEndPosition;
-		if (lineNumber <= 0) 
-			return -1;
-		return this.lineEnds[lineNumber-1]; // next line start one character behind the lineEnd of the previous line	
+
+	private void manageClosingParenthesizedExpression(Expression expression, int numberOfParens) {
+		for (int i = 0; i < numberOfParens; i++) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_parenthesized_expression);
+		}
 	}
-	
-	Alignment getMemberAlignment() {
-		return this.memberAlignment;
+
+	private void manageOpeningParenthesizedExpression(Expression expression, int numberOfParens) {
+		for (int i = 0; i < numberOfParens; i++) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_parenthesized_expression);
+			if (this.preferences.insert_space_after_opening_paren_in_parenthesized_expression) {
+				this.scribe.space();
+			}
+		}
 	}
-	
-	public String getNewLine() {
-		if (this.nlsTagCounter > 0) {
-			return EMPTY_STRING;
+			
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.AllocationExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		AllocationExpression allocationExpression,
+		BlockScope scope) {
+		// 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt
+
+		final int numberOfParens = (allocationExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(allocationExpression, numberOfParens);
 		}
-		if (lastNumberOfNewLines >= 1) {
-			column = 1; // ensure that the scribe is at the beginning of a new line
-			return EMPTY_STRING;
+		this.scribe.printNextToken(TerminalTokens.TokenNamenew);
+		TypeReference[] typeArguments = allocationExpression.typeArguments;
+		if (typeArguments != null) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_arguments); 
+				if (this.preferences.insert_space_after_opening_angle_bracket_in_type_arguments) {
+					this.scribe.space();
+				}
+				int length = typeArguments.length;
+				for (int i = 0; i < length - 1; i++) {
+					typeArguments[i].traverse(this, scope);
+					this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_arguments);
+					if (this.preferences.insert_space_after_comma_in_type_arguments) {
+						this.scribe.space();
+					}				
+				}
+				typeArguments[length - 1].traverse(this, scope);
+				if (isClosingGenericToken()) {
+					this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_arguments); 
+				}
+				if (this.preferences.insert_space_after_closing_angle_bracket_in_type_arguments) {
+					this.scribe.space();
+				}
+		} else {
+			this.scribe.space();
 		}
-		line++;
-		lastNumberOfNewLines = 1;
-		column = 1;
-		needSpace = false;
-		this.pendingSpace = false;
-		return this.lineSeparator;
+
+		allocationExpression.type.traverse(this, scope);
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_method_invocation);
+
+		final Expression[] arguments = allocationExpression.arguments;
+		if (arguments != null) {
+			if (this.preferences.insert_space_after_opening_paren_in_method_invocation) {
+				this.scribe.space();
+			}			
+			int argumentLength = arguments.length;
+			Alignment argumentsAlignment =this.scribe.createAlignment(
+					"allocation",//$NON-NLS-1$
+					this.preferences.alignment_for_arguments_in_allocation_expression,
+					argumentLength,
+					this.scribe.scanner.currentPosition);
+			this.scribe.enterAlignment(argumentsAlignment);
+			boolean ok = false;
+			do {
+				try {
+					for (int i = 0; i < argumentLength; i++) {
+						if (i > 0) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_allocation_expression);
+							this.scribe.printTrailingComment();
+						}
+						this.scribe.alignFragment(argumentsAlignment, i);
+						if (i > 0 && this.preferences.insert_space_after_comma_in_allocation_expression) {
+							this.scribe.space();
+						}
+						arguments[i].traverse(this, scope);
+					}
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(argumentsAlignment, true);
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_method_invocation); 
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_between_empty_parens_in_method_invocation); 
+		}
+		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(allocationExpression, numberOfParens);
+		}
+		return false;
 	}
 
-	/** 
-	 * Answer next indentation level based on column estimated position
-	 * (if column is not indented, then use indentationLevel)
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
 	 */
-	public int getNextIndentationLevel(int someColumn) {
-		int indent = someColumn - 1;
-		if (indent == 0)
-			return this.indentationLevel;
-		if (this.tabChar == DefaultCodeFormatterOptions.TAB) {
-			if (this.useTabsOnlyForLeadingIndents) {
-				return indent;
+	public boolean visit(
+		AND_AND_Expression and_and_Expression,
+		BlockScope scope) {
+			
+		return dumpBinaryExpression(and_and_Expression, TerminalTokens.TokenNameAND_AND, scope);
+	}
+	public boolean visit(
+			AnnotationMethodDeclaration annotationTypeMemberDeclaration,
+			ClassScope scope) {        
+        /*
+         * Print comments to get proper line number
+         */
+        this.scribe.printComment();        
+        this.scribe.printModifiers(annotationTypeMemberDeclaration.annotations, this);
+		this.scribe.space();
+		/*
+		 * Print the method return type
+		 */	
+		final TypeReference returnType = annotationTypeMemberDeclaration.returnType;
+		final MethodScope annotationTypeMemberDeclarationScope = annotationTypeMemberDeclaration.scope;
+		
+		if (returnType != null) {
+			returnType.traverse(this, annotationTypeMemberDeclarationScope);
+		}
+		/*
+		 * Print the method name
+		 */
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true); 
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_annotation_type_member_declaration); 
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_between_empty_parens_in_annotation_type_member_declaration); 
+
+		/*
+		 * Check for extra dimensions
+		 */
+		int extraDimensions = annotationTypeMemberDeclaration.extendedDimensions;
+		if (extraDimensions != 0) {
+			 for (int i = 0; i < extraDimensions; i++) {
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			 }
+		}
+
+		Expression defaultValue = annotationTypeMemberDeclaration.defaultValue;
+		if (defaultValue != null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNamedefault, true);
+			this.scribe.space();
+			defaultValue.traverse(this, (BlockScope) null);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+		this.scribe.printTrailingComment();
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.Argument, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(Argument argument, BlockScope scope) {
+
+		if (argument.modifiers != NO_MODIFIERS || argument.annotations != null) {
+	        this.scribe.printComment();
+			this.scribe.printModifiers(argument.annotations, this);
+			this.scribe.space();
+		}
+
+		/*
+		 * Argument type 
+		 */
+		if (argument.type != null) {
+			argument.type.traverse(this, scope);
+		}
+		
+		if (argument.isVarArgs()) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameELLIPSIS, this.preferences.insert_space_before_ellipsis);
+			if (this.preferences.insert_space_after_ellipsis) {
+				this.scribe.space();
 			}
-			int rem = indent % this.indentationSize;
-			int addition = rem == 0 ? 0 : this.indentationSize - rem; // round to superior
-			return indent + addition;
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, false);
 		} else {
-			return indent;
+			/*
+			 * Print the argument name
+			 */	
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true);
 		}
+
+
+		/*
+		 * Check for extra dimensions
+		 */
+		int extraDimensions = getDimensions();
+		if (extraDimensions != 0) {
+			 for (int i = 0; i < extraDimensions; i++) {
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			 }
+		}
+		
+		return false;
 	}
 
-	private String getPreserveEmptyLines(int count) {
-		if (count > 0) {
-			if (this.formatter.preferences.number_of_empty_lines_to_preserve != 0) {
-				int linesToPreserve = Math.min(count, this.formatter.preferences.number_of_empty_lines_to_preserve);
-				return this.getEmptyLines(linesToPreserve);
-			} else {
-				return getNewLine();
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		ArrayAllocationExpression arrayAllocationExpression,
+		BlockScope scope) {
+
+			final int numberOfParens = (arrayAllocationExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+			if (numberOfParens > 0) {
+				manageOpeningParenthesizedExpression(arrayAllocationExpression, numberOfParens);
 			}
+			this.scribe.printNextToken(TerminalTokens.TokenNamenew);
+			this.scribe.space();
+			arrayAllocationExpression.type.traverse(this, scope);
+			
+			final Expression[] dimensions = arrayAllocationExpression.dimensions;
+			int dimensionsLength = dimensions.length;
+			for (int i = 0; i < dimensionsLength; i++) {
+				if (this.preferences.insert_space_before_opening_bracket_in_array_allocation_expression) {
+					this.scribe.space();
+				}
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET, false);
+				if (dimensions[i] != null) {
+					if (this.preferences.insert_space_after_opening_bracket_in_array_allocation_expression) {
+						this.scribe.space();
+					}
+					dimensions[i].traverse(this, scope);
+					this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET, this.preferences.insert_space_before_closing_bracket_in_array_allocation_expression);
+				} else {
+					this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET, this.preferences.insert_space_between_empty_brackets_in_array_allocation_expression);
+				}
+			}
+			final ArrayInitializer initializer = arrayAllocationExpression.initializer;
+			if (initializer != null) {
+				initializer.traverse(this, scope);
+			}
+
+			if (numberOfParens > 0) {
+				manageClosingParenthesizedExpression(arrayAllocationExpression, numberOfParens);
+			}
+			return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayInitializer, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(ArrayInitializer arrayInitializer, BlockScope scope) {		final int numberOfParens = (arrayInitializer.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(arrayInitializer, numberOfParens);
 		}
-		return EMPTY_STRING;
-	}
-	
-	public TextEdit getRootEdit() {
-		MultiTextEdit edit = null;
-		int length = this.textRegionEnd - this.textRegionStart + 1;
-		if (this.textRegionStart <= 0) {
-			if (length <= 0) {
-				edit = new MultiTextEdit(0, 0);
+		
+		final Expression[] expressions = arrayInitializer.expressions;
+		if (expressions != null) {
+			String array_initializer_brace_position = this.preferences.brace_position_for_array_initializer;
+			formatOpeningBrace(array_initializer_brace_position, this.preferences.insert_space_before_opening_brace_in_array_initializer);
+		
+			int expressionsLength = expressions.length;
+			final boolean insert_new_line_after_opening_brace = this.preferences.insert_new_line_after_opening_brace_in_array_initializer;
+			if (expressionsLength > 1) {
+				if (insert_new_line_after_opening_brace) {
+					this.scribe.printNewLine();
+				}
+				Alignment arrayInitializerAlignment =this.scribe.createAlignment(
+						"array_initializer",//$NON-NLS-1$
+						this.preferences.alignment_for_expressions_in_array_initializer,
+						Alignment.R_OUTERMOST,
+						expressionsLength,
+						this.scribe.scanner.currentPosition,
+						this.preferences.continuation_indentation_for_array_initializer,
+						true);
+				
+				if (insert_new_line_after_opening_brace) {
+				    arrayInitializerAlignment.fragmentIndentations[0] = arrayInitializerAlignment.breakIndentationLevel;
+				}
+				
+				this.scribe.enterAlignment(arrayInitializerAlignment);
+				boolean ok = false;
+				do {
+					try {
+						this.scribe.alignFragment(arrayInitializerAlignment, 0);
+						if (this.preferences.insert_space_after_opening_brace_in_array_initializer) {
+							this.scribe.space();
+						}
+						expressions[0].traverse(this, scope);
+						for (int i = 1; i < expressionsLength; i++) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_array_initializer);
+							this.scribe.printTrailingComment();
+							this.scribe.alignFragment(arrayInitializerAlignment, i);
+							if (this.preferences.insert_space_after_comma_in_array_initializer) {
+								this.scribe.space();
+							}
+							expressions[i].traverse(this, scope);
+							if (i == expressionsLength - 1) {
+								if (isNextToken(TerminalTokens.TokenNameCOMMA)) {
+									this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_array_initializer);
+									this.scribe.printTrailingComment();
+								}
+							}
+						}
+						ok = true;
+					} catch (AlignmentException e) {
+						this.scribe.redoAlignment(e);
+					}
+				} while (!ok);
+				this.scribe.exitAlignment(arrayInitializerAlignment, true);
 			} else {
-				edit = new MultiTextEdit(0, this.textRegionEnd + 1);
+				if (insert_new_line_after_opening_brace) {
+					this.scribe.printNewLine();
+					this.scribe.indent();
+				}
+				// we don't need to use an alignment
+				if (this.preferences.insert_space_after_opening_brace_in_array_initializer) {
+					this.scribe.space();
+				} else {
+					this.scribe.needSpace = false;
+				}
+				expressions[0].traverse(this, scope);
+				if (isNextToken(TerminalTokens.TokenNameCOMMA)) {
+					this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_array_initializer);
+					this.scribe.printTrailingComment();
+				}
+				if (insert_new_line_after_opening_brace) {
+					this.scribe.unIndent();
+				}
 			}
+			if (this.preferences.insert_new_line_before_closing_brace_in_array_initializer) {
+				this.scribe.printNewLine();
+			} else if (this.preferences.insert_space_before_closing_brace_in_array_initializer) {
+				this.scribe.space();
+			}
+			this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, false); 
+			if (array_initializer_brace_position.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+				this.scribe.unIndent();
+			}	
 		} else {
-			edit = new MultiTextEdit(this.textRegionStart, this.textRegionEnd - this.textRegionStart + 1);
-		}
-		for (int i= 0, max = this.editsIndex; i < max; i++) {
-			OptimizedReplaceEdit currentEdit = edits[i];
-			if (isValidEdit(currentEdit)) {
-				edit.addChild(new ReplaceEdit(currentEdit.offset, currentEdit.length, currentEdit.replacement));
+			boolean keepEmptyArrayInitializerOnTheSameLine = this.preferences.keep_empty_array_initializer_on_one_line;
+			String array_initializer_brace_position = this.preferences.brace_position_for_array_initializer;
+			if (keepEmptyArrayInitializerOnTheSameLine) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACE, this.preferences.insert_space_before_opening_brace_in_array_initializer);
+				this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, this.preferences.insert_space_between_empty_braces_in_array_initializer); 
+			} else {
+				formatOpeningBrace(array_initializer_brace_position, this.preferences.insert_space_before_opening_brace_in_array_initializer);
+				this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, false); 
+				if (array_initializer_brace_position.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+					this.scribe.unIndent();
+				}
 			}
 		}
-		this.edits = null;
-		return edit;
+	
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(arrayInitializer, numberOfParens);
+		}
+		return false;
 	}
 	
-	public void handleLineTooLong() {
-		// search for closest breakable alignment, using tiebreak rules
-		// look for outermost breakable one
-		int relativeDepth = 0, outerMostDepth = -1;
-		Alignment targetAlignment = this.currentAlignment;
-		while (targetAlignment != null){
-			if (targetAlignment.tieBreakRule == Alignment.R_OUTERMOST && targetAlignment.couldBreak()){
-				outerMostDepth = relativeDepth;
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		ArrayQualifiedTypeReference arrayQualifiedTypeReference,
+		BlockScope scope) {
+
+			final int numberOfParens = (arrayQualifiedTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+			if (numberOfParens > 0) {
+				manageOpeningParenthesizedExpression(arrayQualifiedTypeReference, numberOfParens);
 			}
-			targetAlignment = targetAlignment.enclosing;
-			relativeDepth++;
+			this.scribe.printArrayQualifiedReference(arrayQualifiedTypeReference.tokens.length, arrayQualifiedTypeReference.sourceEnd);
+			int dimensions = getDimensions();
+			if (dimensions != 0) {
+				for (int i = 0; i < dimensions; i++) {
+					this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+					this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+				}
+			}
+			if (numberOfParens > 0) {
+				manageClosingParenthesizedExpression(arrayQualifiedTypeReference, numberOfParens);
+			}
+			return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference, org.eclipse.jdt.internal.compiler.lookup.ClassScope)
+	 */
+	public boolean visit(
+		ArrayQualifiedTypeReference arrayQualifiedTypeReference,
+		ClassScope scope) {
+
+			final int numberOfParens = (arrayQualifiedTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+			if (numberOfParens > 0) {
+				manageOpeningParenthesizedExpression(arrayQualifiedTypeReference, numberOfParens);
+			}
+			this.scribe.printArrayQualifiedReference(arrayQualifiedTypeReference.tokens.length, arrayQualifiedTypeReference.sourceEnd);
+			int dimensions = getDimensions();
+			if (dimensions != 0) {
+				for (int i = 0; i < dimensions; i++) {
+					this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+					this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+				}
+			}
+			if (numberOfParens > 0) {
+				manageClosingParenthesizedExpression(arrayQualifiedTypeReference, numberOfParens);
+			}
+			return false;
+	}
+
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(ArrayReference arrayReference, BlockScope scope) {
+
+		final int numberOfParens = (arrayReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(arrayReference, numberOfParens);
 		}
-		if (outerMostDepth >= 0) {
-			throw new AlignmentException(AlignmentException.LINE_TOO_LONG, outerMostDepth);
+		arrayReference.receiver.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET, this.preferences.insert_space_before_opening_bracket_in_array_reference);
+		if (this.preferences.insert_space_after_opening_bracket_in_array_reference) {
+			this.scribe.space();
 		}
-		// look for innermost breakable one
-		relativeDepth = 0;
-		targetAlignment = this.currentAlignment;
-		while (targetAlignment != null){
-			if (targetAlignment.couldBreak()){
-				throw new AlignmentException(AlignmentException.LINE_TOO_LONG, relativeDepth);
+		arrayReference.position.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET, this.preferences.insert_space_before_closing_bracket_in_array_reference);
+		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(arrayReference, numberOfParens);
+		}
+		return false;
+	}
+	
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		ArrayTypeReference arrayTypeReference,
+		BlockScope scope) {
+
+		final int numberOfParens = (arrayTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(arrayTypeReference, numberOfParens);
+		}
+		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS);
+		
+		int dimensions = getDimensions();
+		if (dimensions != 0) {
+			if (this.preferences.insert_space_before_opening_bracket_in_array_type_reference) {
+				this.scribe.space();
 			}
-			targetAlignment = targetAlignment.enclosing;
-			relativeDepth++;
+			for (int i = 0; i < dimensions; i++) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+				if (this.preferences.insert_space_between_brackets_in_array_type_reference) {
+					this.scribe.space();
+				}
+				this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			}
 		}
-		// did not find any breakable location - proceed
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(arrayTypeReference, numberOfParens);
+		}
+		return false;
 	}
 
-	/*
-	 * Check if there is a NLS tag on this line. If yes, return true, returns false otherwise.
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference, org.eclipse.jdt.internal.compiler.lookup.ClassScope)
 	 */
-	private boolean hasNLSTag(int sourceStart) {
-		// search the last comment where commentEnd < current lineEnd
-		if (this.lineEnds == null) return false;
-		int index = Arrays.binarySearch(this.lineEnds, sourceStart);
-		int currentLineEnd = this.getLineEnd(-index);
-		if (currentLineEnd != -1) {
-			int commentIndex = getCommentIndex(currentLineEnd);
-			if (commentIndex < 0) {
-				commentIndex = -commentIndex - 2;
+	public boolean visit(
+		ArrayTypeReference arrayTypeReference,
+		ClassScope scope) {
+
+		final int numberOfParens = (arrayTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) { 
+			manageOpeningParenthesizedExpression(arrayTypeReference, numberOfParens);
+		}
+		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS);
+		int dimensions = getDimensions();
+		if (dimensions != 0) {
+			if (this.preferences.insert_space_before_opening_bracket_in_array_type_reference) {
+				this.scribe.space();
 			}
-			if (commentIndex >= 0 && commentIndex < this.commentPositions.length) {
-				int start = this.commentPositions[commentIndex][0];
-				if (start < 0) {
-					start = -start;
-					// check that we are on the same line
-					int lineIndexForComment = Arrays.binarySearch(this.lineEnds, start);
-					if (lineIndexForComment == index) {
-						return CharOperation.indexOf(Scanner.TAG_PREFIX, this.scanner.source, true, start) != -1;
-					}
+			for (int i = 0; i < dimensions; i++) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+				if (this.preferences.insert_space_between_brackets_in_array_type_reference) {
+					this.scribe.space();
 				}
+				this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
 			}
 		}
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(arrayTypeReference, numberOfParens);
+		}
 		return false;
 	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.AssertStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(AssertStatement assertStatement, BlockScope scope) {
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNameassert);
+		this.scribe.space();
+		assertStatement.assertExpression.traverse(this, scope);
+		
+		if (assertStatement.exceptionArgument != null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameCOLON, this.preferences.insert_space_before_colon_in_assert);
+			if (this.preferences.insert_space_after_colon_in_assert) {
+				this.scribe.space();
+			}
+			assertStatement.exceptionArgument.traverse(this, scope);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);		
+		this.scribe.printTrailingComment();
+		return false;
+	}
 	
-	public void indent() {
-		this.indentationLevel += this.indentationSize;
-		this.numberOfIndentations++;
-	}	
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.Assignment, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(Assignment assignment, BlockScope scope) {
 
+		final int numberOfParens = (assignment.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(assignment, numberOfParens);
+		}
+		assignment.lhs.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameEQUAL, this.preferences.insert_space_before_assignment_operator);
+		if (this.preferences.insert_space_after_assignment_operator) {
+			this.scribe.space();
+		}
+
+		Alignment assignmentAlignment = this.scribe.createAlignment("assignmentAlignment", this.preferences.alignment_for_assignment, Alignment.R_OUTERMOST, 1, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+		this.scribe.enterAlignment(assignmentAlignment);
+		boolean ok = false;
+		do {
+			try {
+				this.scribe.alignFragment(assignmentAlignment, 0);
+				assignment.expression.traverse(this, scope);
+				ok = true;
+			} catch(AlignmentException e){
+				this.scribe.redoAlignment(e);
+			}
+		} while (!ok);		
+		this.scribe.exitAlignment(assignmentAlignment, true);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(assignment, numberOfParens);
+		}
+		return false;
+	}
+
 	/**
-	 * @param compilationUnitSource
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.BinaryExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
 	 */
-	public void initializeScanner(char[] compilationUnitSource) {
-		this.scanner.setSource(compilationUnitSource);
-		this.scannerEndPosition = compilationUnitSource.length;
-		thi