'use strict';

import {BehaviorSubject, Observable} from 'rxjs';
import {
  IAdapter,
  IConnectionOptions,
  IBaseModelConstructor,
  IConnection
} from './interfaces';

export const ConnectionStatus = {
  NotConnected: 'NotConnected',
  Connected: 'Connected'
}

export class Connection implements IConnection {

  protected _adapter: IAdapter;
  protected _status: BehaviorSubject<string>;
  protected _options: IConnectionOptions;

  constructor(options: IConnectionOptions) {
    this._status = new BehaviorSubject(ConnectionStatus.NotConnected);
    this._options = options;    
  }
  
  get name(): string {
    return this._options.name;
  }

  get adapter(): IAdapter {
    return this._adapter;
  }

  get status(): BehaviorSubject<string> {
    return this._status;
  }

  get isConnected(): boolean {
    return this._status.getValue() === ConnectionStatus.Connected;
  }

  init(): Observable<IConnection> {
    this._options.adapter
      .init(this._options.params)
      .subscribe(adapter => {
        this._adapter = adapter;
        this._status.next(ConnectionStatus.Connected);
      });
      
    return Observable.create(observer => {
        this.status
          .filter(status => status === ConnectionStatus.Connected)
          .subscribe(() => {
            observer.next(this);
            observer.complete();
          });
    });
  }

  attach(model: IBaseModelConstructor) {
    Object.defineProperty(model, '_connection', {
      configurable: false,
      enumerable: false,
      writable: true,
      value: this
    });
    
    model.metadata.buildPropertyId(this.adapter.idPropertyName, this.adapter.idPropertyType);  
  }
  
  static init(options: IConnectionOptions): Observable<IConnection> {
    return this.create(options).init();
  }
  
  static create(options: IConnectionOptions): IConnection {
    return new this(options);
  }
}