# RTEMS Tools Project (http://www.rtems.org/)
# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
# All rights reserved.
#
# This file is part of the RTEMS Tools package in 'rtems-tools'.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#

#
# RTEMS Classic API Support
#

import gdb
import itertools
import re
#ToDo This shouldn't be here
import helper

import heaps
import mutex
import objects
import supercore
import threads
import watchdog


class attribute:
    """The Classic API attribute."""

    groups = {
        'none': [],
        'all': [
            'scope', 'priority', 'fpu', 'semaphore-type', 'semaphore-pri',
            'semaphore-pri-ceiling', 'barrier', 'task'
        ],
        'task': ['scope', 'priority', 'fpu', 'task'],
        'semaphore': [
            'scope', 'priority', 'semaphore-type', 'semaphore-pri',
            'semaphore-pri-ceiling'
        ],
        'barrier': ['barrier'],
        'message_queue': ['priority', 'scope'],
        'partition': ['scope'],
        'region': ['priority']
    }

    masks = {
        'scope': 0x00000002,
        'priority': 0x00000004,
        'fpu': 0x00000001,
        'semaphore-type': 0x00000030,
        'semaphore-pri': 0x00000040,
        'semaphore-pri-ceiling': 0x00000080,
        'barrier': 0x00000010,
        'task': 0x00008000
    }

    fields = {
        'scope': [(0x00000000, 'local'), (0x00000002, 'global')],
        'priority': [(0x00000000, 'fifo'), (0x00000004, 'pri')],
        'fpu': [(0x00000000, 'no-fpu'), (0x00000001, 'fpu')],
        'semaphore-type': [(0x00000000, 'count-sema'),
                           (0x00000010, 'bin-sema'),
                           (0x00000020, 'simple-bin-sema')],
        'semaphore-pri': [(0x00000000, 'no-inherit-pri'),
                          (0x00000040, 'inherit-pri')],
        'semaphore-pri-ceiling': [(0x00000000, 'no-pri-ceiling'),
                                  (0x00000080, 'pri-ceiling')],
        'barrier': [(0x00000010, 'barrier-auto-release'),
                    (0x00000000, 'barrier-manual-release')],
        'task': [(0x00000000, 'app-task'), (0x00008000, 'sys-task')]
    }

    def __init__(self, attr, attrtype='none'):
        if attrtype not in self.groups:
            raise 'invalid attribute type'
        self.attrtype = attrtype
        self.attr = attr

    #ToDo: Move this out
    def to_string(self):
        s = '(0x%08x) ' % (self.attr)
        if self.attrtype != 'none':
            for m in self.groups[self.attrtype]:
                v = self.attr & self.masks[m]
                for f in self.fields[m]:
                    if f[0] == v:
                        s += f[1] + ','
                        break
        return s[:-1]

    def test(self, mask, value):
        if self.attrtype != 'none' and \
                mask in self.groups[self.attrtype]:
            v = self.masks[mask] & self.attr
            for f in self.fields[mask]:
                if v == f[0] and value == f[1]:
                    return True
        return False


class semaphore:
    "Print a classic semaphore."

    def __init__(self, obj):
        if obj.type.code == gdb.TYPE_CODE_PTR:
            self.reference = obj
            self.object = obj.dereference()
        else:
            self.object = obj
            self.reference = obj.address
        self.object_control = objects.control(self.object['Object'])
        self.attr = attribute(self.object['attribute_set'], 'semaphore')

    def show(self, from_tty):
        if self.object_control.id() != 0:
            print('     Name:', self.object_control.name())
            print('       Id: 0x%08x (@ 0x%08x)' %
                  (self.object_control.id(), self.reference))
            print('     Attr:', self.attr.to_string())
            if self.attr.test('semaphore-type', 'bin-sema') or \
               self.attr.test('semaphore-type', 'simple-bin-sema'):
                core_mutex = mutex.control(
                    self.object['Core_control']['mutex'])
                print('  Nesting:', core_mutex.nest_count())
                print('   Holder:', )
                holder = core_mutex.holder()
                if holder:
                    print('%s (id 0x%08x)' % (holder.brief(), holder.id()))
                else:
                    print('no holder (unlocked)')
                wait_queue = core_mutex.wait_queue()
                tasks = wait_queue.tasks()
                print('    Queue: len = %d, state = %s' %
                      (len(tasks), wait_queue.state()))
                if len(tasks) > 0:
                    print('    Tasks:')
                    print('    Name (c:current, r:real), (id)')
                    for t in range(0, len(tasks)):
                        print('      ', tasks[t].brief(),
                              ' (%08x)' % (tasks[t].id()))
                return True
        return False


class task:
    "Print a classic task"

    def __init__(self, obj):
        self.reference = obj
        self.object = obj.dereference()
        self.task = threads.control(self.reference)
        self.wait_info = self.task.wait_info()
        self.regs = self.task.registers()
        #self.regs = sparc.register(self.object['Registers'])

    def show(self, from_tty):
        if self.task.id() != 0:
            cpu = self.task.executing()
            if cpu == -1:
                cpu = 'not executing'
            print('         Id:',
                  '0x%08x (@ 0x%08x)' % (self.task.id(), self.task.reference))
            print('       Name:', self.task.name())
            print(' Active CPU:', cpu)
            print('      State:', self.task.current_state())
            print('    Current:', self.task.current_priority())
            print('       Real:', self.task.real_priority())
            print('    Preempt:', self.task.preemptible())
            print('   T Budget:', self.task.cpu_time_budget())
            print('       Time:', self.task.cpu_time_used())
            print('  Resources:', self.task.resource_count())
            print('  Regsters:')
            for name in self.regs.names():
                val = self.regs.get(name)
                print('    %20s: %08x (%d)' % (name, val, val))
            return True
        return False


class message_queue:
    "Print classic messege queue"

    def __init__(self, obj):
        self.reference = obj
        self.object = obj.dereference()
        self.object_control = objects.control(self.object['Object'])
        self.attr = attribute(self.object['attribute_set'], \
            'message_queue')
        self.wait_queue = threads.queue( \
            self.object['message_queue']['Wait_queue'])

        self.core_control = supercore.message_queue(
            self.object['message_queue'])

    def show(self, from_tty):
        print('     Name:', self.object_control.name())
        print('     Attr:', self.attr.to_string())

        self.core_control.show()


class timer:
    '''Print a classic timer'''

    def __init__(self, obj):
        self.reference = obj
        self.object = obj.dereference()
        self.object_control = objects.control(self.object['Object'])
        self.watchdog = watchdog.control(self.object['Ticker'])

    def show(self, from_tty):
        print('     Name:', self.object_control.name())
        self.watchdog.show()


class partition:
    ''' Print a rtems partition '''

    def __init__(self, obj):
        self.reference = obj
        self.object = obj.dereference()
        self.object_control = objects.control(self.object['Object'])
        self.attr = attribute(self.object['attribute_set'], 'partition')
        self.starting_addr = self.object['starting_address']
        self.length = self.object['length']
        self.buffer_size = self.object['buffer_size']
        self.used_blocks = self.object['number_of_used_blocks']

    def show(self, from_tty):
        # ToDo: the printing still somewhat crude.
        print('     Name:', self.object_control.name())
        print('     Attr:', self.attr.to_string())
        print('   Length:', self.length)
        print('   B Size:', self.buffer_size)
        print(' U Blocks:', self.used_blocks)


class region:
    "prints a classic region"

    def __init__(self, obj):
        self.reference = obj
        self.object = obj.dereference()
        self.object_control = objects.control(self.object['Object'])
        self.attr = attribute(self.object['attribute_set'], 'region')
        self.wait_queue = threads.queue(self.object['Wait_queue'])
        self.heap = heaps.control(self.object['Memory'])

    def show(self, from_tty):
        print('     Name:', self.object_control.name())
        print('     Attr:', self.attr.to_string())
        helper.tasks_printer_routine(self.wait_queue)
        print('   Memory:')
        self.heap.show()


class barrier:
    '''classic barrier abstraction'''

    def __init__(self, obj):
        self.reference = obj
        self.object = obj.dereference()
        self.object_control = objects.control(self.object['Object'])
        self.attr = attribute(self.object['attribute_set'], 'barrier')
        self.core_b_control = supercore.barrier_control(self.object['Barrier'])

    def show(self, from_tty):
        print('     Name:', self.object_control.name())
        print('     Attr:', self.attr.to_string())

        if self.attr.test('barrier', 'barrier-auto-release'):
            max_count = self.core_b_control.max_count()
            print('Aut Count:', max_count)

        print('  Waiting:', self.core_b_control.waiting_threads())
        helper.tasks_printer_routine(self.core_b_control.tasks())
