/*
 * Copyright (C) 2018 Robert Bosch GmbH Copyright (C) 2018 Robert Bosch Manufacturing Solutions GmbH, Germany. All rights reserved.
 */

import { GridsterItem } from 'angular-gridster2';
import { Observable, Subject } from 'rxjs';
import { UserSettingChangeEvent } from './user-setting-change-event';
import { UserSetting } from './userSetting';
import { WidgetContentComponent } from './widget-content-component';
import { WidgetDefinition } from './widget-definition';
import { WidgetFilter } from './widget-filter';

/**
 * The Widget class holds the instance configurations, settings, informations
 */
export class Widget<T extends WidgetContentComponent = any, C = any, S = any> {
  /**
   * Unique identfier
   * Newly added widgets by the user will have the id "newWidget"
   */
  public id = '';
  /**
   * WidgetDefinition which belongs to the Widget
   */
  public widgetDefinition: WidgetDefinition<T, C, S>;
  /**
   * An array of filters passed from outside in order to be passed to each widget
   */
  public widgetFilters: Array<WidgetFilter>;
  /**
   * Title which will be displayed in the widget menu bar
   */
  public title = '';
  /**
   * Show/ hide the tile which will be displayed in the widget menu bar
   */
  public showWidgetTitle = true;
  /**
   * Will be bound to gridster, to modify the widget on the grid use the gridster api
   */
  public gridsterItem: GridsterItem = { x: 0, y: 0, cols: 1, rows: 1 };
  public settings: S = {} as S;
  /**
   * Holds the "selected" values of the usersettings
   */
  private userSettingsValues: C = {} as C;
  /**
   * Subject for emitting user config changes
   */
  private userSettingChangedSubject: Subject<UserSettingChangeEvent> = new Subject<UserSettingChangeEvent>();
  /**
   * Emitted, when a usersetting changed
   */
  public userSettingChanged: Observable<UserSettingChangeEvent> = this.userSettingChangedSubject.asObservable();
  /**
   * Subject for emitting save button click on the widget settings component
   */
  private widgetSavedSubject: Subject<void> = new Subject<void>();
  /**
   * Emitted, when a user clicks on the save button of the widget settings component
   */
  public widgetSaved: Observable<void> = this.widgetSavedSubject.asObservable();
  /**
   * Subject for emitting save button click on the widget settings component
   */
  public widgetFiltersChangedSubject: Subject<void> = new Subject<void>();
  /**
   * Emitted, when a user clicks on the save button of the widget settings component
   */
  public widgetFiltersChanged: Observable<void> = this.widgetFiltersChangedSubject.asObservable();
  /**
   * whether the widget listens to the pinboard filter
   */
  public isLinkedToFilter = true;
  /**
   * Used when user provides a set custom sizes
   */
  private customSizeArray: number[];
  /**
   * Gets the custom size array
   */
  public get sizeArray(): number[] {
    return this.customSizeArray;
  }

  /**
   * Sets size for a widget from the custom size options provided by the user
   */
  public set sizeArray(sizeArray: number[]) {
    if (sizeArray) {
      this.customSizeArray = sizeArray;
      this.gridsterItem.rows = sizeArray[0];
      this.gridsterItem.cols = sizeArray[1];
    }
  }

  constructor(id?: string) {
    if (id) {
      this.id = id;
    }
  }

  /**
   * Sets a settings value to the widget model config and triggers the widget's setting change event
   */
  public setUserSettingValue(setting: UserSetting, value: any): void {
    this.userSettingsValues[setting.id] = value;
    this.userSettingChangedSubject.next({ newValue: value, widget: this, setting: setting });
  }

  /**
   * Gives the values of a setting saved in the widget model
   * @param settingId UserSetting ID
   */
  public getUserSettingValue(settingId: string): any {
    return this.userSettingsValues[settingId];
  }

  /**
   * Returns the whole config object
   * Be careful on editing, no events will be emitted!
   */
  public getUserSettingsObject(): C {
    return this.userSettingsValues;
  }

  /**
   * Emits the widgetSaved Observable
   */
  public saveWidget(): void {
    this.widgetSavedSubject.next();
  }
}
