/**
 * This class is a base for all id generators. It also provides lookup of id generators by
 * their id.
 * 
 * Generally, id generators are used to generate a primary key for new model instances. There
 * are different approaches to solving this problem, so this mechanism has both simple use
 * cases and is open to custom implementations. A {@link Ext.data.Model} requests id generation
 * using the {@link Ext.data.Model#identifier} property.
 *
 * The following types of `identifiers` are provided:
 *
 *   * `{@link Ext.data.identifier.Sequential sequential}`
 *   * `{@link Ext.data.identifier.Negative negative}`
 *   * `{@link Ext.data.identifier.Uuid uuid}`
 *
 * In most cases (other than `uuid`), the server is the only party that can generate
 * authoritative id values. This means that any id generated by an `identifier` should be
 * consider "provisional" and must eventually be reconciled with the server. This makes a
 * `uuid` very attractive as an `identifier` because they are designed to be generated in
 * a distributed manner and therefore never require reconciliation.
 *
 * It is common for id values to be generated as increasing integer values (1, 2, etc.) by
 * the server when records are inserted. A `{@link Ext.data.identifier.Negative negative}`
 * `identifier` may be useful as it generates client-side values of -1, -2, etc.. These
 * values are of the same data type (integer) and so can typically be read by servers
 * using typed languages (such as Java or C#) and easily recognized as provisional.
 *
 * In the end, the choice of `identifier` strategy requires agreement between client and
 * server.
 *
 * # Identity, Type and Shared Generators
 *
 * It is often desirable to share Generators to ensure uniqueness or common configuration.
 * This is done by giving Generator instances an id property by which they can be looked
 * up using the {@link Ext.Factory#dataIdentifier dataIdentifier} method. To configure two {@link Ext.data.Model Model} classes
 * to share one {@link Ext.data.identifier.Sequential sequential} id generator, you simply
 * assign them the same id:
 *
 *     Ext.define('MyApp.data.MyModelA', {
 *         extend: 'Ext.data.Model',
 *         identifier: {
 *             type: 'sequential',
 *             id: 'foo'
 *         }
 *     });
 *
 *     Ext.define('MyApp.data.MyModelB', {
 *         extend: 'Ext.data.Model',
 *         identifier: {
 *             type: 'sequential',
 *             id: 'foo'
 *         }
 *     });
 *
 * To make this as simple as possible for generator types that are shared by many (or all)
 * Models, the Generator types (such as 'sequential' or 'uuid') are also reserved as
 * generator ids. This is used by the {@link Ext.data.identifier.Uuid} which has an id equal
 * to its type ('uuid'). In other words, the following Models share the same generator:
 *
 *     Ext.define('MyApp.data.MyModelX', {
 *         extend: 'Ext.data.Model',
 *         identifier: 'uuid'
 *     });
 *
 *     Ext.define('MyApp.data.MyModelY', {
 *         extend: 'Ext.data.Model',
 *         identifier: 'uuid'
 *     });
 *
 * This can be overridden (by specifying the id explicitly), but there is no particularly
 * good reason to do so for this generator type.
 *
 * # Creating Custom Generators
 * 
 * An id generator should derive from this class and implement the {@link #generate} method.
 *
 * To register an id generator type, a derived class should provide an `alias` like so:
 *
 *     Ext.define('MyApp.data.identifier.Custom', {
 *         extend: 'Ext.data.identifier.Generator',
 *         alias: 'data.identifier.custom',
 *         config: {
 *             configProp: 42 // some config property w/default value
 *         }
 *
 *         generate: function () {
 *             return ... // a new id
 *         }
 *     });
 *
 * Using the custom id generator is then straightforward:
 *
 *     Ext.define('MyApp.data.MyModel', {
 *         extend: 'Ext.data.Model',
 *         identifier: 'custom'
 *     });
 *     // or...
 *
 *     Ext.define('MyApp.data.MyModel', {
 *         extend: 'Ext.data.Model',
 *         identifier: {
 *             type: 'custom',
 *             configProp: value
 *         }
 *     });
 *
 * It is not recommended to mix shared generators with generator configuration. This leads
 * to unpredictable results unless all configurations match (which is also redundant). In
 * such cases, a custom generator with a default id is the best approach.
 *
 *     Ext.define('MyApp.data.identifier.Custom', {
 *         extend: 'Ext.data.identifier.Sequential',
 *         alias: 'data.identifier.custom',
 *         
 *         config: {
 *             id: 'custom',
 *             prefix: 'ID_',
 *             seed: 1000
 *         }
 *     });
 *
 *     Ext.define('MyApp.data.MyModelX', {
 *         extend: 'Ext.data.Model',
 *         identifier: 'custom'
 *     });
 *
 *     Ext.define('MyApp.data.MyModelY', {
 *         extend: 'Ext.data.Model',
 *         identifier: 'custom'
 *     });
 *
 *     // the above models share a generator that produces ID_1000, ID_1001, etc..
 *
 */
Ext.define('Ext.data.identifier.Generator', {
    'abstract': true,

    mixins: [
        'Ext.mixin.Factoryable'
    ],

    alias: 'data.identifier.default',  // this is used by Factoryable

    factoryConfig: {
        defaultType: 'sequential'  // this is not a suitable type to create
    },

    /**
     * @property {Boolean} isGenerator
     * `true` in this class to identify an object as an instantiated IdGenerator, or subclass thereof.
     */
    isGenerator: true,

    config: {
        /**
         * @cfg {String} id
         * The id for this generator.
         */
        id: null
    },

    /**
     * Initializes a new instance.
     * @param {Object} config (optional) Configuration object to be applied to the new instance.
     */
    constructor: function (config) {
        var me = this,
            cache, id;

        me.initConfig(config);

        id = me.getId();
        if (id) {
            cache = (config && config.cache) || Ext.data.identifier.Generator.all;
            cache[id] = me;
        }
    },

    /**
     * Generates and returns the next id. This method must be implemented by the derived
     * class.
     *
     * @return {Number/String} The next id.
     * @method generate
     * @abstract
     */

    privates: {
        /**
         * Create a copy of this identifier.
         * @private
         * @return {Ext.data.identifier.Generator} The clone
         */
        clone: function (config) {
            var cfg = this.getInitialConfig();
            cfg = config ? Ext.apply({}, config, cfg) : cfg;
            return new this.self(cfg);
        },

        statics: {
            /**
             * @property {Object} all
             * This object is keyed by id to lookup instances.
             * @private
             * @static
             */
            all: {}
        }
    }
},
function () {
    var Generator = this,
        Factory = Ext.Factory,
        factory = Factory.dataIdentifier;

    // If there is an id property passed we need to lookup that id in the cache. If that
    // produces a cache miss, call the normal factory.
    /**
     * @member Ext.Factory
     * @method dataIdentifier
     * Returns an instance of an ID generator based on the ID you pass in.
     * @param {string} id
     * @return {Object} Ext.data.identifier.* The data identifier
     */
    Factory.dataIdentifier = function (config) {
        var id = Ext.isString(config) ? config : (config && config.id),
            existing = id && ((config && config.cache) || Generator.all)[id];

        return existing || factory(config);
    };
});
