/*
 * Copyright 2014 Guidewire Software, Inc.
 */

package com.guidewire.editor.devtools;

import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiFile;
import gw.lang.parser.IParseIssue;
import gw.lang.parser.exceptions.ParseResultsException;
import gw.lang.reflect.TypeSystem;
import gw.plugin.ij.actions.TypeSystemAwareAction;
import gw.plugin.ij.lang.psi.impl.AbstractGosuClassFileImpl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MarkErrorsForGosuLanguageTestAction extends TypeSystemAwareAction {

  @Override
  public void actionPerformed( AnActionEvent event ) {
    PsiFile psiFile = LangDataKeys.PSI_FILE.getData( event.getDataContext() );
    if( psiFile instanceof AbstractGosuClassFileImpl ) {
      TypeSystem.pushModule( ((AbstractGosuClassFileImpl)psiFile).getModule() );
      try {
        final AbstractGosuClassFileImpl gsFile = (AbstractGosuClassFileImpl)psiFile;
        ParseResultsException pre = gsFile.getParseData().getClassFileStatement().getGosuClass().getParseResultsException();
        if( pre == null || (!pre.hasParseExceptions() && !pre.hasParseWarnings()) ) {
          return;
        }

        if( !CodeInsightUtilBase.prepareFileForWrite( gsFile ) ) {
          return;
        }

        final Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
        for( IParseIssue pi: pre.getParseIssues() ) {
          String issue = pi.getMessageKey().getKey();
          int iLine = pi.getLine();
          List<String> issues = map.get( iLine );
          if( issues == null ) {
            map.put( iLine, issues = new ArrayList<String>() );
          }
          issues.add( issue );
        }
        final List<Integer> lines = new ArrayList<Integer>( map.keySet() );
        Collections.sort( lines );

        ApplicationManager.getApplication().runWriteAction( new Runnable() {
          @Override
          public void run() {
            Document document = gsFile.getViewProvider().getDocument();
            removeOldIssueKeyMarkers( document );
            addIssueKeyMarkers( document, lines, map );
            gsFile.reparsePsiFromContent();
          }
        } );
      }
      finally {
        TypeSystem.popModule( ((AbstractGosuClassFileImpl)psiFile).getModule() );
      }
    }
  }

  private void removeOldIssueKeyMarkers( Document document ) {
    for( int i = 0; i < document.getLineCount(); i++ ) {
      int iStart = document.getLineStartOffset( i );
      int iEnd = document.getLineEndOffset( i );
      String line = document.getText( new TextRange( iStart, iEnd ) );
      int iOffset = line.indexOf( "  //## issuekeys:" );
      if( iOffset >= 0 ) {
        document.replaceString( iStart + iOffset, iEnd, "" );
      }
    }
  }

  private void addIssueKeyMarkers( Document document, List<Integer> lines, Map<Integer, List<String>> map ) {
    for( int iLine : lines ) {
      String issues = makeIssueString( map.get( iLine ) );
      int iEnd = document.getLineEndOffset( iLine - 1 );
      document.insertString( iEnd, issues );
    }
  }

  private String makeIssueString( List<String> issues ) {
    StringBuilder sb = new StringBuilder();
    for( String issue: issues ) {
      sb.append( sb.length() != 0 ? ", " : "" ).append( issue );
    }
    sb.insert( 0, "  //## issuekeys: " );
    return sb.toString();
  }
}

@@ -517,24 +517,69 @@
 sException;%0A
+import gw.lang.parser.resources.ResourceKey;%0A
 import gw.la
@@ -1796,41 +1796,137 @@
     
-String issue = pi.getMessageKey()
+ResourceKey messageKey = pi.getMessageKey();%0A          if( messageKey != null )%0A          %7B%0A            String issue = messageKey
 .get
@@ -1938,24 +1938,26 @@
 ;%0A          
+  
 int iLine = 
@@ -1966,24 +1966,26 @@
 .getLine();%0A
+  
           Li
@@ -2028,24 +2028,26 @@
 ;%0A          
+  
 if( issues =
@@ -2053,24 +2053,26 @@
 == null ) %7B%0A
+  
             
@@ -2125,34 +2125,38 @@
 () );%0A          
-%7D%0A
+  %7D%0A  
           issues
@@ -2166,24 +2166,36 @@
 d( issue );%0A
+          %7D%0A
         %7D%0A  

Make null tolerant