Searching for models into client cache

Change-Id: Ib65b1565153040684083fbc21a59e8c8365628fd
diff --git a/src/app/datasources/helpers/search.service.ts b/src/app/datasources/helpers/search.service.ts
new file mode 100644
index 0000000..8cd98a7
--- /dev/null
+++ b/src/app/datasources/helpers/search.service.ts
@@ -0,0 +1,62 @@
+import * as _ from 'lodash';
+import {IXosNavigationService} from '../../core/services/navigation';
+import {IXosState} from '../../../index';
+import {IModelStoreService} from '../stores/model.store';
+import {IXosConfigHelpersService} from '../../core/services/helpers/config.helpers';
+
+export interface IXosSearchResult {
+  label: string;
+  state: string | {name: string, params: any};
+  type?: string;
+}
+
+export interface IXosSearchService {
+  search(query: string): IXosSearchResult[];
+}
+
+export class SearchService {
+  static $inject = ['$rootScope', 'NavigationService', 'ModelStore', 'ConfigHelpers'];
+  private states: IXosState[];
+
+  constructor (
+    private $rootScope: ng.IScope,
+    private NavigationService: IXosNavigationService,
+    private ModelStore: IModelStoreService,
+    private ConfigHelpers: IXosConfigHelpersService
+  ) {
+    this.$rootScope.$on('xos.core.modelSetup', () => {
+      this.states = this.NavigationService.query().reduce((list, state) => {
+        // if it does not have child (otherwise it is abstract)
+        if (!state.children || state.children.length === 0) {
+          list.push(state);
+        }
+        // else push child
+        if (state.children && state.children.length > 0) {
+          state.children.forEach(c => {
+            list.push(c);
+          });
+        }
+        return list;
+      }, []);
+      this.states = _.uniqBy(this.states, 'state');
+    });
+  }
+
+  public search(query: string): IXosSearchResult[] {
+    const routes: IXosSearchResult[] = _.filter(this.states, s => {
+      return s.label.toLowerCase().indexOf(query) > -1;
+    }).map(r => {
+      r.type = 'View';
+      return r;
+    });
+
+    const models = _.map(this.ModelStore.search(query), m => {
+      return {
+        label: m.humanReadableName ? m.humanReadableName : m.name,
+        state: this.ConfigHelpers.stateWithParamsForJs(m.modelName, m),
+        type: m.modelName
+      };
+    });
+    return routes.concat(models);
+  }
+}
diff --git a/src/app/datasources/index.ts b/src/app/datasources/index.ts
index 7a14a9a..04c58db 100644
--- a/src/app/datasources/index.ts
+++ b/src/app/datasources/index.ts
@@ -6,6 +6,7 @@
 import {SynchronizerStore} from './stores/synchronizer.store';
 import {ModeldefsService} from './rest/modeldefs.rest';
 import {xosCore} from '../core/index';
+import {SearchService} from './helpers/search.service';
 
 export const xosDataSources = 'xosDataSources';
 
@@ -13,11 +14,9 @@
   .module('xosDataSources', ['ngCookies', 'ngResource', xosCore])
   .service('ModelRest', ModelRest)
   .service('AuthService', AuthService)
-  .service('WebSocket', WebSocketEvent);
-
-angular
-  .module('xosDataSources')
+  .service('WebSocket', WebSocketEvent)
   .service('StoreHelpers', StoreHelpers)
   .service('SynchronizerStore', SynchronizerStore)
   .service('ModelStore', ModelStore)
-  .service('ModelDefs', ModeldefsService);
+  .service('ModelDefs', ModeldefsService)
+  .service('SearchService', SearchService);
diff --git a/src/app/datasources/stores/model.store.ts b/src/app/datasources/stores/model.store.ts
index fdcac63..4c6c09d 100644
--- a/src/app/datasources/stores/model.store.ts
+++ b/src/app/datasources/stores/model.store.ts
@@ -1,5 +1,5 @@
 /// <reference path="../../../../typings/index.d.ts"/>
-
+import * as _ from 'lodash';
 import {BehaviorSubject, Observable} from 'rxjs/Rx';
 import {IWSEvent, IWSEventService} from '../websocket/global';
 import {IXosResourceService} from '../rest/model.rest';
@@ -7,6 +7,7 @@
 
 export interface  IModelStoreService {
   query(model: string): Observable<any>;
+  search(modelName: string): any[];
 }
 
 export class ModelStore {
@@ -39,6 +40,26 @@
     return this._collections[model].asObservable();
   }
 
+  public search(modelName: string): any[] {
+    return _.reduce(Object.keys(this._collections), (results, k) => {
+      // console.log(k, this._collections[k].value)
+      const partialRes = _.filter(this._collections[k].value, i => {
+        if (i.humanReadableName) {
+          return i.humanReadableName.toLowerCase().indexOf(modelName) > -1;
+        }
+        else if (i.name) {
+          return i.name.toLowerCase().indexOf(modelName) > -1;
+        }
+        return false;
+      })
+        .map(m => {
+          m.modelName = k;
+          return m;
+        });
+      return results.concat(partialRes);
+    }, []);
+  }
+
   public get(model: string, id: number) {
     // TODO implement a get method
   }