import { ResourcesDialogParameters } from "../../Dialogs/DialogParameters/ResourcesDialogParameters";
import { TaskEditParameters } from "../../Dialogs/DialogParameters/TaskEditParameters";
import { ITaskUpdateValues } from "../Entities/ITaskUpdateValues";
import { ResourceAssignment } from "../Entities/ResourceAssignment";
import { Task } from "../Entities/Task";
import { DependencyInsertingArguments } from "../Events/Dependency/DependencyInsertingArguments";
import { DependencyRemovingArguments } from "../Events/Dependency/DependencyRemovingArguments";
import { ResourceManagerDialogShowingArguments } from "../Events/Dialogs/ResourceManagerDialogShowingArguments";
import { TaskEditDialogShowingArguments } from "../Events/Dialogs/TaskEditDialogShowingArguments";
import { ResourceInsertingArguments } from "../Events/Resource/ResourceInsertingArguments";
import { ResourceRemovingArguments } from "../Events/Resource/ResourceRemovingArguments";
import { ResourceAssigningArguments } from "../Events/ResourceAssignment/ResourceAssigningArguments";
import { ResourceUnassigningArguments } from "../Events/ResourceAssignment/ResourceUnassigningArguments";
import { TaskInsertingArguments } from "../Events/Task/TaskInsertingArguments";
import { TaskRemovingArguments } from "../Events/Task/TaskRemovingArguments";
import { TaskUpdatingArguments } from "../Events/Task/TaskUpdatingArguments";
import { EventDispatcher } from "./EventDispatcher";

export class ModelChangesDispatcher {
    onModelChanged: EventDispatcher = new EventDispatcher();
    private isLocked: boolean = false;

    notifyTaskCreating(args: TaskInsertingArguments): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyTaskCreating", args);
    }

    notifyTaskCreated(task: any, callback: (id: any) => void, errorCallback: () => void): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyTaskCreated", task, callback, errorCallback);
    }
    notifyTaskRemoving(args: TaskRemovingArguments): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyTaskRemoving", args);
    }
    notifyTaskRemoved(taskID: any, errorCallback: () => void, task: any): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyTaskRemoved", taskID, errorCallback, task);
    }
    notifyTaskUpdating(args: TaskUpdatingArguments): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyTaskUpdating", args);
    }
    notifyTaskMoving(args: TaskUpdatingArguments): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyTaskMoving", args);
    }
    notifyTaskEditDialogShowing(args: TaskEditDialogShowingArguments): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyTaskEditDialogShowing", args);
    }
    notifyResourceManagerDialogShowing(args: ResourceManagerDialogShowingArguments): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyResourceManagerDialogShowing", args);
    }
    notifyTaskUpdated(taskID: any, newValues: Record<string, any>, errorCallback: () => void): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyTaskUpdated", taskID, newValues, errorCallback);
    }
    notifyParentTaskUpdated(task: Task, errorCallback: () => void): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyParentTaskUpdated", task, errorCallback);
    }
    notifyDependencyInserting(args: DependencyInsertingArguments): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyDependencyInserting", args);
    }
    notifyDependencyInserted(dependency: any, callback: (id: any) => void, errorCallback: () => void): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyDependencyInserted", dependency, callback, errorCallback);
    }
    notifyDependencyRemoving(args: DependencyRemovingArguments): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyDependencyRemoving", args);
    }
    notifyDependencyRemoved(dependencyID: any, errorCallback: () => void, dependency: any): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyDependencyRemoved", dependencyID, errorCallback, dependency);
    }
    notifyResourceCreating(args: ResourceInsertingArguments): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyResourceCreating", args);
    }
    notifyResourceCreated(resource: any, callback: (id: any) => void, errorCallback: () => void): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyResourceCreated", resource, callback, errorCallback);
    }
    notifyResourceRemoving(args: ResourceRemovingArguments): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyResourceRemoving", args);
    }
    notifyResourceRemoved(resourceID: any, errorCallback: () => void, resource: any): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyResourceRemoved", resourceID, errorCallback, resource);
    }
    notifyResourceColorChanged(resourceID: any, newValue: string, errorCallback: () => void): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyResourceColorChanged", resourceID, newValue, errorCallback);
    }
    notifyResourceAssigning(args: ResourceAssigningArguments): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyResourceAssigning", args);
    }
    notifyResourceAssigned(assignment: any, callback: (id: any) => void, errorCallback: () => void): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyResourceAssigned", assignment, callback, errorCallback);
    }
    notifyResourceUnassigning(args: ResourceUnassigningArguments): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyResourceUnassigning", args);
    }
    notifyResourceUnassigned(assignmentID: any, errorCallback: () => void, assignment: any): void {
        if(!this.isLocked)
            this.onModelChanged.raise("NotifyResourceUnassigned", assignmentID, errorCallback, assignment);
    }
    notifyParentDataRecalculated(data: any): void {
        this.onModelChanged.raise("NotifyParentDataRecalculated", data);
    }
    notifyScaleCellPrepared(data: Record<string, any>): void {
        this.onModelChanged.raise("NotifyScaleCellPrepared", data);
    }

    fireResourceUnassigning(assignment: ResourceAssignment): boolean {
        const args = new ResourceUnassigningArguments(assignment);
        this.notifyResourceUnassigning(args);
        return !args.cancel;
    }

    raiseTaskUpdating(task: Task, newValues: ITaskUpdateValues, callback:(newValues: any) => void): boolean {
        const args = new TaskUpdatingArguments(task, newValues);
        this.notifyTaskUpdating(args);
        if(!args.cancel) {
            callback(args.newValues);
            return true;
        }
        return false;
    }
    raiseTaskMoving(task: Task, newStart: Date, newEnd: Date, callback:(newStart, newEnd: Date) => void): boolean {
        const args = new TaskUpdatingArguments(task, { start: newStart, end: newEnd });
        this.notifyTaskMoving(args);
        if(!args.cancel) {
            callback(args["start"], args["end"]);
            return true;
        }
        return false;
    }
    raiseTaskTaskEditDialogShowing(params: TaskEditParameters, callback:(args: TaskEditDialogShowingArguments) => void): boolean {
        const args = new TaskEditDialogShowingArguments(params);
        this.notifyTaskEditDialogShowing(args);
        if(!args.cancel) {
            callback(args);
            return true;
        }
        return false;
    }

    raiseResourceManagerDialogShowing(params: ResourcesDialogParameters, callback:(args: ResourceManagerDialogShowingArguments) => void): boolean {
        const args = new ResourceManagerDialogShowingArguments(params);
        this.notifyResourceManagerDialogShowing(args);
        if(!args.cancel) {
            callback(args);
            return true;
        }
        return false;
    }

    public lock(): void { this.isLocked = true; }
    public unlock(): void { this.isLocked = false; }
}
