/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.formatting.templateLanguages;

import com.intellij.formatting.*;
import static com.intellij.formatting.templateLanguages.BlockUtil.buildChildWrappers;
import static com.intellij.formatting.templateLanguages.BlockUtil.filterBlocksByRange;
import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageFormatting;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.DocumentBasedFormattingModel;
import com.intellij.psi.formatter.common.AbstractBlock;
import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider;
import org.jetbrains.annotations.NotNull;

import java.util.Collections;
import java.util.List;

/**
 * @author Alexey Chmutov
 *         Date: Jun 26, 2009
 *         Time: 4:07:09 PM
 */
public abstract class TemplateLanguageFormattingModelBuilder implements DelegatingFormattingModelBuilder, TemplateLanguageBlockFactory {

  @NotNull
  public FormattingModel createModel(PsiElement element, CodeStyleSettings settings) {
    final PsiFile file = element.getContainingFile();
    Block rootBlock = getRootBlock(file, file.getViewProvider(), settings);
    return new DocumentBasedFormattingModel(rootBlock, element.getProject(), settings, file.getFileType(), file);
  }

  private Block getRootBlock(PsiElement element, FileViewProvider viewProvider, CodeStyleSettings settings) {
    ASTNode node = element.getNode();
    if (node == null) {
      return createDummyBlock(node);
    }
    final Language dataLanguage = ((TemplateLanguageFileViewProvider)viewProvider).getTemplateDataLanguage();
    final FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forLanguage(dataLanguage);
    if (builder instanceof DelegatingFormattingModelBuilder && ((DelegatingFormattingModelBuilder)builder).dontFormatMyModel()) {
      return createDummyBlock(node);
    }
    if (builder == null) {
      return createTemplateLanguageBlock(node,  Wrap.createWrap(WrapType.NONE, false), null, Collections.<DataLanguageBlockWrapper>emptyList(), settings);
    }
    final FormattingModel model = builder.createModel(viewProvider.getPsi(dataLanguage), settings);
    List<DataLanguageBlockWrapper> childWrappers = buildChildWrappers(model.getRootBlock());
    if (childWrappers.size() == 1) {
      childWrappers = buildChildWrappers(childWrappers.get(0).getOriginal());
    }
    return createTemplateLanguageBlock(node,  Wrap.createWrap(WrapType.NONE, false), null, filterBlocksByRange(childWrappers, node.getTextRange()), settings);
  }

  protected AbstractBlock createDummyBlock(final ASTNode node) {
    return new AbstractBlock(node, Wrap.createWrap(WrapType.NONE, false), Alignment.createAlignment()) {
      protected List<Block> buildChildren() {
        return Collections.emptyList();
      }

      public Spacing getSpacing(final Block child1, final Block child2) {
        return Spacing.getReadOnlySpacing();
      }

      public boolean isLeaf() {
        return true;
      }
    };
  }

  public TextRange getRangeAffectingIndent(PsiFile file, int offset, ASTNode elementAtOffset) {
    return null;
  }

  public boolean dontFormatMyModel() {
    return true;
  }
}

@@ -2252,32 +2252,102 @@
 ck(node);%0A    %7D%0A
+    if (viewProvider instanceof TemplateLanguageFileViewProvider) %7B%0A  
     final Langua
@@ -2440,24 +2440,26 @@
 uage();%0A    
+  
 final Format
@@ -2536,24 +2536,26 @@
 aLanguage);%0A
+  
     if (buil
@@ -2670,32 +2670,34 @@
 odel()) %7B%0A      
+  
 return createDum
@@ -2707,34 +2707,38 @@
 lock(node);%0A    
-%7D%0A
+  %7D%0A  
     if (builder 
@@ -2737,17 +2737,17 @@
 builder 
-=
+!
 = null) 
@@ -2756,165 +2756,8 @@
     
-  return createTemplateLanguageBlock(node,  Wrap.createWrap(WrapType.NONE, false), null, Collections.%3CDataLanguageBlockWrapper%3EemptyList(), settings);%0A    %7D%0A
     
@@ -2848,24 +2848,28 @@
  settings);%0A
+    
     List%3CDat
@@ -2945,24 +2945,28 @@
 otBlock());%0A
+    
     if (chil
@@ -2996,16 +2996,20 @@
 %7B%0A      
+   
+ 
 childWra
@@ -3076,22 +3076,30 @@
 ));%0A    
-%7D%0A
+    %7D%0A   
     
+ 
 return c
@@ -3130,17 +3130,16 @@
 ck(node,
- 
  Wrap.cr
@@ -3175,16 +3175,59 @@
 ), null,
+%0A                                          
  filterB
@@ -3287,16 +3287,183 @@
 tings);%0A
+      %7D%0A    %7D%0A    return createTemplateLanguageBlock(node,  Wrap.createWrap(WrapType.NONE, false), null, Collections.%3CDataLanguageBlockWrapper%3EemptyList(), settings);%0A
   %7D%0A%0A  p

Fix for EA-30598, EA-29115