/*
 * generated by Xtext
 */
package ca.queensu.cs.mase.formatting;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter;
import org.eclipse.xtext.formatting.impl.FormattingConfig;
import org.eclipse.xtext.util.Pair;

import ca.queensu.cs.mase.services.UrmlGrammarAccess;

/**
 * This class contains custom formatting description.
 * 
 * see : http://www.eclipse.org/Xtext/documentation/latest/xtext.html#formatting
 * on how and when to use it
 * 
 * Also see {@link org.eclipse.xtext.xtext.XtextFormattingTokenSerializer} as an
 * example
 */
public class UrmlFormatter extends AbstractDeclarativeFormatter {

	@Override
	protected void configureFormatting(FormattingConfig c) {
		UrmlGrammarAccess f = (UrmlGrammarAccess) getGrammarAccess();

		setCommenting(c, f);
		c.setAutoLinewrap(120);
		setParenAndBraces(c, f);
		setLeftParenAndComma(c, f);
		c.setNoSpace().after(
				f.getUnaryExpressionAccess().getHyphenMinusKeyword_1_1());
		c.setNoSpace()
				.after(f.getNotBooleanExpressionAccess()
						.getExclamationMarkKeyword_0());
		c.setNoSpace().after(f.getPortAccess().getConjugatedTildeKeyword_1_0());
		setLineWrapForKeyword(c, f);
		c.setNoLinewrap()
				.after(f.getCapsuleAccess().getExternalKeyword_4_0_0());
		setPeriods(c, f);
		c.setSpace(" ").after(f.getState_Access().getSubKeyword_3_3_0());
	}

	private void setPeriods(FormattingConfig c, UrmlGrammarAccess f) {
		for (Keyword kw : f.findKeywords(".")) {
			c.setNoSpace().before(kw);
			c.setNoSpace().after(kw);
		}
	}

	private void setParenAndBraces(FormattingConfig c, UrmlGrammarAccess f) {
		for (final Pair<Keyword, Keyword> pair : f.findKeywordPairs("(", ")")) {
			c.setNoSpace().after(pair.getFirst());
			c.setNoSpace().before(pair.getSecond());
		}
		for (final Pair<Keyword, Keyword> pair : f.findKeywordPairs("{", "}")) {
			c.setSpace(" ").before(pair.getFirst());
			c.setLinewrap().after(pair.getFirst());
			c.setLinewrap().before(pair.getSecond());
			c.setIndentation(pair.getFirst(), pair.getSecond());
		}
	}

	private void setCommenting(FormattingConfig c, UrmlGrammarAccess f) {
		// It's usually a good idea to activate the following three statements.
		// They will add and preserve newlines around comments
		c.setLinewrap(0, 1, 2).before(f.getSL_COMMENTRule());
		c.setLinewrap(0, 1, 2).before(f.getML_COMMENTRule());
		c.setLinewrap(0, 1, 1).after(f.getML_COMMENTRule());
	}

	private void setLineWrapForKeyword(FormattingConfig c, UrmlGrammarAccess f) {
		EObject[] linewrapElem = new EObject[] { f.getModelRule(),
				f.getModelAccess().getModelKeyword_0(), f.getAttributeRule(),
				f.getProtocolAccess().getProtocolKeyword_0(),
				f.getProtocolAccess().getIncomingKeyword_3_0_0(),
				f.getProtocolAccess().getOutgoingKeyword_3_1_0(),
				f.getSignalRule(), f.getCapsuleRule(), f.getOperationRule(),
				f.getTimerPortRule(), f.getLogPortRule(), f.getPortRule(),
				f.getConnectorRule(), f.getCapsuleInstRule(),
				f.getStateMachineRule(), f.getState_Rule(),
				f.getState_Access().getEntryKeyword_3_1_0(),
				f.getState_Access().getSubKeyword_3_3_0(),
				f.getState_Access().getExitKeyword_3_2_0(),
				f.getTransitionRule(),
				f.getTransitionAccess().getGuardKeyword_7_0(),
				f.getTransitionAccess().getTriggeredByKeyword_8_0(),
				f.getTransitionAccess().getActionKeyword_9_0(),
				f.getStatementRule(), f.getStatementOperationRule(),

				f.getCapsuleAccess().getExternalKeyword_4_0_0() };

		for (final EObject obj : linewrapElem) {
			c.setLinewrap().before(obj);
		}
	}

	private void setLeftParenAndComma(FormattingConfig c, UrmlGrammarAccess f) {
		c.setNoSpace().before(f.getOperationAccess().getCommaKeyword_4_1_0());
		c.setNoSpace().before(
				f.getOperationAccess().getLeftParenthesisKeyword_3());
		c.setNoSpace().before(f.getInvokeAccess().getCommaKeyword_3_1_0());
		c.setNoSpace()
				.before(f.getInvokeAccess().getLeftParenthesisKeyword_2());
		c.setNoSpace()
				.before(f.getFunctionCallAccess().getCommaKeyword_3_1_0());
		c.setNoSpace().before(
				f.getFunctionCallAccess().getLeftParenthesisKeyword_2());
		c.setNoSpace().before(f.getSignalAccess().getCommaKeyword_2_1_0());
		c.setNoSpace()
				.before(f.getSignalAccess().getLeftParenthesisKeyword_1());
		c.setNoSpace().before(f.getTrigger_inAccess().getCommaKeyword_4_1_0());
		c.setNoSpace().before(
				f.getTrigger_inAccess().getLeftParenthesisKeyword_3());
		c.setNoSpace().before(f.getTrigger_outAccess().getCommaKeyword_4_1_0());
		c.setNoSpace().before(
				f.getTrigger_outAccess().getLeftParenthesisKeyword_3());
	}
}
