/*
 * Copyright 2000-2015 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.execution.filters;

import com.intellij.ide.IdeBundle;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.io.URLUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author yole
 */
public class UrlFilter implements Filter, DumbAware {
  private static final String FILE_URL_PROTOCOL = "file://";
  private final Project myProject;

  public UrlFilter() {
    this(null);
  }

  public UrlFilter(Project project) {
    myProject = project;
  }

  @Nullable
  @Override
  public Result applyFilter(@NotNull String line, int entireLength) {
    if (!URLUtil.canContainUrl(line)) return null;

    int textStartOffset = entireLength - line.length();
    Pattern pattern = line.contains(URLUtil.FILE_PROTOCOL + URLUtil.SCHEME_SEPARATOR) ? URLUtil.FILE_URL_PATTERN : URLUtil.URL_PATTERN;
    Matcher m = pattern.matcher(line);
    ResultItem item = null;
    List<ResultItem> items = null;
    while (m.find()) {
      if (item == null) {
        item = new ResultItem(textStartOffset + m.start(), textStartOffset + m.end(), buildHyperlinkInfo(m.group()));
      } else {
        if (items == null) {
          items = new ArrayList<>(2);
          items.add(item);
        }
        items.add(new ResultItem(textStartOffset + m.start(), textStartOffset + m.end(), buildHyperlinkInfo(m.group())));
      }
    }
    return items != null ? new Result(items)
                         : item != null ? new Result(item.getHighlightStartOffset(), item.getHighlightEndOffset(), item.getHyperlinkInfo())
                                        : null;
  }

  @NotNull
  protected HyperlinkInfo buildHyperlinkInfo(@NotNull String url) {
    HyperlinkInfo fileHyperlinkInfo = buildFileHyperlinkInfo(url);
    return fileHyperlinkInfo != null ? fileHyperlinkInfo : new BrowserHyperlinkInfo(url);
  }

  @Nullable
  private HyperlinkInfo buildFileHyperlinkInfo(@NotNull String url) {
    if (myProject != null && url.startsWith(FILE_URL_PROTOCOL)) {
      return new LazyFileHyperlinkInfo(myProject, StringUtil.trimStart(url, FILE_URL_PROTOCOL), 0, 0) {
        @Nullable
        @Override
        public OpenFileDescriptor getDescriptor() {
          OpenFileDescriptor descriptor = super.getDescriptor();
          if (descriptor == null) {
            Messages.showErrorDialog(myProject, "Cannot find file " + StringUtil.trimMiddle(url, 150),
                                     IdeBundle.message("title.cannot.open.file"));
          }
          return descriptor;
        }
      };
    }
    return null;
  }

  public static class UrlFilterProvider implements ConsoleFilterProviderEx {
    @NotNull
    @Override
    public Filter[] getDefaultFilters(@NotNull Project project, @NotNull GlobalSearchScope scope) {
      return new Filter[]{new UrlFilter(project)};
    }

    @NotNull
    @Override
    public Filter[] getDefaultFilters(@NotNull Project project) {
      return getDefaultFilters(project, GlobalSearchScope.allScope(project));
    }
  }
}

@@ -908,24 +908,73 @@
 StringUtil;%0A
+import com.intellij.openapi.vfs.LocalFileSystem;%0A
 import com.i
@@ -1011,16 +1011,16 @@
 hScope;%0A
-
 import c
@@ -1332,69 +1332,8 @@
 e %7B%0A
-  private static final String FILE_URL_PROTOCOL = %22file://%22;%0A
   pr
@@ -1718,56 +1718,39 @@
 ins(
-URLUtil.FILE_PROTOCOL + URLUtil.SCHEME_SEPARATOR
+LocalFileSystem.PROTOCOL_PREFIX
 ) ? 
@@ -2926,33 +2926,40 @@
 rtsWith(
-FILE_URL_
+LocalFileSystem.
 PROTOCOL
 )) %7B%0A   
@@ -2950,16 +2950,23 @@
 PROTOCOL
+_PREFIX
 )) %7B%0A   
@@ -2972,102 +2972,1172 @@
     
-return new LazyFileHyperlinkInfo(myProject, StringUtil.trimStart(url, FILE_URL_PROTOCOL), 0, 0
+int documentLine = 0, documentColumn = 0;%0A      int filePathEndIndex = url.length();%0A      final int lastColonInd = url.lastIndexOf(':');%0A      if (lastColonInd %3E LocalFileSystem.PROTOCOL_PREFIX.length() && lastColonInd %3C url.length() - 1) %7B%0A        int lastValue = StringUtil.parseInt(url.substring(lastColonInd + 1), Integer.MIN_VALUE);%0A        if (lastValue != Integer.MIN_VALUE) %7B%0A          documentLine = lastValue - 1;%0A          filePathEndIndex = lastColonInd;%0A          int preLastColonInd = url.lastIndexOf(':', lastColonInd - 1);%0A          if (preLastColonInd %3E LocalFileSystem.PROTOCOL_PREFIX.length()) %7B%0A            int preLastValue = StringUtil.parseInt(url.substring(preLastColonInd + 1, lastColonInd), Integer.MIN_VALUE);%0A            if (preLastValue != Integer.MIN_VALUE) %7B%0A              documentLine = preLastValue - 1;%0A              documentColumn = lastValue - 1;%0A              filePathEndIndex = preLastColonInd;%0A            %7D%0A          %7D%0A        %7D%0A      %7D%0A      String filePath = url.substring(LocalFileSystem.PROTOCOL_PREFIX.length(), filePathEndIndex);%0A      return new LazyFileHyperlinkInfo(myProject, filePath, documentLine, documentColumn
 ) %7B%0A

support file:// links with :line:column at the end (WEB-35908)