private void WhiteSpace_BreakAsExpected(TSqlFormattingState state)
 {
     if (state.BreakExpected)
     {
         state.WhiteSpace_BreakToNextLine();
     }
     if (state.AdditionalBreakExpected)
     {
         state.WhiteSpace_BreakToNextLine();
         state.AdditionalBreakExpected = false;
     }
 }
        private void ProcessSqlNode(XmlElement contentElement, TSqlFormattingState state)
        {
            int initialIndent = state.IndentLevel;

            switch (contentElement.Name)
            {
            case SqlXmlConstants.ENAME_SQL_STATEMENT:
                WhiteSpace_SeparateStatements(contentElement, state);
                state.ResetKeywords();
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state);
                state.StatementBreakExpected = true;
                break;

            case SqlXmlConstants.ENAME_SQL_CLAUSE:
                state.UnIndentInitialBreak = true;
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state.IncrementIndent());
                state.DecrementIndent();
                state.BreakExpected = true;
                break;

            case SqlXmlConstants.ENAME_SET_OPERATOR_CLAUSE:
                state.DecrementIndent();
                state.WhiteSpace_BreakToNextLine();     //this is the one already recommended by the start of the clause
                state.WhiteSpace_BreakToNextLine();     //this is the one we additionally want to apply
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state.IncrementIndent());
                state.BreakExpected           = true;
                state.AdditionalBreakExpected = true;
                break;

            case SqlXmlConstants.ENAME_BATCH_SEPARATOR:
                //newline regardless of whether previous element recommended a break or not.
                state.WhiteSpace_BreakToNextLine();
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state);
                state.BreakExpected = true;
                break;

            case SqlXmlConstants.ENAME_DDL_PROCEDURAL_BLOCK:
            case SqlXmlConstants.ENAME_DDL_OTHER_BLOCK:
            case SqlXmlConstants.ENAME_CURSOR_DECLARATION:
            case SqlXmlConstants.ENAME_BEGIN_TRANSACTION:
            case SqlXmlConstants.ENAME_SAVE_TRANSACTION:
            case SqlXmlConstants.ENAME_COMMIT_TRANSACTION:
            case SqlXmlConstants.ENAME_ROLLBACK_TRANSACTION:
            case SqlXmlConstants.ENAME_CONTAINER_OPEN:
            case SqlXmlConstants.ENAME_CONTAINER_CLOSE:
            case SqlXmlConstants.ENAME_WHILE_LOOP:
            case SqlXmlConstants.ENAME_IF_STATEMENT:
            case SqlXmlConstants.ENAME_SELECTIONTARGET:
            case SqlXmlConstants.ENAME_CONTAINER_GENERALCONTENT:
            case SqlXmlConstants.ENAME_CTE_WITH_CLAUSE:
            case SqlXmlConstants.ENAME_PERMISSIONS_BLOCK:
            case SqlXmlConstants.ENAME_PERMISSIONS_DETAIL:
            case SqlXmlConstants.ENAME_MERGE_CLAUSE:
            case SqlXmlConstants.ENAME_MERGE_TARGET:
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state);
                break;

            case SqlXmlConstants.ENAME_CASE_INPUT:
            case SqlXmlConstants.ENAME_BOOLEAN_EXPRESSION:
            case SqlXmlConstants.ENAME_BETWEEN_LOWERBOUND:
            case SqlXmlConstants.ENAME_BETWEEN_UPPERBOUND:
                WhiteSpace_SeparateWords(state);
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state);
                break;

            case SqlXmlConstants.ENAME_CONTAINER_SINGLESTATEMENT:
            case SqlXmlConstants.ENAME_CONTAINER_MULTISTATEMENT:
            case SqlXmlConstants.ENAME_MERGE_ACTION:
                state.BreakExpected = true;
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state);
                state.StatementBreakExpected = false;   //the responsibility for breaking will be with the OUTER statement; there should be no consequence propagating out from statements in this container;
                state.UnIndentInitialBreak   = false;   //if there was no word spacing after the last content statement's clause starter, doesn't mean the unIndent should propagate to the following content!
                break;

            case SqlXmlConstants.ENAME_PERMISSIONS_TARGET:
            case SqlXmlConstants.ENAME_PERMISSIONS_RECIPIENT:
            case SqlXmlConstants.ENAME_DDL_WITH_CLAUSE:
            case SqlXmlConstants.ENAME_MERGE_CONDITION:
            case SqlXmlConstants.ENAME_MERGE_THEN:
                state.BreakExpected        = true;
                state.UnIndentInitialBreak = true;
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state.IncrementIndent());
                state.DecrementIndent();
                break;

            case SqlXmlConstants.ENAME_JOIN_ON_SECTION:
                if (BreakJoinOnSections)
                {
                    state.BreakExpected = true;
                }
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_OPEN), state);
                if (BreakJoinOnSections)
                {
                    state.IncrementIndent();
                }
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_GENERALCONTENT), state);
                if (BreakJoinOnSections)
                {
                    state.DecrementIndent();
                }
                break;

            case SqlXmlConstants.ENAME_CTE_ALIAS:
                state.UnIndentInitialBreak = true;
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state);
                break;

            case SqlXmlConstants.ENAME_ELSE_CLAUSE:
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_OPEN), state.DecrementIndent());
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_SINGLESTATEMENT), state.IncrementIndent());
                break;

            case SqlXmlConstants.ENAME_DDL_AS_BLOCK:
            case SqlXmlConstants.ENAME_CURSOR_FOR_BLOCK:
                state.BreakExpected = true;
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_OPEN), state.DecrementIndent());
                state.BreakExpected = true;
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_GENERALCONTENT), state);
                state.IncrementIndent();
                break;

            case SqlXmlConstants.ENAME_TRIGGER_CONDITION:
                state.DecrementIndent();
                state.WhiteSpace_BreakToNextLine();
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state.IncrementIndent());
                break;

            case SqlXmlConstants.ENAME_CURSOR_FOR_OPTIONS:
            case SqlXmlConstants.ENAME_CTE_AS_BLOCK:
                state.BreakExpected = true;
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_OPEN), state.DecrementIndent());
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_GENERALCONTENT), state.IncrementIndent());
                break;

            case SqlXmlConstants.ENAME_DDL_RETURNS:
            case SqlXmlConstants.ENAME_MERGE_USING:
            case SqlXmlConstants.ENAME_MERGE_WHEN:
                state.BreakExpected        = true;
                state.UnIndentInitialBreak = true;
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state);
                break;

            case SqlXmlConstants.ENAME_BETWEEN_CONDITION:
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_OPEN), state);
                state.IncrementIndent();
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_BETWEEN_LOWERBOUND), state.IncrementIndent());
                if (ExpandBetweenConditions)
                {
                    state.BreakExpected = true;
                }
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_CLOSE), state.DecrementIndent());
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_BETWEEN_UPPERBOUND), state.IncrementIndent());
                state.DecrementIndent();
                state.DecrementIndent();
                break;

            case SqlXmlConstants.ENAME_DDLDETAIL_PARENS:
            case SqlXmlConstants.ENAME_FUNCTION_PARENS:
                //simply process sub-nodes - don't add space or expect any linebreaks (but respect linebreaks if necessary)
                state.WordSeparatorExpected = false;
                WhiteSpace_BreakAsExpected(state);
                state.AddOutputContent(FormatOperator("("), Interfaces.SqlHtmlConstants.CLASS_OPERATOR);
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state.IncrementIndent());
                state.DecrementIndent();
                WhiteSpace_BreakAsExpected(state);
                state.AddOutputContent(FormatOperator(")"), Interfaces.SqlHtmlConstants.CLASS_OPERATOR);
                state.WordSeparatorExpected = true;
                break;

            case SqlXmlConstants.ENAME_DDL_PARENS:
            case SqlXmlConstants.ENAME_EXPRESSION_PARENS:
            case SqlXmlConstants.ENAME_SELECTIONTARGET_PARENS:
                WhiteSpace_SeparateWords(state);
                if (contentElement.Name.Equals(SqlXmlConstants.ENAME_EXPRESSION_PARENS))
                {
                    state.IncrementIndent();
                }
                state.AddOutputContent(FormatOperator("("), Interfaces.SqlHtmlConstants.CLASS_OPERATOR);
                TSqlFormattingState innerState = new TSqlFormattingState(state);
                ProcessSqlNodeList(contentElement.SelectNodes("*"), innerState);
                //if there was a linebreak in the parens content, or if it wanted one to follow, then put linebreaks before and after.
                if (innerState.BreakExpected || innerState.OutputContainsLineBreak)
                {
                    state.WhiteSpace_BreakToNextLine();
                    state.Assimilate(innerState);
                    state.WhiteSpace_BreakToNextLine();
                }
                else
                {
                    state.Assimilate(innerState);
                }
                state.AddOutputContent(FormatOperator(")"), Interfaces.SqlHtmlConstants.CLASS_OPERATOR);
                if (contentElement.Name.Equals(SqlXmlConstants.ENAME_EXPRESSION_PARENS))
                {
                    state.DecrementIndent();
                }
                state.WordSeparatorExpected = true;
                break;

            case SqlXmlConstants.ENAME_BEGIN_END_BLOCK:
            case SqlXmlConstants.ENAME_TRY_BLOCK:
            case SqlXmlConstants.ENAME_CATCH_BLOCK:
                if (contentElement.ParentNode.Name.Equals(SqlXmlConstants.ENAME_SQL_CLAUSE) &&
                    contentElement.ParentNode.ParentNode.Name.Equals(SqlXmlConstants.ENAME_SQL_STATEMENT) &&
                    contentElement.ParentNode.ParentNode.ParentNode.Name.Equals(SqlXmlConstants.ENAME_CONTAINER_SINGLESTATEMENT)
                    )
                {
                    state.DecrementIndent();
                }
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_OPEN), state);
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_MULTISTATEMENT), state);
                state.DecrementIndent();
                state.BreakExpected = true;
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_CLOSE), state);
                state.IncrementIndent();
                if (contentElement.ParentNode.Name.Equals(SqlXmlConstants.ENAME_SQL_CLAUSE) &&
                    contentElement.ParentNode.ParentNode.Name.Equals(SqlXmlConstants.ENAME_SQL_STATEMENT) &&
                    contentElement.ParentNode.ParentNode.ParentNode.Name.Equals(SqlXmlConstants.ENAME_CONTAINER_SINGLESTATEMENT)
                    )
                {
                    state.IncrementIndent();
                }
                break;

            case SqlXmlConstants.ENAME_CASE_STATEMENT:
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_OPEN), state);
                state.IncrementIndent();
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CASE_INPUT), state);
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CASE_WHEN), state);
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CASE_ELSE), state);
                if (ExpandCaseStatements)
                {
                    state.BreakExpected = true;
                }
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_CLOSE), state);
                state.DecrementIndent();
                break;

            case SqlXmlConstants.ENAME_CASE_WHEN:
            case SqlXmlConstants.ENAME_CASE_THEN:
            case SqlXmlConstants.ENAME_CASE_ELSE:
                if (ExpandCaseStatements)
                {
                    state.BreakExpected = true;
                }
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_OPEN), state);
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CONTAINER_GENERALCONTENT), state.IncrementIndent());
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_CASE_THEN), state);
                state.DecrementIndent();
                break;

            case SqlXmlConstants.ENAME_AND_OPERATOR:
            case SqlXmlConstants.ENAME_OR_OPERATOR:
                if (ExpandBooleanExpressions)
                {
                    state.BreakExpected = true;
                }
                ProcessSqlNodeList(contentElement.SelectNodes("*"), state);
                break;

            case SqlXmlConstants.ENAME_COMMENT_MULTILINE:
                WhiteSpace_SeparateComment(contentElement, state);
                state.AddOutputContent("/*" + contentElement.InnerText + "*/", Interfaces.SqlHtmlConstants.CLASS_COMMENT);
                if (contentElement.ParentNode.Name.Equals(SqlXmlConstants.ENAME_SQL_STATEMENT))
                {
                    state.BreakExpected = true;
                }
                else
                {
                    state.WordSeparatorExpected = true;
                }
                break;

            case SqlXmlConstants.ENAME_COMMENT_SINGLELINE:
                WhiteSpace_SeparateComment(contentElement, state);
                state.AddOutputContent("--" + contentElement.InnerText.Replace("\r", "").Replace("\n", ""), Interfaces.SqlHtmlConstants.CLASS_COMMENT);
                state.BreakExpected      = true;
                state.SourceBreakPending = true;
                break;

            case SqlXmlConstants.ENAME_STRING:
            case SqlXmlConstants.ENAME_NSTRING:
                WhiteSpace_SeparateWords(state);
                string outValue = null;
                if (contentElement.Name.Equals(SqlXmlConstants.ENAME_NSTRING))
                {
                    outValue = "N'" + contentElement.InnerText.Replace("'", "''") + "'";
                }
                else
                {
                    outValue = "'" + contentElement.InnerText.Replace("'", "''") + "'";
                }
                state.AddOutputContent(outValue, Interfaces.SqlHtmlConstants.CLASS_STRING);
                state.WordSeparatorExpected = true;
                break;

            case SqlXmlConstants.ENAME_BRACKET_QUOTED_NAME:
                WhiteSpace_SeparateWords(state);
                state.AddOutputContent("[" + contentElement.InnerText.Replace("]", "]]") + "]");
                state.WordSeparatorExpected = true;
                break;

            case SqlXmlConstants.ENAME_QUOTED_STRING:
                WhiteSpace_SeparateWords(state);
                state.AddOutputContent("\"" + contentElement.InnerText.Replace("\"", "\"\"") + "\"");
                state.WordSeparatorExpected = true;
                break;

            case SqlXmlConstants.ENAME_COMMA:
                //comma always ignores requested word spacing
                if (TrailingCommas)
                {
                    state.AddOutputContent(FormatOperator(","), Interfaces.SqlHtmlConstants.CLASS_OPERATOR);

                    if (ExpandCommaLists &&
                        !(contentElement.ParentNode.Name.Equals(SqlXmlConstants.ENAME_DDLDETAIL_PARENS) ||
                          contentElement.ParentNode.Name.Equals(SqlXmlConstants.ENAME_FUNCTION_PARENS)
                          )
                        )
                    {
                        state.BreakExpected = true;
                    }
                    else
                    {
                        state.WordSeparatorExpected = true;
                    }
                }
                else
                {
                    if (ExpandCommaLists &&
                        !(contentElement.ParentNode.Name.Equals(SqlXmlConstants.ENAME_DDLDETAIL_PARENS) ||
                          contentElement.ParentNode.Name.Equals(SqlXmlConstants.ENAME_FUNCTION_PARENS)
                          )
                        )
                    {
                        state.WhiteSpace_BreakToNextLine();
                        state.AddOutputContent(FormatOperator(","), Interfaces.SqlHtmlConstants.CLASS_OPERATOR);
                        if (SpaceAfterExpandedComma)
                        {
                            state.WordSeparatorExpected = true;
                        }
                    }
                    else
                    {
                        WhiteSpace_BreakAsExpected(state);
                        state.AddOutputContent(FormatOperator(","), Interfaces.SqlHtmlConstants.CLASS_OPERATOR);
                        state.WordSeparatorExpected = true;
                    }
                }
                break;

            case SqlXmlConstants.ENAME_PERIOD:
            case SqlXmlConstants.ENAME_SEMICOLON:
            case SqlXmlConstants.ENAME_SCOPERESOLUTIONOPERATOR:
                //always ignores requested word spacing, and doesn't request a following space either.
                state.WordSeparatorExpected = false;
                WhiteSpace_BreakAsExpected(state);
                state.AddOutputContent(FormatOperator(contentElement.InnerText), Interfaces.SqlHtmlConstants.CLASS_OPERATOR);
                break;

            case SqlXmlConstants.ENAME_ASTERISK:
            case SqlXmlConstants.ENAME_OTHEROPERATOR:
                WhiteSpace_SeparateWords(state);
                state.AddOutputContent(FormatOperator(contentElement.InnerText), Interfaces.SqlHtmlConstants.CLASS_OPERATOR);
                state.WordSeparatorExpected = true;
                break;

            case SqlXmlConstants.ENAME_COMPOUNDKEYWORD:
                WhiteSpace_SeparateWords(state);
                state.SetRecentKeyword(contentElement.Attributes[SqlXmlConstants.ANAME_SIMPLETEXT].Value);
                state.AddOutputContent(FormatKeyword(contentElement.Attributes[SqlXmlConstants.ANAME_SIMPLETEXT].Value), Interfaces.SqlHtmlConstants.CLASS_KEYWORD);
                state.WordSeparatorExpected = true;
                ProcessSqlNodeList(contentElement.SelectNodes(SqlXmlConstants.ENAME_COMMENT_MULTILINE + " | " + SqlXmlConstants.ENAME_COMMENT_SINGLELINE), state.IncrementIndent());
                state.DecrementIndent();
                state.WordSeparatorExpected = true;
                break;

            case SqlXmlConstants.ENAME_OTHERKEYWORD:
            case SqlXmlConstants.ENAME_DATATYPE_KEYWORD:
                WhiteSpace_SeparateWords(state);
                state.SetRecentKeyword(contentElement.InnerText);
                state.AddOutputContent(FormatKeyword(contentElement.InnerText), Interfaces.SqlHtmlConstants.CLASS_KEYWORD);
                state.WordSeparatorExpected = true;
                break;

            case SqlXmlConstants.ENAME_PSEUDONAME:
                WhiteSpace_SeparateWords(state);
                state.AddOutputContent(FormatKeyword(contentElement.InnerText), Interfaces.SqlHtmlConstants.CLASS_KEYWORD);
                state.WordSeparatorExpected = true;
                break;

            case SqlXmlConstants.ENAME_FUNCTION_KEYWORD:
                WhiteSpace_SeparateWords(state);
                state.SetRecentKeyword(contentElement.InnerText);
                state.AddOutputContent(contentElement.InnerText, Interfaces.SqlHtmlConstants.CLASS_FUNCTION);
                state.WordSeparatorExpected = true;
                break;

            case SqlXmlConstants.ENAME_OTHERNODE:
            case SqlXmlConstants.ENAME_NUMBER_VALUE:
            case SqlXmlConstants.ENAME_MONETARY_VALUE:
            case SqlXmlConstants.ENAME_BINARY_VALUE:
            case SqlXmlConstants.ENAME_LABEL:
                WhiteSpace_SeparateWords(state);
                state.AddOutputContent(contentElement.InnerText);
                state.WordSeparatorExpected = true;
                break;

            case SqlXmlConstants.ENAME_WHITESPACE:
                //take note if it's a line-breaking space, but don't DO anything here
                if (Regex.IsMatch(contentElement.InnerText, @"(\r|\n)+"))
                {
                    state.SourceBreakPending = true;
                }
                break;

            default:
                throw new Exception("Unrecognized element in SQL Xml!");
            }

            if (initialIndent != state.IndentLevel)
            {
                throw new Exception("Messed up the indenting!! Check code/stack or panic!");
            }
        }