import io
import os
import tkinter as tk
from tkinter import filedialog
import pandas as pd 
import sys 
import re  #正则表达式

def safe_hex_to_int(x):
    if isinstance(x, str) and all(c in "0123456789ABCDEFabcdef" for c in x):
        try:
            return int(x, 16)
        except ValueError:
            return None  # 或者返回一个默认值，如-1或np.nan
    else:
        return '0' # 或者根据需要返回其他默认值
def parse_varName(text:str)->str:
    result :str = None
    # 正则表达式匹配 _static_ 到字符串末尾
    pattern = r"_static_.*" 
    # 使用 re.search 查找匹配
    match = re.search(pattern, text)
    if match:
        moduleName = match.group()
        var = text.replace(moduleName,"") 
        # 正则表达式匹配 obj 和 _inf 之间的字符
        pattern = r"obj(.*?)_inf" 
        match = re.search(pattern, moduleName)
        if match:
            moduleName = match.group() 
            moduleName = moduleName.removeprefix("obj")
            moduleName = moduleName.removesuffix("_inf")
            result = moduleName+" "+var
        else:
            result = var + " Global"
    else:
        result = text.replace("\n","")+ " Global"
    return result
    
def select_file()->str:
    """
    打开文件选择对话框，并返回用户选择的文件路径。    
    Args:
        无    
    Returns:
        str: 用户选择的文件路径，如果用户未选择文件则返回空字符串。    
    """
    # 使用filedialog.askopenfilename函数打开文件选择对话框
    # 初始目录设置为 ".\"
    filepath = filedialog.askopenfilename(initialdir=".\\",
                                         title="please choose a map file",
                                         filetypes=[("Map files", "*.map")])

    # 如果用户选择了文件，打印出文件路径
    if filepath:
        print("select file "+filepath)
    return filepath

def writedf2ExcelFile(file_name:str,df:pd.DataFrame,sheet_name:str): 
    
    try: 
        file_exists = os.path.isfile(file_name)
        mode = 'a' if file_exists else 'w'
        with pd.ExcelWriter(file_name, mode=mode, engine='openpyxl' if file_exists else 'xlsxwriter') as writer:
            # 如果文件存在且使用 openpyxl 引擎，需要避免覆盖现有 sheet
            if mode == 'a':
                # 获取现有的 sheet 名列表（可选，用于避免重名）
                book = writer.book
                existing_sheets = [sheet.title for sheet in book.worksheets]
                
                # 为新 sheet 生成一个不重复的名称（这里简单使用递增数字） 
                counter = 1
                while sheet_name in existing_sheets:
                    sheet_name = f'Sheet{counter}'
                    counter += 1 

            # 将 DataFrame 写入到指定的 sheet 中
            df.to_excel(writer, sheet_name=sheet_name, index=False) 
            print(f"DataFrame 已成功保存到 {file_name} 的 {sheet_name} sheet 中")
    except Exception as e:
        print('Error: ',e)
 
def decodModuleSummary(file:str)->None: 
    '''
    #读取 Module Summary 行到  Load Map行, 
    #遇到空行继续下一行
    #Origin+Size    Section          Module作为标题
    '''
    
    bStartImageSummary= False 
    lines = []
    try: 
        with open(file,'r',encoding='utf-8') as f:
            for line in f:
                if bStartImageSummary:  
                    if line == '\n':
                        continue
                    elif 'Load Map' in line : 
                        break
                    line = line.replace('+', ' ')
                    line = line.replace('.o', ' ')
                    lines.append(line)
                if bStartImageSummary==False and 'Module Summary' in line :
                    bStartImageSummary = True 
            #print(lines)
            header = lines[0].split()
            #rows = [line.split() for line in lines[1:]] 
            rows = []
            for line in lines[1:]:
                line = line.replace(" -> ","->") 
                lineWord = line.split()
                if len(lineWord)<=4:
                    if len(lineWord)==4:                #有一个0xFF的空白字符钻进来
                        rows.append(lineWord)
                else: 
                    words = []
                    words.append(lineWord[0])
                    words.append(lineWord[1])
                    words.append(lineWord[2])
                    last  = "_".join(lineWord[3:])  
                    words.append(last)
                    rows.append(words) 
            # 创建DataFrame
            df = pd.DataFrame(rows, columns=header)  
            #df['Base_dec'] = df['Origin'].apply(safe_hex_to_int)
            df['Base_dec'] = df['Origin'].apply(lambda x: int(x, 16))     #增加排序列
            df_sorted = df.sort_values(by='Base_dec')  # 排序 
            df_sorted = df_sorted.drop(columns=['Base_dec'])   #删除排序列
            df_sorted = df_sorted.reset_index(drop=True)        #删除索引

            output_file = file.replace('.map','.xlsx') 
            writedf2ExcelFile(output_file,df_sorted,sheet_name='Module Summary')
            print("")
    except Exception as e:
        print('Error: ',e)




def decodeImageSummary(file:str)->None: 
    '''
    #读取Image Summary 行到  .debug_info行,
    #遇到空行继续下一行
    #Section Base Size(hex) Size(dec)  SecOffs 作为标题
    '''
    bStartImageSummary = False 
    lines = []
    try:
        with open(file,'r',encoding='utf-8') as f:
            for line in f:
                if bStartImageSummary: 
                    if line == '\n':
                        continue
                    elif bStartImageSummary:
                        if 'debug_info' in line : 
                            break
                    lines.append(line)
                if bStartImageSummary==False and 'Image Summary' in line :
                    bStartImageSummary = True 
            #print(lines)
            header = lines[0].split()
            rows = [line.split() for line in lines[1:]] 
            # 创建DataFrame
            df = pd.DataFrame(rows, columns=header)
            df['Base_dec'] = df['Base'].apply(lambda x: int(x, 16))     #增加排序列
            df_sorted = df.sort_values(by='Base_dec')  # 排序 
            df_sorted = df_sorted.drop(columns=['Base_dec'])   #删除排序列
            df_sorted = df_sorted.reset_index(drop=True)        #删除索引
            output_file = file.replace('.map','.xlsx')
            # with pd.ExcelWriter(output_file, engine='openpyxl') as writer:
            #    df_sorted.to_excel(writer, sheet_name='Image Summary', index=False)
            writedf2ExcelFile(output_file,df_sorted,sheet_name='Image Summary')
            print("")
    except Exception as e:
        print('Error: ',e)


def replace_multiple_spaces(text):
    return re.sub(r' +', ' ', text)
def decodGlobalSymbols(file:str)->None: 
    bStartGlobalSymbols = False 
    lines = []
    Header = ['segment','Base','Size','varName']#,"Module"]
    try:
        with open(file,'r',encoding='utf-8') as f:
            for line in f:
                if bStartGlobalSymbols: 
                    if line == '\n':
                        continue 
                    line = replace_multiple_spaces(line)
                    line = line.replace(' .', '.')
                    if line.startswith(' '): 
                        continue 
                    line = line.replace('+', ' ')
                    # line = parse_varName(line)
                    lines.append(line.split()) 
 
                if bStartGlobalSymbols==False and 'Global Symbols ' in line :
                    bStartGlobalSymbols = True
        
        df = pd.DataFrame(lines, columns=Header )  
        #df['Base_dec'] = df['Base'].apply(safe_hex_to_int)
        #df['Base_dec'] = df['Base'].apply(lambda x: int(x, 16))     #增加排序列
        #parse_varName("__Coding_CPM_PARA_aucLsTarget2Tz_static_in_D1_ProjectgitC25510BuildTmpX01Hq008_App_defaultobjCpm_Adapter_inf")
        #df_sorted = df.sort_values(by='Base_dec')  # 排序 
        #df_sorted = df_sorted.drop(columns=['Base_dec'])   #删除排序列
        #df_sorted = df_sorted.reset_index(drop=True)        #删除索引

        output_file = file.replace('.map','.xlsx') 
        writedf2ExcelFile(output_file,df,sheet_name='Global Symbols')
    except Exception as e:
        print('Error: ',e)

# 创建一个窗口用于触发文件选择
root = tk.Tk()
root.withdraw()  # 隐藏主窗口

if __name__ == "__main__":      
    mapfile:str = None
    if len(sys.argv)>1 :
        #for arg in sys.argv:
        #    print(arg) 
        mapfile = sys.argv[1]
    else: 
        # 调用函数
        mapfile = select_file() 
    if(mapfile is not None): 
        
        try:
            # 读取地图文件  
            output_file = mapfile.replace('.map','.xlsx')
            if(os.path.exists(output_file)):
                os.remove(output_file)
            decodGlobalSymbols(mapfile)
            decodModuleSummary(mapfile)
            decodeImageSummary(mapfile)
        except FileNotFoundError:
            print(f"文件 {output_file} 不存在")
        except PermissionError:
            print(f"无权删除 {output_file}")



