content: /*
   * Copyright 2013 Raffael Herzog
   *
   * This file is part of markdown-doclet.
   *
   * markdown-doclet is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * markdown-doclet is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with markdown-doclet.  If not, see <http://www.gnu.org/licenses/>.
   */
  package ch.raffael.mddoclet.integrations.idea;
  
  import java.util.List;
  
  import com.intellij.codeInsight.javadoc.JavaDocExternalFilter;
  import com.intellij.lang.ASTNode;
  import com.intellij.lang.java.JavaDocumentationProvider;
  import com.intellij.lang.java.JavaLanguage;
  import com.intellij.psi.JavaDirectoryService;
  import com.intellij.psi.PsiClass;
  import com.intellij.psi.PsiDirectory;
  import com.intellij.psi.PsiElement;
  import com.intellij.psi.PsiField;
  import com.intellij.psi.PsiFile;
  import com.intellij.psi.PsiManager;
  import com.intellij.psi.PsiMethod;
  import com.intellij.psi.PsiPackage;
  import com.intellij.psi.PsiParameter;
  import com.intellij.psi.impl.source.tree.JavaDocElementType;
  import org.jetbrains.annotations.Nullable;
  
  
  /**
   * A documentation provider that renders the JavaDoc comments using Markdown.
   *
   * @author <a href="mailto:herzog@raffael.ch">Raffael Herzog</a>
   */
  public class MarkdownDocumentationProvider extends JavaDocumentationProvider {
  
      private final Class[] SUPPORTED_ELEMENT_TYPES = {
              PsiPackage.class, PsiDirectory.class, PsiClass.class, // FIXME: PsiFile.class?
              PsiMethod.class, PsiField.class, PsiParameter.class
      };
  
      public MarkdownDocumentationProvider() {
      }
  
      @Nullable
      @Override
      public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
          // JavaDocumentationProvider will do the Right Thing
          return null;
      }
  
      @Nullable
      @Override
      public List<String> getUrlFor(PsiElement element, PsiElement originalElement) {
          // JavaDocumentationProvider will do the Right Thing
          return null;
      }
  
      @Nullable
      @Override
      public String generateDoc(PsiElement element, @Nullable PsiElement originalElement) {
          boolean process = false;
          for ( Class supported: SUPPORTED_ELEMENT_TYPES ) {
              if ( supported.isInstance(element) ) {
                  process = true;
                  break;
              }
          }
          if ( !process ) {
              return null;
          }
          PsiFile file = null;
          if ( element instanceof PsiDirectory ) {
              // let's see whether we can map the directory to a package; if so, change the
              // element to the package and continue
              PsiPackage pkg = JavaDirectoryService.getInstance().getPackage((PsiDirectory)element);
              if ( pkg != null ) {
                  element = pkg;
              }
              else {
                  return null;
              }
          }
          if ( element instanceof PsiPackage ) {
              for ( PsiDirectory dir : ((PsiPackage)element).getDirectories() ) {
                  PsiFile info = dir.findFile(PsiPackage.PACKAGE_INFO_FILE);
                  if ( info != null ) {
                      ASTNode node = info.getNode();
                      if ( node != null ) {
                          ASTNode docCommentNode = node.findChildByType(JavaDocElementType.DOC_COMMENT);
                          if ( docCommentNode != null ) {
                              // the default implementation will now use this file
                              // we're going to take over below, if Markdown is enabled in
                              // the corresponding module
                              // see JavaDocInfoGenerator.generatePackageJavaDoc()
                              file = info;
                              break;
                          }
                      }
                  }
                  if ( dir.findFile("package.html") != null ) {
                      // leave that to the default
                      return null;
                  }
              }
          }
          else {
              if ( JavaLanguage.INSTANCE.equals(element.getLanguage()) ) {
                  element = element.getNavigationElement();
                  if ( element.getContainingFile() != null ) {
                      file = element.getContainingFile();
                  }
              }
          }
          if ( file != null ) {
              DocCommentProcessor processor = new DocCommentProcessor(file);
              if ( processor.isEnabled() ) {
                  String docHtml;
                  if ( element instanceof PsiMethod ) {
                      docHtml = super.generateDoc(PsiProxy.forMethod((PsiMethod)element), originalElement);
                  }
                  else if ( element instanceof PsiParameter ) {
                      docHtml = super.generateDoc(PsiProxy.forParameter((PsiParameter)element), originalElement);
                  }
                  else {
                      MarkdownJavaDocInfoGenerator javaDocInfoGenerator = new MarkdownJavaDocInfoGenerator(element.getProject(), element, processor);
                      List<String> docURLs = getExternalJavaDocUrl(element);
                      String text = javaDocInfoGenerator.generateDocInfo(docURLs);
                      Plugin.print("Intermediate HTML output", text);
                      docHtml = JavaDocExternalFilter.filterInternalDocInfo(text);
                  }
                  docHtml = extendCss(docHtml);
                  Plugin.print("Final HTML output", docHtml);
                  return docHtml;
              }
              else {
                  return null;
              }
          }
          else {
              return null;
          }
      }
  
      @Nullable
      @Override
      public PsiElement getDocumentationElementForLookupItem(PsiManager psiManager, Object object, PsiElement element) {
          // nothing to do here
          return null;
      }
  
      @Nullable
      @Override
      public PsiElement getDocumentationElementForLink(PsiManager psiManager, String link, PsiElement context) {
          // JavaDocumentationProvider will do the Right Thing
          return null;
      }
  
      private static String extendCss(String html) {
          String css = "\n"
                  // I know, these tables aren't beautiful; however, Swing CSS is so
                  // limited, this is about as good as it gets ...
                  +"table { /*unsupported: border-collapse: collapse;*/ border: 0; border-spacing: 0; }\n"
                  +"table td, table th { border: outset 1px black; padding-left: 5px; padding-right: 5px;}\n"
                  +"\n";
          String upperHtml = html.toUpperCase();
          int bodyPos = upperHtml.indexOf("<BODY>");
          if ( bodyPos < 0 ) {
              return html;
          }
          int stylePos = upperHtml.lastIndexOf("</STYLE>", bodyPos);
          if ( stylePos < 0 ) {
              return html;
          }
          return html.substring(0, stylePos) + css + html.substring(stylePos);
      }
  
  }
  