// 假设 IPage 接口定义如下
interface IPage {
    // 可根据实际情况添加其他方法
}

// 假设 PrintContainer 类定义如下
class PrintContainer {
    // 可根据实际情况添加属性和方法
    Device: string;
    ActualWidth: number;
    ActualHeight: number;
    PrintToXps(): FileInfo;
    Content: any;
    DocumentName: string;
}

// 假设 FileInfo 类定义如下
class FileInfo {
    FullName: string;
}

// 假设 TradeForms 类定义如下
class TradeForms {
    formid: string;
    formname: string;
    isenabled: number;
    rolecount: number;
}

// 假设 PrintHandle 类定义如下
class PrintHandle {
    static GetTradeFormsByTradecode(tradeCode: string): TradeForms[] {
        // 实现获取交易相关的表单项配置信息的逻辑
        return [];
    }
}

// 假设 TellerSys.ServiceProxy.PrintService.TPrintData 类定义如下
class TPrintData {
    formid: string;
    formName: string;
    businessId: string;
    rolecount: number;
    formdata: Uint8Array;
}

// 假设 TellerSys.ServiceProxy.ServiceHelper 类定义如下
class ServiceHelper {
    static AddPrintData(data: TPrintData): string {
        // 实现添加打印数据的逻辑
        return "";
    }
    static AddPrintHistory(id: string, tellerNo: string, empty: string): void {
        // 实现记录打印历史的逻辑
    }
}

// 假设 PrintPreviewWindow 类定义如下
class PrintPreviewWindow {
    Owner: any;
    IsPrinted: boolean;
    constructor(xpsFile: FileInfo, device: string) {
        // 实现构造函数逻辑
    }
    DoPrint(): void {
        // 实现打印操作的逻辑
    }
    ShowDialog(): void {
        // 实现显示对话框的逻辑
    }
}

// 假设 FrameworkElement 类定义如下
class FrameworkElement {
    // 可根据实际情况添加属性和方法
    ActualWidth: number;
    ActualHeight: number;
    Parent: any;
    Name: string;
    Children: any[];
    ItemsSource: any;
    Items: any[];
    SelectedIndex: number;
}

// 假设 ComboBox 类定义如下
class ComboBox extends FrameworkElement {
    // 可根据实际情况添加属性和方法
}

// 假设 DataGrid 类定义如下
class DataGrid extends FrameworkElement {
    // 可根据实际情况添加属性和方法
    Columns: any[];
}

// 假设 DataBox 类定义如下
class DataBox extends FrameworkElement {
    // 可根据实际情况添加属性和方法
}

// 假设 FocusManager 类定义如下
class FocusManager {
    static GetIsInternalKeyboardControlling(element: any): boolean {
        // 实现获取是否内部键盘控制的逻辑
        return false;
    }
}

// 假设 XmlDocument 类定义如下
class XmlDocument {
    DocumentElement: any;
    InnerXml: string;
    LoadXml(xml: string): void {
        // 实现加载 XML 的逻辑
    }
    SelectSingleNode(node: string): any {
        // 实现选择单个节点的逻辑
        return null;
    }
    CreateElement(name: string): any {
        // 实现创建元素的逻辑
        return null;
    }
}

// 假设 XmlNode 类定义如下
class XmlNode {
    Attributes: any;
    ChildNodes: any[];
    AppendChild(node: any): void {
        // 实现追加子节点的逻辑
    }
}

// 假设 XmlElement 类定义如下
class XmlElement extends XmlNode {
    SetAttribute(name: string, value: string): void {
        // 实现设置属性的逻辑
    }
}

// 假设 XmlReader 类定义如下
class XmlReader {
    static Create(reader: any): XmlReader {
        // 实现创建 XmlReader 的逻辑
        return null;
    }
}

// 假设 XamlReader 类定义如下
class XamlReader {
    static Load(reader: any): any {
        // 实现加载 XAML 的逻辑
        return null;
    }
}

// 假设 XamlWriter 类定义如下
class XamlWriter {
    static Save(element: any): string {
        // 实现保存 XAML 的逻辑
        return "";
    }
}

// 假设 RenderTargetBitmap 类定义如下
class RenderTargetBitmap {
    constructor(width: number, height: number, dpiX: number, dpiY: number, format: any) {
        // 实现构造函数逻辑
    }
    Render(element: any): void {
        // 实现渲染元素的逻辑
    }
}

// 假设 BitmapSource 类定义如下
class BitmapSource {
    // 可根据实际情况添加属性和方法
}

// 假设 BitmapImage 类定义如下
class BitmapImage extends BitmapSource {
    BeginInit(): void {
        // 实现开始初始化的逻辑
    }
    StreamSource: any;
    EndInit(): void {
        // 实现结束初始化的逻辑
    }
}

// 假设 PngBitmapEncoder 类定义如下
class PngBitmapEncoder {
    Frames: any[];
    Add(frame: any): void {
        // 实现添加帧的逻辑
    }
    Save(stream: any): void {
        // 实现保存到流的逻辑
    }
}

// 假设 MemoryStream 类定义如下
class MemoryStream {
    constructor(buffer?: Uint8Array) {
        // 实现构造函数逻辑
    }
    Position: number;
    Length: number;
    Read(buffer: Uint8Array, offset: number, count: number): number {
        // 实现读取数据的逻辑
        return 0;
    }
    Flush(): void {
        // 实现刷新流的逻辑
    }
    Close(): void {
        // 实现关闭流的逻辑
    }
    ToArray(): Uint8Array {
        // 实现转换为字节数组的逻辑
        return new Uint8Array();
    }
}

// 假设 IFormatter 类定义如下
class IFormatter {
    Serialize(stream: any, obj: any): void {
        // 实现序列化的逻辑
    }
    Deserialize(stream: any): any {
        // 实现反序列化的逻辑
        return null;
    }
}

// 假设 BinaryFormatter 类定义如下
class BinaryFormatter extends IFormatter {
    // 可根据实际情况添加属性和方法
}

// 假设 Image 类定义如下
class Image {
    Source: BitmapSource;
}

// 假设 Panel 类定义如下
class Panel extends FrameworkElement {
    Children: FrameworkElement[];
    Remove(child: FrameworkElement): void {
        // 实现移除子元素的逻辑
    }
}

// 假设 ContentControl 类定义如下
class ContentControl extends FrameworkElement {
    Content: any;
}

// 假设 ItemsControl 类定义如下
class ItemsControl extends FrameworkElement {
    Items: any[];
    Remove(child: any): void {
        // 实现移除子项的逻辑
    }
}

// 假设 DataTable 类定义如下
class DataTable {
    Columns: any[];
    Rows: any[];
    AddColumn(name: string): void {
        // 实现添加列的逻辑
    }
    AddRow(data: any[]): void {
        // 实现添加行的逻辑
    }
    DefaultView: any;
}

// 假设 DataRowView 类定义如下
class DataRowView {
    Row: any;
}

// 假设 DataGridColumn 类定义如下
class DataGridColumn {
    Header: any;
}

// 假设 Application 类定义如下
class Application {
    static Current: Application;
    MainWindow: any;
}

// 假设 TradePage 类定义如下
class TradePage {
    Content: any;
    ShowPageMessageBoxExt(message: string, options: { [key: string]: string }, defaultKey: any): any {
        // 实现显示消息框的逻辑
        return null;
    }
}

// 转换后的 TradePageExtension 类
export class TradePageExtension {
    static SaveTradePage(target: IPage, rootElement: FrameworkElement): Uint8Array {
        const rtb = new RenderTargetBitmap(
            Math.floor(rootElement.ActualWidth),
            Math.floor(rootElement.ActualHeight),
            96,
            96,
            null // 此处需要根据实际情况指定像素格式
        );
        rtb.Render(rootElement);
        return this.BitmapSourceToByte(rtb as unknown as BitmapSource);
    }

    static RestoreTradePage(target: IPage, tradepagedata: Uint8Array): FrameworkElement {
        const image = new Image();
        image.Source = this.ByteToBitmapSource(tradepagedata);
        return image as unknown as FrameworkElement;
    }

    private static DealSpecialControl(rootElement: FrameworkElement, pagedata: XmlDocument, specialitems: { [key: string]: any }, flag: number): void {
        const elements = rootElement.Children;
        for (let i = 0; i < elements.length; i++) {
            const element = elements[i] as FrameworkElement;
            if (!element) continue;

            if (element instanceof ComboBox) {
                if (flag === 0) {
                    if (!specialitems[element.Name]) {
                        const items: { [key: string]: any } = {};
                        for (let j = 0; j < element.Items.length; j++) {
                            const item = element.Items[j];
                            if (item) {
                                items[(j + 1).toString()] = item;
                            }
                        }
                        this.InsertInfoToXml(pagedata, "ComBoxInfo", element.Name, this.Serialize(items), element.SelectedIndex.toString());
                        items["selectedindex"] = element.SelectedIndex;
                        specialitems[element.Name] = items;
                        element.Items = [];
                    }
                } else if (flag === 1) {
                    if (Object.keys(specialitems).length !== 0) {
                        for (const [key, value] of Object.entries(specialitems)) {
                            if (key === element.Name) {
                                const itemObj = value as { [key: string]: any };
                                for (const [itemKey, itemValue] of Object.entries(itemObj)) {
                                    if (itemKey === "selectedindex") {
                                        element.SelectedIndex = itemValue as number;
                                    } else {
                                        element.Items.push(itemValue);
                                    }
                                }
                                break;
                            }
                        }
                    } else {
                        const items = this.Deserialize<{ [key: string]: any }>(this.GetDataFromXml(pagedata, "ComBoxInfo", element.Name, "value"));
                        for (const [key, value] of Object.entries(items)) {
                            element.Items.push(value);
                        }
                        let index = 0;
                        const indexStr = this.GetDataFromXml(pagedata, "ComBoxInfo", element.Name, "selectedindex");
                        if (indexStr) {
                            index = parseInt(indexStr, 10);
                        }
                        element.SelectedIndex = index;
                    }
                }
            } else if (element instanceof DataGrid) {
                if (flag === 0) {
                    if (!specialitems[element.Name]) {
                        specialitems[element.Name] = element.ItemsSource;
                        const items: { [key: string]: any } = {};
                        const colname: any[] = [];
                        for (let j = 0; j < element.Columns.length; j++) {
                            const column = element.Columns[j];
                            colname.push(column.Header);
                        }
                        items["colname"] = colname;
                        for (let j = 0; j < element.Items.length; j++) {
                            const item = element.Items[j] as DataRowView;
                            if (item) {
                                items[(j + 1).toString()] = item.Row.ItemArray;
                            }
                        }
                        this.InsertInfoToXml(pagedata, "DataGrid", element.Name, this.Serialize(items), "");
                        element.ItemsSource = null;
                    }
                } else if (flag === 1) {
                    if (Object.keys(specialitems).length !== 0) {
                        for (const [key, value] of Object.entries(specialitems)) {
                            if (key === element.Name) {
                                element.ItemsSource = value as any;
                                break;
                            }
                        }
                    } else {
                        const items = this.Deserialize<{ [key: string]: any }>(this.GetDataFromXml(pagedata, "DataGrid", element.Name, "value"));
                        const table = new DataTable();
                        for (const [key, value] of Object.entries(items)) {
                            if (key === "colname") {
                                const colnames = value as any[];
                                for (const colname of colnames) {
                                    table.AddColumn(colname.toString());
                                }
                            } else {
                                table.AddRow(value as any[]);
                            }
                        }
                        element.ItemsSource = table.DefaultView;
                    }
                }
            } else if (element instanceof DataBox) {
                const parent = element.Parent as FrameworkElement;
                if (parent instanceof Panel) {
                    parent.Remove(element);
                } else if (parent instanceof ContentControl) {
                    parent.Content = null;
                } else if (parent instanceof ItemsControl) {
                    parent.Items.remove(element);
                }
                this.DealSpecialControl(parent, pagedata, specialitems, flag);
                break;
            }

            if (element && !FocusManager.GetIsInternalKeyboardControlling(element)) {
                this.DealSpecialControl(element, pagedata, specialitems, flag);
            }
        }
    }

    private static InsertInfoToXml(pagedataxml: XmlDocument, node: string, name: string, value: string, selectedindex: string): void {
        try {
            if (pagedataxml) {
                const root = pagedataxml.DocumentElement;
                const nodetmp = root.SelectSingleNode(node);
                const xe = pagedataxml.CreateElement("info");
                xe.SetAttribute("name", name);
                xe.SetAttribute("selectedindex", selectedindex);
                xe.SetAttribute("value", value);
                nodetmp.AppendChild(xe);
            }
        } catch (e) {
            throw e;
        }
    }

    private static GetDataFromXml(pagedataxml: XmlDocument, node: string, name: string, property: string): string {
        let result = null;
        try {
            const root = pagedataxml.DocumentElement;
            const nodetmp = root.SelectSingleNode(node);
            for (const tmp of nodetmp.ChildNodes) {
                if (tmp.Attributes["name"].Value === name) {
                    result = tmp.Attributes[property].Value;
                    break;
                }
            }
        } catch (e) {
            throw e;
        }
        return result;
    }

    private static Serialize<T>(obj: T): string {
        if (!obj) return null;
        const formatter = new BinaryFormatter();
        const stream = new MemoryStream();
        formatter.Serialize(stream, obj);
        stream.Position = 0;
        const buffer = new Uint8Array(stream.Length);
        stream.Read(buffer, 0, buffer.length);
        stream.Flush();
        stream.Close();
        return btoa(String.fromCharCode.apply(null, Array.from(buffer)));
    }

    static Serialize<T>(target: IPage, obj: T): string {
        return this.Serialize(obj);
    }

    static Deserialize<T>(target: IPage, str: string): T {
        return this.Deserialize(str);
    }

    private static Deserialize<T>(str: string): T {
        let obj: T = null;
        const formatter = new BinaryFormatter();
        const buffer = Uint8Array.from(atob(str).split('').map(c => c.charCodeAt(0)));
        const stream = new MemoryStream(buffer);
        obj = formatter.Deserialize(stream) as T;
        stream.Flush();
        stream.Close();
        return obj;
    }

    static PrintCertificate(target: IPage, tradeCode: string, businessId: string, forms: PrintContainer[]): void {
        const tradeForms = PrintHandle.GetTradeFormsByTradecode(tradeCode);
        for (const print of forms) {
            let xpsFile: FileInfo = null;
            // 此处省略了原代码中复杂的打印逻辑，需要根据实际情况实现
        }
    }

    static BitmapSourceToByte(bitmapSource: BitmapSource): Uint8Array {
        const encoder = new PngBitmapEncoder();
        encoder.Frames = [];
        encoder.Add(BitmapFrame.Create(bitmapSource));
        const ms = new MemoryStream();
        encoder.Save(ms);
        return ms.ToArray();
    }

    static ByteToBitmapSource(byteData: Uint8Array): BitmapSource {
        const bi = new BitmapImage();
        bi.BeginInit();
        bi.StreamSource = new MemoryStream(byteData);
        bi.EndInit();
        return bi;
    }
}