/*
 * Copyright 2000-2014 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.jetbrains.python.debugger;

import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.xdebugger.XDebuggerUtil;
import com.intellij.xdebugger.XSourcePosition;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;


public class PyLocalPositionConverter implements PyPositionConverter {
  private final static String[] EGG_EXTENSIONS = new String[] {".egg", ".zip"};

  protected static class PyLocalSourcePosition extends PySourcePosition {
    public PyLocalSourcePosition(final String file, final int line) {
      super(file, line);
    }

    @Override
    protected String normalize(@Nullable String file) {
      if (file == null) {
        return null;
      }
      if (SystemInfo.isWindows) {
        file = file.toLowerCase();
      }
      return super.normalize(file);
    }
  }

  protected static class PyRemoteSourcePosition extends PySourcePosition {
    public PyRemoteSourcePosition(final String file, final int line) {
      super(file, line);
    }

    @Override
    protected String normalize(@Nullable String file) {
      if (file == null) {
        return null;
      }
      if (SystemInfo.isWindows && isWindowsPath(file)) {
        file = file.toLowerCase();
      }
      return super.normalize(file);
    }
  }

  @NotNull
  final public PySourcePosition create(@NotNull final String filePath, final int line) {
    File file = new File(filePath);

    if (file.exists()) {
      return new PyLocalSourcePosition(file.getPath(), line);
    }
    else {
      return new PyRemoteSourcePosition(filePath, line);
    }
  }

  @NotNull
  public final PySourcePosition convertToPython(@NotNull final XSourcePosition position) {
    return convertToPython(convertFilePath(position.getFile().getPath()), convertLocalLineToRemote(position.getFile(), position.getLine()));
  }

  @NotNull
  protected PySourcePosition convertToPython(String filePath, int line) {
    return new PyLocalSourcePosition(filePath, line);
  }

  protected static int convertLocalLineToRemote(VirtualFile file, int line) {
    final Document document = FileDocumentManager.getInstance().getDocument(file);
    if (document != null) {
      while (PyDebugSupportUtils.isContinuationLine(document, line)) {
        line++;
      }
    }
    return line + 1;
  }

  @Nullable
  public XSourcePosition convertFromPython(@NotNull final PySourcePosition position) {
    return createXSourcePosition(getVirtualFile(position.getFile()), position.getLine());
  }

  @Override
  public PySignature convertSignature(PySignature signature) {
    return signature;
  }

  public VirtualFile getVirtualFile(String path) {
    VirtualFile vFile = getLocalFileSystem().findFileByPath(path);

    if (vFile == null) {
      vFile = findEggEntry(path);
    }
    return vFile;
  }

  protected VirtualFileSystem getLocalFileSystem() {
    return LocalFileSystem.getInstance();
  }

  private VirtualFile findEggEntry(String file) {
    int ind = -1;
    for (String ext: EGG_EXTENSIONS) {
      ind = file.indexOf(ext);
      if (ind != -1) break;
    }
    if (ind != -1) {
      String jarPath = file.substring(0, ind + 4);
      VirtualFile jarFile = getLocalFileSystem().findFileByPath(jarPath);
      if (jarFile != null) {
        String innerPath = file.substring(ind + 4);
        final VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(jarFile);
        if (jarRoot != null) {
          return jarRoot.findFileByRelativePath(innerPath);
        }
      }
    }
    return null;
  }

  private static String convertFilePath(String file) {
    int ind = -1;
    for (String ext: EGG_EXTENSIONS) {
      ind = file.indexOf(ext + "!");
      if (ind != -1) break;
    }
    if (ind != -1) {
      return file.substring(0, ind + 4) + file.substring(ind + 5);
    }
    else {
      return file;
    }
  }

  @Nullable
  protected static XSourcePosition createXSourcePosition(@Nullable VirtualFile vFile, int line) {
    if (vFile != null) {
      return XDebuggerUtil.getInstance().createPosition(vFile, convertRemoteLineToLocal(vFile, line));
    }
    else {
      return null;
    }
  }

  private static int convertRemoteLineToLocal(VirtualFile vFile, int line) {
    final Document document = FileDocumentManager.getInstance().getDocument(vFile);
    line--;
    if (document != null) {
      while (PyDebugSupportUtils.isContinuationLine(document, line - 1)) {
        line--;
      }
    }
    return line;
  }
}

@@ -634,16 +634,76 @@
 ugger;%0A%0A
+import com.intellij.openapi.application.ApplicationManager;%0A
 import c
@@ -791,32 +791,77 @@
 ocumentManager;%0A
+import com.intellij.openapi.util.Computable;%0A
 import com.intel
@@ -5211,16 +5211,22 @@
 ToLocal(
+final 
 VirtualF
@@ -5269,32 +5269,176 @@
 ument document =
+ ApplicationManager.getApplication().runReadAction(new Computable%3CDocument%3E() %7B%0A      @Override%0A      public Document compute() %7B%0A        return
  FileDocumentMan
@@ -5472,24 +5472,41 @@
 ent(vFile);%0A
+      %7D%0A    %7D);%0A%0A
     line--;%0A

Fix tests: getDocument should be under readAction