@startuml

hide empty fields
hide empty methods

class Event {
  engine: Engine
  type: string
}

class ComponentEvent {
  component: string
  entities: Map<number, Component>
}

class EntityEvent {
  entity: number
  components: Map<string, Component>
}

ComponentEvent --|> Event
EntityEvent --|> Event

interface Observable {
  observe(observer: Observer): void
  unobserve(observer: Observer): void
}

interface Action {
  type: String
  payload: Object
  meta: Object
}
interface Component {
  [id: number]: JSON
}
interface JSON

Action --|> JSON
Component --|> JSON

Component --* State

interface Middleware {
  engine: Engine
  action: Action
  next: Function
}
interface System {
  ' Systems should be able to set up events, etc. However I don't suppose
  ' That's system's job.
  engine: Engine
  action: Action
}
interface Observer {
  event: Event
}
interface Function

Middleware --|> Function
System --|> Function
Observer --|> Function

class Handler {
}

Handler --|> Observer

class State {
  id: Component
  [key: string]: Component
}

class Engine {
  ' EventListener add / delete
  ' System add and delete should be done at initalization time
  ' Middleware too
  ' Component too, since Components are managed by the engine.
  systems: Array<System>
  state: State

  dispatch(action: Action)
  update(delta: number)

  get(id: number)
  create(id: number)
  remove(id: number)
}

Middleware --o Engine
System --o Engine
Engine --|> Observable
State --* Engine

class Entity {
  engine: Engine
  id: number
  get(key: String)
  set(key: String, component)
  remove(key: String)
}

Component --o Entity
Entity --* Engine
Entity --|> Observable

class EventQueue {
  observeEntry()
  observeComponent()
  push()
  notify()
}

EventQueue --* Engine
Observer --* EventQueue
Event --o EventQueue



@enduml
