import { Observable, Subject, Subscription } from 'rxjs';
import { WorkBook, JSON2SheetOpts, WorkSheet, WritingOptions } from 'xlsx';

declare class Base64 {
    private static PADCHAR;
    private static ALPHA;
    private static getByte;
    private static getByte64;
    static decode(s: string): string;
    static encode(s: string): string;
}

declare function customCacheHasher(parameters: unknown[]): unknown[];

interface CompressedData {
    length: number;
    type: string;
    object: any;
}

declare class Compression {
    private base64Index;
    private indexBase64;
    constructor();
    private generateBase64Index;
    compressBlob(blob: Blob): Observable<CompressedData>;
    decompressBlob(compressedData: CompressedData): Blob;
    private compressStringBase64;
    private decompressStringBase64;
}

declare enum ChangeType {
    ADDED = "added",
    DELETED = "deleted",
    MODIFIED = "modified"
}
interface Change {
    type: ChangeType;
    keysChanged?: {
        key: string;
        newValue: any;
        oldValue: any;
    }[];
}
interface GroupingChanges {
    added: ChangeItem[];
    deleted: ChangeItem[];
    modified: ChangeItem[];
}
interface ChangeItem {
    change: Change;
    value: any;
    oldValue?: any;
    newValue?: any;
}

declare class ChangeUtils {
    static findChanges(obj1: any[], obj2: any[], ignoreKeys?: string[]): GroupingChanges;
    private static compareObject;
}

declare function isIsoDate(value: string): boolean;
declare const TimeFrame: readonly ["now", "today"];
type TimeFrame = (typeof TimeFrame)[number];
declare function isTimeFrame(value: Date | TimeFrame | string | number): value is TimeFrame;
declare function resolveDate(input?: Date | TimeFrame): Date | undefined;

declare class DomUtils {
    static create<K extends keyof HTMLElementTagNameMap>(doc: Document, tagName: K, options?: Partial<HTMLElementTagNameMap[K]>): HTMLElementTagNameMap[K];
    static remove(node: HTMLElement | SVGElement): void;
}

declare function createExcelWorkBook(workSheet?: WorkSheet, workSheetName?: string): Promise<WorkBook>;
declare function addExcelSheetToWorkBook<T = Record<string, unknown>>(title: string, rows: T[], workBook: WorkBook, opts?: {
    json2SheetOpts?: JSON2SheetOpts;
    bookAppendSheetOpts?: {
        roll?: boolean;
    };
}): Promise<void>;
declare function writeExcelFile(workBook: WorkBook, filename: string, opts?: WritingOptions): Promise<void>;

/**
 * Trigger download of a file
 *
 * @param content File content
 * @param mimeType File mime type
 * @param fileName File name
 */
declare function downloadContent(content: string, mimeType: string, fileName: string): void;
declare function downloadBlob(blob: Blob, fileName: string): void;
/**
 * Trigger download of a file
 *
 * @param content File content
 * @param mimeType File mime type
 * @param fileName File name
 */
declare function downloadFromUri(uri: string, fileName: string): void;
/**
 * Validate if string is valid json object
 * @param jsonString
 * @return boolean
 */
declare function isValidJSON(jsonString: string): boolean;

declare class ObjectUtils {
    static resolve(obj: object, key: string): any;
    static isObject(item: object): boolean;
    static mergeDeep(target: object, source: object, ignoreUndefined?: boolean): any;
    static copyDeep(src: any): any;
    static removeDuplicateCaseInsensitive(obj: object): void;
    static removeUndefined(obj: object): any;
    static removeNull(obj: object): any;
    static naturalCompare(a: any, b: any, direction?: string, nullsFirst?: boolean): any;
    /**
     * Return true if two object are equivalent.
     * Objects are considered equivalent if they have the same properties and
     * if all of their properties (first-level only) share the same value.
     * @param obj1 First object
     * @param obj2 Second object
     * @returns Whether two objects arer equivalent
     */
    static objectsAreEquivalent(obj1: object, obj2: object): boolean;
    /**
     * Return a new object with an array of keys removed
     * @param obj Source object
     * @param keys Keys to remove
     * @returns A new object
     */
    static removeKeys(obj: object, keys: string[]): object;
    static isEmpty(obj: object): boolean;
}

declare class NumberUtils {
    static roundToNDecimal(num: number, decimal?: number): number;
}

/** Utility function to create a K:V from a list of strings */
declare function strEnum<T extends string>(o: T[]): {
    [K in T]: K;
};

declare class StringUtils {
    static diff(s1: string, s2: string, p?: number): string;
    private static getMatchingSubstring;
    private static getChanges;
    private static rotateArray;
    static isValidNumber(value: string): boolean;
    static isOctalNumber(value: string): boolean;
}

declare function loadTheme(doc: Document, themeName: string, path?: string): void;

type TreeId = string | number;
interface ITreeConfig<T> {
    getChildren: (dataNode: T) => T[] | undefined | null;
    getId: (dataNode: T) => TreeId;
    getLevel: (dataNode: T) => number;
    reverse?: boolean;
}
declare const TREE_SEPERATOR = ".";
declare class Tree<T> {
    private config;
    private _data;
    getChildren: (dataNode: T) => T[] | undefined | null;
    getId: (dataNode: T) => TreeId;
    getLevel: (dataNode: T) => number;
    constructor(initialData: T[], config: ITreeConfig<T>);
    get data(): readonly T[];
    get flattened(): readonly T[];
    add(...nodes: T[]): T[];
    addBefore(beforeId: string | undefined, ...nodes: T[]): void;
    remove(...nodes: T[]): T[];
    clear(): void;
    exist(node: T): boolean;
    /**
     * Move a node to a different position
     * @param node
     * @param beforeTo The position of index into the tree. If -1 move at the end
     */
    moveTo(beforeTo: number[], ...nodes: T[]): T[];
    getPosition(node: T): number[];
    private _addBefore;
    private _remove;
    /**
     * Move an node before an id
     * @param node Node to be move
     * @param recipient
     * @param beforeId
     */
    private move;
    private _getPosition;
    private getAncestorAtPosition;
    /** Recursive */
    private sortDeep;
    private sort;
    /** Recursive */
    private _getNodeById;
    getNodeByPosition(indexes: number[]): T;
    private _getByIndex;
    private getNodeAncestor;
    /** Recursive */
    private getAncestorById;
    /** Recursive */
    private flatten;
    private getIndex;
}

type OptionalRequired<T> = {
    [K in keyof T]-?: T[K];
};

declare function S4(): string;
declare function uuid(): string;

declare enum SubjectStatus {
    Error = 0,
    Done = 1,
    Working = 2,
    Waiting = 3
}
declare abstract class Watcher {
    status$: Subject<SubjectStatus>;
    protected status$$: Subscription;
    get status(): SubjectStatus;
    set status(value: SubjectStatus);
    private _status;
    protected abstract watch(): any;
    protected abstract unwatch(): any;
    subscribe(callback: Function, scope?: any): void;
    unsubscribe(): void;
}

export { Base64, ChangeType, ChangeUtils, Compression, DomUtils, NumberUtils, ObjectUtils, S4, StringUtils, SubjectStatus, TREE_SEPERATOR, TimeFrame, Tree, Watcher, addExcelSheetToWorkBook, createExcelWorkBook, customCacheHasher, downloadBlob, downloadContent, downloadFromUri, isIsoDate, isTimeFrame, isValidJSON, loadTheme, resolveDate, strEnum, uuid, writeExcelFile };
export type { Change, ChangeItem, CompressedData, GroupingChanges, ITreeConfig, OptionalRequired };
