/**
 * @class Ext.data.reader.Reader
 * @extend Ext.Base
 * @alias reader.base
 * @mixins Ext.mixin.Observable
 * @mixins Ext.mixin.Factoryable
 *
 * Readers are used to interpret data to be loaded into a {@link Ext.data.Model Model} instance or a {@link
 * Ext.data.Store Store} - often in response to an AJAX request. In general there is usually no need to create
 * a Reader instance directly, since a Reader is almost always used together with a {@link Ext.data.proxy.Proxy Proxy},
 * and is configured using the Proxy's {@link Ext.data.proxy.Proxy#cfg-reader reader} configuration property:
 * 
 *     Ext.create('Ext.data.Store', {
 *         model: 'User',
 *         proxy: {
 *             type: 'ajax',
 *             url : 'users.json',
 *             reader: {
 *                 type: 'json',
 *                 rootProperty: 'users'
 *             }
 *         },
 *     });
 *     
 * The above reader is configured to consume a JSON string that looks something like this:
 *  
 *     {
 *         "success": true,
 *         "users": [
 *             { "name": "User 1" },
 *             { "name": "User 2" }
 *         ]
 *     }
 * 
 *
 * # Loading Nested Data
 *
 * Readers have the ability to automatically load deeply-nested data objects based on the {@link Ext.data.schema.Association associations}
 * configured on each Model. Below is an example demonstrating the flexibility of these associations in a
 * fictional CRM system which manages a User, their Orders, OrderItems and Products. First we'll define the models:
 *
 *     Ext.define("User", {
 *         extend: 'Ext.data.Model',
 *         fields: [
 *             'id', 'name'
 *         ],
 *
 *         hasMany: {model: 'Order', name: 'orders'},
 *
 *         proxy: {
 *             type: 'rest',
 *             url : 'users.json',
 *             reader: {
 *                 type: 'json',
 *                 rootProperty: 'users'
 *             }
 *         }
 *     });
 *
 *     Ext.define("Order", {
 *         extend: 'Ext.data.Model',
 *         fields: [
 *             'id', 'total'
 *         ],
 *
 *         hasMany  : {model: 'OrderItem', name: 'orderItems', associationKey: 'order_items'},
 *         belongsTo: 'User'
 *     });
 *
 *     Ext.define("OrderItem", {
 *         extend: 'Ext.data.Model',
 *         fields: [
 *             'id', 'price', 'quantity', 'order_id', 'product_id'
 *         ],
 *
 *         belongsTo: ['Order', {model: 'Product', associationKey: 'product'}]
 *     });
 *
 *     Ext.define("Product", {
 *         extend: 'Ext.data.Model',
 *         fields: [
 *             'id', 'name'
 *         ],
 *
 *         hasMany: 'OrderItem'
 *     });
 *
 * This may be a lot to take in - basically a User has many Orders, each of which is composed of several OrderItems.
 * Finally, each OrderItem has a single Product. This allows us to consume data like this:
 *
 *     {
 *         "users": [
 *             {
 *                 "id": 123,
 *                 "name": "Ed",
 *                 "orders": [
 *                     {
 *                         "id": 50,
 *                         "total": 100,
 *                         "order_items": [
 *                             {
 *                                 "id"      : 20,
 *                                 "price"   : 40,
 *                                 "quantity": 2,
 *                                 "product" : {
 *                                     "id": 1000,
 *                                     "name": "MacBook Pro"
 *                                 }
 *                             },
 *                             {
 *                                 "id"      : 21,
 *                                 "price"   : 20,
 *                                 "quantity": 3,
 *                                 "product" : {
 *                                     "id": 1001,
 *                                     "name": "iPhone"
 *                                 }
 *                             }
 *                         ]
 *                     }
 *                 ]
 *             }
 *         ]
 *     }
 *
 * The JSON response is deeply nested - it returns all Users (in this case just 1 for simplicity's sake), all of the
 * Orders for each User (again just 1 in this case), all of the OrderItems for each Order (2 order items in this case),
 * and finally the Product associated with each OrderItem. Now we can read the data and use it as follows:
 *
 *     var store = Ext.create('Ext.data.Store', {
 *         model: "User"
 *     });
 *
 *     store.load({
 *         callback: function() {
 *             //the user that was loaded
 *             var user = store.first();
 *
 *             console.log("Orders for " + user.get('name') + ":")
 *
 *             //iterate over the Orders for each User
 *             user.orders().each(function(order) {
 *                 console.log("Order ID: " + order.getId() + ", which contains items:");
 *
 *                 //iterate over the OrderItems for each Order
 *                 order.orderItems().each(function(orderItem) {
 *                     //we know that the Product data is already loaded, so we can use the synchronous getProduct
 *                     //usually, we would use the asynchronous version (see #belongsTo)
 *                     var product = orderItem.getProduct();
 *
 *                     console.log(orderItem.get('quantity') + ' orders of ' + product.get('name'));
 *                 });
 *             });
 *         }
 *     });
 *
 * Running the code above results in the following:
 *
 *     Orders for Ed:
 *     Order ID: 50, which contains items:
 *     2 orders of MacBook Pro
 *     3 orders of iPhone
 */
 
/**
 * @cfg {String/Function} [groupRootProperty=""]
 * Name of the property from which to retrieve remote grouping summary information.
 * There should be an item for each group.
 *
 * The remote summary data should be parseable as a {@link #model} used by this reader.
 * @accessor
 */
 
/**
 * @cfg {Boolean} [implicitIncludes=true]
 * True to automatically parse models nested within other models in a response object. See the
 * Ext.data.reader.Reader intro docs for full explanation.
 * @accessor
 */
 
/**
 * @cfg {Boolean} [keepRawData] Determines if the Reader will keep raw data
 * received from the server in the {@link #rawData} property.
 *
 * While this might seem useful to do additional data processing, keeping raw data
 * might cause adverse effects such as memory leaks. It is recommended to set
 * `keepRawData` to `false` if you do not need the raw data.
 *
 * If you need to process data packet to extract additional data such as row summaries,
 * it is recommended to use {@link #transform} function for that purpose.
 *
 * Note that starting with Ext JS 6.0 the default behavior has been changed to
 * **not** keep the raw data because of the high potential for memory leaks.
 * @since 5.1.1
 * @accessor
 */
 
/**
 * @cfg {String/Function} [messageProperty=""]
 * The name of the property which contains a response message for exception handling. If you want to return a false success
 * response from the server, maybe due to some server-side validation, the messageProperty can hold the error message. For
 * example:
 *
 *     {
 *         "success": false,
 *         "error": "There was an error with your request"
 *     }
 *
 * You can retrieve this error message in a callback when loading a {@link Ext.data.Store Store} or {@link Ext.data.Model Model} like:
 *
 *     var store = new Ext.data.Store({
 *         fields : ['foo'],
 *         proxy  : {
 *             type   : 'ajax',
 *             url    : 'data.json',
 *             reader : {
 *                 type            : 'json',
 *                 rootProperty    : 'data',
 *                 messageProperty : 'error'
 *             }
 *         }
 *     });
 *
 *     store.load({
 *         callback: function(records, operation, success) {
 *             if (success) {
 *                 // ...
 *             } else {
 *                 var error = operation.getError();
 *
 *                 Ext.Msg.alert('Error', error);
 *             }
 *         }
 *     });
 *
 * In this example, the callback will execute with `success` being `false` and will therefore show the {@link Ext.MessageBox#alert Ext.Msg.alert} with
 * the error string returned in the response.
 * @accessor
 */
 
/**
 * @cfg {String/Ext.data.Model} [model]
 * The model to use for this reader. This config is only required if the reader is being used
 * without a proxy, otherwise the proxy will automatically set the model.
 * @accessor
 */
 
/**
 * @cfg {Boolean} [readRecordsOnFailure=true]
 * True to extract the records from a data packet even if the {@link #successProperty} returns false.
 * @accessor
 */
 
/**
 * @cfg {String/Function} rootProperty
 * The property that contains data items corresponding to the
 * Model(s) of the configured Reader. `rootProperty` varies by Reader type.
 *
 * ##JSON Reader
 * `rootProperty` is a property name. It may also be a dot-separated
 * list of property names if the root is nested. The root JSON array will be
 * used by default.
 *
 *     // rootPropety config
 *     rootProperty: 'embedded.myresults'
 *
 *     // server response
 *     {
 *         embedded: {
 *             myresults: [{
 *                 name: 'Scott',
 *                 age: 22
 *             }, {
 *                 name: 'Ramona',
 *                 age: 24
 *             }]
 *         },
 *         success: true
 *     }
 *
 * ##XML Reader
 * `rootProperty` is a CSS selector. The root XML element will be used
 * by default.
 *
 *     // rootProperty config (plus record config)
 *     rootProperty: 'myresults',
 *     record: 'user'
 *
 *     // server response
 *     <?xml version="1.0" encoding="UTF-8"?>
 *     <embedded>
 *         <myresults>
 *             <user>
 *                 <name>Scott</name>
 *                 <age>22</age>
 *             </user>
 *             <user>
 *                 <name>Ramona</name>
 *                 <age>24</age>
 *             </user>
 *         </myresults>
 *     </embedded>
 *
 * ##Array Reader
 * `rootProperty` is not typically applicable since the data is assumed to be a
 * single-level array of arrays.  However, if the array of records is returned
 * within a JSON response a `rootProperty` config may be used:
 *
 *     // rootProperty config
 *     rootProperty: 'embedded.myresults'
 *
 *     // server response
 *     {
 *         embedded: {
 *             myresults: [['Scott', 22], ['Ramona', 24]]
 *         },
 *         success: true
 *     }
 *
 * ##rootProperty as a function
 * The `rootProperty` may also be a function that returns the root node from
 * the dataset. For example:
 *
 *     var store = Ext.create('Ext.data.TreeStore', {
 *         proxy: {
 *             type: 'memory',
 *             reader: {
 *                 type: 'json',
 *                 rootProperty: function(data){
 *                     // Extract child nodes from the items or children property in the dataset
 *                     return data.items || data.children;
 *                 }
 *             }
 *         },
 *         data: {
 *             items: [{
 *                 text: 'item 1',
 *                 children: [{
 *                     text: 'child A',
 *                     leaf: true
 *                 }]
 *             }]
 *         }
 *     });
 *
 *     Ext.create('Ext.tree.Panel', {
 *         title: 'rootProperty as a function',
 *         width: 200,
 *         height:150,
 *         store: store,
 *         rootVisible: false,
 *         renderTo: Ext.getBody()
 *     });
 *
 * @accessor
 */
 
/**
 * @cfg {String} [successProperty="success"]
 * Name of the property from which to retrieve the `success` attribute, the value of which indicates
 * whether a given request succeeded or failed (typically a boolean or 'true'|'false'). See
 * {@link Ext.data.proxy.Server}.{@link Ext.data.proxy.Server#exception exception} for additional information.
 * @accessor
 */
 
/**
 * @cfg {String/Function} [summaryRootProperty=""]
 * Name of the property from which to retrieve remote summary information.
 *
 * The remote summary data should be parseable as a {@link #model} used by this reader.
 * @accessor
 */
 
/**
 * @cfg {String} [totalProperty="total"]
 * Name of the property from which to retrieve the total number of records in the dataset. This is only needed if
 * the whole dataset is not passed in one go, but is being paged from the remote server.
 * @accessor
 */
 
/**
 * @cfg {Function|String|Object} [transform]
 * If a transform function is set, it will be invoked just before {@link #readRecords} executes.
 * It is passed the raw (deserialized) data object. The transform function returns a data object, which can be
 * a modified version of the original data object, or a completely new data object. The transform can
 * be a function, or a method name on the Reader instance, or an object with a 'fn' key
 * and an optional 'scope' key.
 *
 * Example usage:
 *
 *     Ext.create('Ext.data.Store', {
 *         model: 'User',
 *         proxy: {
 *             type: 'ajax',
 *             url : 'users.json',
 *             reader: {
 *                 type: 'json',
 *                 transform: {
 *                     fn: function(data) {
 *                         // do some manipulation of the raw data object
 *                         return data;
 *                     },
 *                     scope: this
 *                 }
 *             }
 *         },
 *     });
 *
 * @accessor
 */
 
/**
* @cfg {String} [typeProperty]
* The name of the property in a node raw data block which indicates the type of the model to be created from that raw data. Useful for heterogeneous trees.
*
* For example, hierarchical geographical data may look like this:
*
*     {
*         nodeType: 'Territory',
*         name: 'EMEA',
*         children: [{
*             nodeType: 'Country',
*             name: 'United Kingdon',
*             children: [{
*                 nodeType: 'City',
*                 name: 'London'
*             }]
*         }]
*     }
*
* You would configure the typeProperty in this case to be `"nodeType"` which would cause the models named "Territory", "Country" and "City" to
* be used.
* @accessor
*/
 
/**
 * @property {Object} rawData 
 * The raw data object that was last passed to {@link #readRecords}. rawData is populated
 * based on the results of {@link Ext.data.proxy.Server#processResponse}. rawData will
 * maintain a cached copy of the last successfully returned records. In other words,
 * if processResponse is unsuccessful, the records from the last successful response
 * will remain cached in rawData.
 *
 * Since Ext JS 5.1.1 you can use the {@link #keepRawData} config option to
 * control this behavior.
 */
 
/**
 * @property {Object} metaData 
 * The raw meta data that was most recently read, if any. Meta data can include existing
 * Reader config options like {@link #totalProperty}, etc. that get
 * automatically applied to the Reader, and those can still be accessed directly from the Reader
 * if needed. However, meta data is also often used to pass other custom data to be processed
 * by application code. For example, it is common when reconfiguring the data model of a grid to
 * also pass a corresponding column model config to be applied to the grid. Any such data will
 * not get applied to the Reader directly (it just gets passed through and is ignored by Ext).
 * This metaData property gives you access to all meta data that was passed, including any such
 * custom data ignored by the reader.
 *
 * This is a read-only property, and it will get replaced each time a new meta data object is
 * passed to the reader. Note that typically you would handle proxy's
 * {@link Ext.data.proxy.Proxy#metachange metachange} event which passes this exact same meta
 * object to listeners. However this property is available if it's more convenient to access it
 * via the reader directly in certain cases.
 * @readonly
 */
    
/**
 * @property {Boolean} [isReader=true]
 * `true` in this class to identify an object as an instantiated Reader, or subclass thereof.
 */
 
/**
 * @event exception
 * Fires when the reader receives improperly encoded data from the server
 * @param {Ext.data.reader.Reader} reader A reference to this reader
 * @param {XMLHttpRequest} response The XMLHttpRequest response object
 * @param {Ext.data.ResultSet} error The error object
 */
 
/**
 * @method constructor
 * Creates new Reader.
 * @param {Object} [config] Config object.
 */
 
/**
 * @method read
 * Reads the given response object. This method normalizes the different types of response object that may be passed to it.
 * If it's an XMLHttpRequest object, hand off to the subclass' {@link #getResponseData} method.
 * Else, hand off the reading of records to the {@link #readRecords} method.
 * @param {Object} response The response object. This may be either an XMLHttpRequest object or a plain JS object
 * @param {Object} [readOptions] Various options that instruct the reader on how to read the data
 * @param {Function} [readOptions.recordCreator] A function to construct the model based on the processed data. By default,
 * this just calls the model constructor and passes the raw data.
 * @return {Ext.data.ResultSet} The parsed or default ResultSet object
 */
 
/**
 * @method readRecords
 * Abstracts common functionality used by all Reader subclasses. Each subclass is expected to call this function
 * before running its own logic and returning the Ext.data.ResultSet instance. For most Readers additional
 * processing should not be needed.
 * @param {Object} data The raw data object
 * @param {Object} [readOptions] See {@link #read} for details.
 * @param {Object} [internalReadOptions] (private)
 * @return {Ext.data.ResultSet} A ResultSet object
 */
 
/**
 * @method getResponseData
 * Takes a raw response object (as passed to the {@link #read} method) and returns the useful data
 * segment from it. This must be implemented by each subclass.
 * @param {Object} response The response object
 * @return {Object} The extracted data from the response. For example, a JSON object or an XML document.
 */