# -*- coding: utf-8 -*-
#   Copyright (C) 2013 Rocky Bernstein <rocky@gnu.org>
#
#   This program 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.
#
#   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Call-frame-oriented helper function for Processor. Put here so we
# can use this in a couple of processors.

from import_relative import *
Mcmdfns = import_relative('cmdfns',   '.')
Mcomplete = import_relative('complete', '..lib')

def frame_low_high(proc_obj, direction):
    stack_size = len(proc_obj.stack) # - hide_level
    if direction is None:
        return [-stack_size, stack_size-1]
    else:
        frame_index = proc_obj.curindex
        low, high = [ frame_index * -direction,
                      (stack_size - frame_index - 1) * direction ]
        if direction < 0: low, high = [high, low]
        return (low, high)
    return

def frame_complete(proc_obj, prefix, direction):
    low, high = frame_low_high(proc_obj, direction)
    ary = [str(low+i) for i in range(high-low+1)]
    return Mcomplete.complete_token(ary, prefix)

def adjust_frame(proc_obj, name, pos, absolute_pos):
    """Adjust stack frame by pos positions. If absolute_pos then
    pos is an absolute number. Otherwise it is a relative number.

    A negative number indexes from the other end."""
    if not proc_obj.curframe:
        proc_obj.errmsg("No stack.")
        return

    # Below we remove any negativity. At the end, pos will be
    # the new value of proc_obj.curindex.
    if absolute_pos:
        if pos >= 0:
            pos = len(proc_obj.stack)-pos-1
        else:
            pos = -pos+1
            pass
    else:
        pos += proc_obj.curindex
        pass

    if pos < 0:
        proc_obj.errmsg("Adjusting would put us beyond the oldest frame.")
        return
    elif pos >= len(proc_obj.stack):
        proc_obj.errmsg("Adjusting would put us beyond the newest frame.")
        return

    proc_obj.curindex = pos
    proc_obj.curframe = proc_obj.stack[proc_obj.curindex][0]
    proc_obj.location()
    proc_obj.list_lineno = None
    return

def adjust_relative(proc_obj, name, args, signum):
    if not proc_obj.stack:
        proc_obj.errmsg("Program has no stack frame set.")
        return False
    if len(args) == 1:
        count = 1
    else:
        i_stack = len(proc_obj.stack)
        count_str = args[1]
        low, high = frame_low_high(proc_obj, signum)
        count = Mcmdfns.get_an_int( proc_obj.errmsg, count_str,
                                    ("The '%s' command argument must eval to an" +
                                     " integer. Got: %s") % (name, count_str),
                                    low, high )
        if count is None: return
        pass

    adjust_frame(proc_obj, name, pos=signum*count,
                 absolute_pos=False)
    return
