var _ = require('underscore');
var Backbone = require('backbone');
var CartoError = require('../error-handling/carto-error');
var EVENTS = require('../events');

/**
 * Base data source object.
 *
 * @constructor
 * @fires error
 * @abstract
 * @memberof carto.source
 * @api
 */
function Base () {
  this._id = Base.$generateId();
}

_.extend(Base.prototype, Backbone.Events);

/**
 * The instance id will be autogenerated by incrementing this variable.
 */
Base.$nextId = 0;

/**
 * Static funciton used internally to autogenerate source ids.
 */
Base.$generateId = function () {
  return 'S' + ++Base.$nextId;
};

/**
 * Return a unique autogenerated id.
 * 
 * @return {string} Unique autogenerated id
 */
Base.prototype.getId = function () {
  return this._id;
};

Base.prototype._createInternalModel = function (engine) {
  throw new Error('_createInternalModel must be implemented by the particular source');
};

/**
 * Fire a CartoError event from a internalError
 */
Base.prototype._triggerError = function (model, internalError) {
  this.trigger(EVENTS.ERROR, new CartoError(internalError, { analysis: this }));
};

Base.prototype.$setEngine = function (engine) {
  if (!this._internalModel) {
    this._internalModel = this._createInternalModel(engine);
    this._internalModel.on('change:error', this._triggerError, this);
  }
};

/**
 * Return the engine form the source internal model
 */
Base.prototype.$getEngine = function (engine) {
  if (this._internalModel) {
    return this._internalModel._engine;
  }
};

/**
 * Return the real CARTO.js model used by the source.
 */
Base.prototype.$getInternalModel = function () {
  return this._internalModel;
};

module.exports = Base;

var _ = require('underscore');
var Backbone = require('backbone');
var CartoError = require('../error-handling/carto-error');
var EVENTS = require('../events');

/**
 * Base data source object.
 * 
 * The methods listed in the {@link carto.source.Base|source.Base} object are availiable in all source objects.
 * 
 * Use a source to reference the data used in a {@link carto.dataview.Base|dataview} or a {@link carto.layer.Base|layer}.
 *  
 * {@link carto.source.Base} should not be used directly use {@link carto.source.Dataset} or {@link carto.source.SQL} instead.
 *
 * @constructor
 * @fires error
 * @abstract
 * @memberof carto.source
 * @api
 */
function Base () {
  this._id = Base.$generateId();
}

_.extend(Base.prototype, Backbone.Events);

/**
 * The instance id will be autogenerated by incrementing this variable.
 */
Base.$nextId = 0;

/**
 * Static funciton used internally to autogenerate source ids.
 */
Base.$generateId = function () {
  return 'S' + ++Base.$nextId;
};

/**
 * Return a unique autogenerated id.
 * 
 * @return {string} Unique autogenerated id
 */
Base.prototype.getId = function () {
  return this._id;
};

Base.prototype._createInternalModel = function (engine) {
  throw new Error('_createInternalModel must be implemented by the particular source');
};

/**
 * Fire a CartoError event from a internalError
 */
Base.prototype._triggerError = function (model, internalError) {
  this.trigger(EVENTS.ERROR, new CartoError(internalError, { analysis: this }));
};

Base.prototype.$setEngine = function (engine) {
  if (!this._internalModel) {
    this._internalModel = this._createInternalModel(engine);
    this._internalModel.on('change:error', this._triggerError, this);
  }
};

/**
 * Return the engine form the source internal model
 */
Base.prototype.$getEngine = function (engine) {
  if (this._internalModel) {
    return this._internalModel._engine;
  }
};

/**
 * Return the real CARTO.js model used by the source.
 */
Base.prototype.$getInternalModel = function () {
  return this._internalModel;
};

module.exports = Base;

Document carto.source.Base