import { Observer } from "./Observer";
import { ObserverData } from "./ObserverData";

/**
 * The Subject interface declares a set of methods for managing subscribers.
 */
export interface Subject<T> {
    // Attach an observer to the subject.
    attach(observer: Observer<T>): void;

    // Detach an observer from the subject.
    detach(observer: Observer<T>): void;

    // Notify all observers about an event.
    notify(param: any): void;
}

/**
 * The Subject owns some important state and notifies observers when the state
 * changes.
 */
// class ConcreteSubject implements Subject {
//     /**
//      * @type {number} For the sake of simplicity, the Subject's state, essential
//      * to all subscribers, is stored in this variable.
//      */
//     public state: number;

//     /**
//      * @type {Observer[]} List of subscribers. In real life, the list of
//      * subscribers can be stored more comprehensively (categorized by event
//      * type, etc.).
//      */
//     private observers: Observer[] = [];

//     /**
//      * The subscription management methods.
//      */
//     public attach(observer: Observer): void {
//         console.log('Subject: Attached an observer.');
//         this.observers.push(observer);
//     }

//     public detach(observer: Observer): void {
//         const observerIndex = this.observers.indexOf(observer);
//         this.observers.splice(observerIndex, 1);
//         console.log('Subject: Detached an observer.');
//     }

//     /**
//      * Trigger an update in each subscriber.
//      */
//     public notify(): void {
//         console.log('Subject: Notifying observers...');
//         for (const observer of this.observers) {
//             observer.update(this);
//         }
//     }

//     /**
//      * Usually, the subscription logic is only a fraction of what a Subject can
//      * really do. Subjects commonly hold some important business logic, that
//      * triggers a notification method whenever something important is about to
//      * happen (or after it).
//      */
//     public someBusinessLogic(): void {
//         console.log('\nSubject: I\'m doing something important.');
//         this.state = Math.floor(Math.random() * (10 + 1));

//         console.log(`Subject: My state has just changed to: ${this.state}`);
//         this.notify();
//     }
// }



// /**
//  * The client code.
//  */

// const subject = new ConcreteSubject();

// const observer1 = new ConcreteObserverA();
// subject.attach(observer1);

// const observer2 = new ConcreteObserverB();
// subject.attach(observer2);

// subject.someBusinessLogic();
// subject.someBusinessLogic();

// subject.detach(observer2);

// subject.someBusinessLogic();