import {tracesAreEqual, tracesAreEqual2} from "../utils";
import type {PrimitiveModel} from "./PrimitiveModel";
import type {StreamData} from "./StreamData.svelte";

export default class Primitive {
    // input from api
    public key: string;
    public ptype: string;
    public sub_type: string;
    public value: string;
    public children: Primitive[];
    public trace: Trace[] = $state([]);
    public expanded: boolean = $state(false);

    //local state
    public stream_data: StreamData | undefined = $state();

    constructor(
        p: PrimitiveModel
    ) {
        this.key = p.key;
        this.ptype = p.ptype;
        this.sub_type = p.sub_type;
        this.value = p.value;
        this.children = [];
        for (let child of p.children) {
            this.children.push(new Primitive(child));
        }
        this.trace = [];
        this.expanded = p.expanded;
        for (let path of p.trace) {
            this.trace.push(path);
        }
    }

    public isContainer() {
        return this.ptype === "Dictionary" || this.ptype === "Array" || this.ptype === "Reference" || this.ptype === "Stream";
    }

    public getPath(): string[] {
        return this.trace.map(path => path.key);
    }

    public traceEquals(trace: Trace[]): boolean {
        return tracesAreEqual(trace, this.trace)
    }
    public pathEquals(path: string[]): boolean {
        return tracesAreEqual2(this.trace, path)
    }

    public getLastJump(): string | number {
        let path = this.trace[this.trace.length - 1].last_jump;
        if (path === "/") {
            return path
        }
        ;
        return +path;
    }

    public isPage(): boolean {
        return this.trace[0].key.startsWith("Page") && !isNaN(+this.trace[0].key.replace("Page", ""));
    }

    public getPageNumber(): number {
        if (!this.isPage()) {
            throw new Error("Primitive is not a page");
        }
        return +this.trace[0].key.replace("Page", "");
    }

    public getFirstJump(): string | number | undefined {
        let path = this.trace[0].last_jump;
        if (path === "Trailer") {
            return path
        }
        ;
        if (path.startsWith("Page")) {
            return path
        }
        ;
        return +path;
    }

    public withoutChildren(): Primitive {
        return new Primitive({
            ...this,
            children: [],
            expanded: false,
        });
    }

    public isChildOf(prim: Primitive | undefined): boolean {
        if (!prim) {
            return false;
        }
        return tracesAreEqual(this.trace.slice(0, -1), prim.trace);
    }
}

export interface Trace {
    readonly key: string;
    readonly last_jump: string;
}
