import Ember from 'ember';
import DS from 'ember-data';

import MegamorphicModel from '../model';
import M3ModelData from '../model-data';
import MegamorphicModelFactory from '../factory';
import SchemaManager from '../schema-manager';
import QueryCache from '../query-cache';

let hasReopened = false;

export function extendStore(Store) {
  Store.reopen({
    init() {
      this._super(...arguments);
      this._queryCache = new QueryCache({ store: this });
      this._globalM3Cache = new Object(null);
    },

    // Store hooks necessary for using a single model class

    _hasModelFor(modelName) {
      return SchemaManager.includesModel(modelName) || this._super(modelName);
    },

    modelFactoryFor(modelName) {
      if (SchemaManager.includesModel(modelName)) {
        return MegamorphicModelFactory;
      }
      return this._super(modelName);
    },

    adapterFor(modelName) {
      if (SchemaManager.includesModel(modelName)) {
        return this._super('-ember-m3');
      }
      return this._super(modelName);
    },

    serializerFor(modelName) {
      if (SchemaManager.includesModel(modelName)) {
        return this._super('-ember-m3');
      }
      return this._super(modelName);
    },

    createModelDataFor(modelName, id, clientId, storeWrapper) {
      if (SchemaManager.includesModel(modelName)) {
        return new M3ModelData(modelName, id, clientId, storeWrapper, this);
      }
      return this._super(modelName, id, clientId, storeWrapper);
    },

    // queryURL store API

    queryURL(url, options) {
      return this._queryCache.queryURL(url, options);
    },

    unloadURL(cacheKey) {
      return this._queryCache.unloadURL(cacheKey);
    },

    containsURL(cacheKey) {
      return this._queryCache.contains(cacheKey);
    },

    // These two hooks are used for the secondary cache
    // TODO: make secondary caches possible via public API

    _pushInternalModel(jsonAPIResource) {
      let internalModel = this._super(jsonAPIResource);
      if (SchemaManager.includesModel(jsonAPIResource.type)) {
        this._globalM3Cache[internalModel.id] = internalModel;
      }
      return internalModel;
    },

    _removeFromIdMap(internalModel) {
      delete this._globalM3Cache[internalModel.id];
      return this._super(internalModel);
    },
  });
}

export function extendDataAdapter(DataAdapter) {
  DataAdapter.reopen({
    getModelTypes() {
      return this._super(...arguments).concat({
        klass: MegamorphicModel,
        name: '-ember-m3',
      });
    },

    _nameToClass(modelName) {
      if (SchemaManager.includesModel(modelName)) {
        return MegamorphicModel;
      }
      return this._super(...arguments);
    },
  });
}

export function initialize() {
  if (hasReopened === true) {
    return;
  }

  hasReopened = true;
  extendStore(DS.Store);
  extendDataAdapter(Ember.DataAdapter);
}

export default {
  name: 'm3-store',
  initialize,
  after: 'm3-schema-initializer',
};

@@ -275,31 +275,67 @@
 ';%0A%0A
-let hasReopened = false
+extendStore(DS.Store);%0AextendDataAdapter(Ember.DataAdapter)
 ;%0A%0Ae
@@ -2779,143 +2779,8 @@
 () %7B
-%0A  if (hasReopened === true) %7B%0A    return;%0A  %7D%0A%0A  hasReopened = true;%0A  extendStore(DS.Store);%0A  extendDataAdapter(Ember.DataAdapter);%0A
 %7D%0A%0Ae

Clean up module-scoped init