# Copyright 2009-2014 Ram Rachum.
# This program is distributed under the MIT license.

from __future__ import with_statement

import os.path, sys
sys.path += [
    os.path.dirname(__file__),
    os.path.join(os.path.dirname(__file__), 'third_party.zip'),
]


import wingapi

import shared


def _normalize_path(path):
    ''' '''
    if not sys.platform.startswith('win'):
        return os.path.realpath(path)
    else:
        return os.path.realpath(path).lower()


def go_up_to_project_frame(application=wingapi.gApplication):
    '''
    Go up one frame in the debugger, skipping any non-project frames.

    Did you ever have Wing stop on an exception, and then drop you in code that
    belongs to an external module? This is often annoying, because you want to
    figure out what you did wrong on *your* code, and the external module is
    usually not to blame.

    `go-up-to-project-frame` to the rescue! Invoke this script while debugging
    in order to be taken to the closest higher stack frame that's on a project
    file rather than an external module.

    Suggested key combination: `Alt-F11`
    '''
    project = application.GetProject()
    debugger = application.GetDebugger()
    all_project_files = set(map(_normalize_path, project.GetAllFiles()))
    _current_run_state = debugger.GetCurrentRunState()
    _thread_id, _frame_index = _current_run_state.GetStackFrame()
    _stack = _current_run_state.GetStack()

    if not _stack:
        return

    file_paths = [_normalize_path(file_path) for file_path, _, _, _, _ in
                  _stack]
    file_paths_in_project_above_current_frame = filter(
        lambda i_and_file_path: i_and_file_path[1] in all_project_files and
                                            i_and_file_path[0] < _frame_index,
        enumerate(file_paths)
    )
    if not file_paths_in_project_above_current_frame:
        return
    index_of_last_file_path_in_project = \
                               file_paths_in_project_above_current_frame[-1][0]

    _current_run_state.SetStackFrame(_thread_id,
                                     index_of_last_file_path_in_project)


def go_down_to_project_frame(application=wingapi.gApplication):
    '''
    Go down one frame in the debugger, skipping any non-project frames.

    Did you ever have Wing stop on an exception, and then drop you in code that
    belongs to an external module? This is often annoying, because you want to
    figure out what you did wrong on *your* code, and the external module is
    usually not to blame.

    `go-down-to-project-frame` to the rescue! Invoke this script while
    debugging in order to be taken to the closest lower stack frame that's on a
    project file rather than an external module.

    Suggested key combination: `Alt-F12`
    '''
    project = application.GetProject()
    debugger = application.GetDebugger()
    all_project_files = set(map(_normalize_path, project.GetAllFiles()))
    _current_run_state = debugger.GetCurrentRunState()
    _thread_id, _frame_index = _current_run_state.GetStackFrame()
    _stack = _current_run_state.GetStack()

    if not _stack:
        return

    file_paths = [_normalize_path(file_path) for file_path, _, _, _, _ in
                  _stack]
    file_paths_in_project_below_current_frame = filter(
        lambda i_and_file_path: i_and_file_path[1] in all_project_files and
                                            i_and_file_path[0] > _frame_index,
        enumerate(file_paths)
    )
    if not file_paths_in_project_below_current_frame:
        return
    index_of_last_file_path_in_project = \
                               file_paths_in_project_below_current_frame[0][0]

    _current_run_state.SetStackFrame(_thread_id,
                                     index_of_last_file_path_in_project)


def _available(application=wingapi.gApplication):
    ''' '''
    debugger_run_state = \
                        wingapi.gApplication.GetDebugger().GetCurrentRunState()
    return bool(debugger_run_state and debugger_run_state.GetStack())

go_up_to_project_frame.available = _available
go_down_to_project_frame.available = _available


@@ -1331,32 +1331,36 @@
 %0A    _thread_id,
+ (_,
  _frame_index = 
@@ -1348,32 +1348,33 @@
 (_, _frame_index
+)
  = _current_run_
@@ -1379,37 +1379,37 @@
 n_state.GetStack
-Frame
+Index
 ()%0A    _stack = 
@@ -1430,33 +1430,32 @@
 tate.GetStack()%0A
-%0A
     if not _stac
@@ -1612,32 +1612,47 @@
 _current_frame =
+ tuple(%0A       
  filter(%0A       
@@ -1636,32 +1636,36 @@
         filter(%0A
+    
         lambda i
@@ -1760,32 +1760,54 @@
                 
+         
+             
 i_and_file_path%5B
@@ -1825,32 +1825,36 @@
 _index,%0A        
+ 
+   
 enumerate(file_p
@@ -1851,32 +1851,42 @@
 ate(file_paths)%0A
+        )%0A
     )%0A    if not
@@ -2091,37 +2091,37 @@
 n_state.SetStack
-Frame
+Index
 (_thread_id,%0A   
@@ -3073,16 +3073,20 @@
 read_id,
+ (_,
  _frame_
@@ -3090,16 +3090,17 @@
 me_index
+)
  = _curr
@@ -3121,21 +3121,21 @@
 GetStack
-Frame
+Index
 ()%0A    _
@@ -3355,16 +3355,31 @@
 _frame =
+ tuple(%0A       
  filter(
@@ -3371,32 +3371,36 @@
         filter(%0A
+    
         lambda i
@@ -3495,32 +3495,54 @@
                 
+         
+             
 i_and_file_path%5B
@@ -3560,32 +3560,36 @@
 _index,%0A        
+ 
+   
 enumerate(file_p
@@ -3590,24 +3590,34 @@
 file_paths)%0A
+        )%0A
     )%0A    if
@@ -3837,13 +3837,13 @@
 tack
-Frame
+Index
 (_th

Replace deprecated GetStackFrame with GetStackIndex (setters as well)