# -*- coding: utf-8 -*-
"""
    Implementation of Flash Programmer erase command

Copyright 2015 Freescale Semiconductor, Inc.
Copyright 2019, 2024-2025 NXP.

SPDX-License-Identifier: BSD-3-Clause

"""

import gdb   # @UnresolvedImport  # pylint: disable=F0401
import argparse
import string

from flash.gdbcommands.base_command import CwFlashBase
from flash.gdbcommands.cmd_name import CMD_CW_FLASH_ERASE_ALL

from flash.scripts.utils import string_to_offset
from flash.scripts.utils import string_to_size
from flash.scripts.utils import size_to_human_readable
from flash.scripts.remote import execute_remote

from errors import Result, Error, ErrorCode

###################################################################
######### flash programmer erase command
###################################################################
class CwFlashEraseAll(CwFlashBase):
    """
usage: [-h]

S32DS Flash Programming erase all command.

optional arguments:
  -h, --help  show this help message and exit
    """

    def __init__(self, hse_limits):
        """
            Register new command with GDB
            Add a parameter parser to easily specify positional offset and size
            parameters
        """
        super(CwFlashEraseAll, self).__init__(CMD_CW_FLASH_ERASE_ALL,
        gdb.COMMAND_USER, gdb.COMPLETE_COMMAND)
        parser = argparse.ArgumentParser(description='S32DS \
                                         Flash Programming erase all command.')
        self._parser = parser
        CwFlashEraseAll.print_result = None

        # Don't print on the screen while progress bar is in place. Save the output and
        # print after closing the progress bar.
        self.output = ""

        self.HSE_limits = hse_limits
        
    def can_execute(self, args):
        """
            Internal method
        """
        pass

    def execute(self, args, from_tty):
        """
            Execute command called with args parameters
            Build command string in the form of a monitor command
            and call internal gdb execution.
        """
        prop = self._info_for_current_device(from_tty)
        f_data_base = prop['data_flash_address']
        if (f_data_base == "0xdeadbeef"):
            try:
                cmd_string = 'mon flash erase chip'
                execute_remote(cmd_string, from_tty, no_wait = True)
            except:
                #try to erase sector by sector
                cmd_string = "mon flash erase offset %d size %s" % (0, prop['size'])
                execute_remote(cmd_string, from_tty, no_wait = True)
                
        else:
            #erase sector by sector from data and program flash
            f_program_base = int(prop['program_flash_address'], 0)
            f_data_base = int(prop['data_flash_address'], 0)
            f_data_sect_size = int(prop['data_sect_size'], 0)
            f_data_sectors = int(prop['data_sectors'],0)
            f_size_buff = hex(f_data_sect_size * f_data_sectors)
            f_data_size = int(f_size_buff,0)

            if(self.HSE_limits != None):
                try:
                    erase_params = self.HSE_limits.erase_chip(f_program_base, f_data_base)
                    if erase_params[0] != 0:
                        gdb.write('Erasing.... Offset: %s Size: %s\n' % (hex(erase_params[0]), hex(erase_params[1])))
                        cmd_string = "mon flash erase offset %d size %d" % (int(erase_params[0]), int(erase_params[1]))
                        execute_remote(cmd_string, from_tty, no_wait = True)
                    if erase_params[2] != 0:
                        gdb.write('Erasing.... Offset: %s Size: %s\n' % (hex(erase_params[2]), hex(erase_params[3])))
                        cmd_string = "mon flash erase offset %d size %d" % (int(erase_params[2]), int(erase_params[3]))
                        execute_remote(cmd_string, from_tty, no_wait = True)
                    if erase_params[4] != 0:
                        gdb.write('Erasing.... Offset: %s Size: %s\n' % (hex(erase_params[4]), hex(erase_params[5])))
                        cmd_string = "mon flash erase offset %d size %d" % (int(erase_params[4]), int(erase_params[5]))
                        execute_remote(cmd_string, from_tty, no_wait = True)
                except:
                    Result(Error(ErrorCode.FlashWriteError, "F-ERROR: Restricted area detected. Aborting Command"))
                    return
            else:
                cmd_string = "mon flash erase offset %d size %s" % (f_program_base, prop['size'])
                execute_remote(cmd_string, from_tty, no_wait = True)
                cmd_string = "mon flash erase offset %d size %s" % (f_data_base, f_data_size)
                execute_remote(cmd_string, from_tty, no_wait = True)

        

    def begin_command(self):
        gdb.write('Erasing....\n')

    def show_result(self):
        summary = 'Flash memory had been erased.\n'
        gdb.write(summary)

    def _info_for_current_device(self, from_tty):
        cmd_string = 'mon flash current'
        current_flash = execute_remote(cmd_string, from_tty, to_string = True, \
            no_wait = True)
        current_flash = current_flash.rstrip('\n')

        if 'no device selected' in current_flash:
            gdb.write('%s\n' % current_flash)
            return
        cmd_string = 'mon ctx get current'
        current_ctx = execute_remote(cmd_string, from_tty, to_string = True)
        if not current_ctx:
            gdb.write('no context selected\n')
            return

        current_ctx = current_ctx.rstrip('\n')
        cmd_string = 'mon ctx id %s:%s info' % (current_ctx, current_flash)
        ctxs = current_ctx.split(':')
        if len(ctxs) >= 3:
            device = ':%s:%s:%s' % (ctxs[1], ctxs[2], current_flash)
            cmd_string = 'mon ctx id %s info' % device
        result = execute_remote(cmd_string, from_tty, to_string = True)
        prop_bag = self._strToPropertyBag(result)
        return prop_bag


    def _strToPropertyBag(self, strProp):
        prop_bag = {}
        prop_list = strProp.split('\n')
        for prop in prop_list:
            prop = prop.replace(' ', '')
            name_value = prop.split(':')
            if len(name_value) == 2:
            #guard against inconsistency from gta side
                if name_value[1].startswith('0x') or \
                   not all(c in string.hexdigits for c in name_value[1]):
                    prop_bag[name_value[0]] = name_value[1]
                else:
                    prop_bag[name_value[0]] = ''.join(['0x', name_value[1]])
        return prop_bag
        
def create_command(hse_limits):
    """
        Instantiate flash programmer erase command
    """
    CwFlashEraseAll(hse_limits)
