/*
This file is part of Ext JS 4.2

Copyright (c) 2011-2013 Sencha Inc

Contact:  http://www.sencha.com/contact

GNU General Public License Usage
This file may be used under the terms of the GNU General Public License version 3.0 as
published by the Free Software Foundation and appearing in the file LICENSE included in the
packaging of this file.

Please review the following information to ensure the GNU General Public License version 3.0
requirements will be met: http://www.gnu.org/copyleft/gpl.html.

If you are unsure which license is appropriate for your use, please contact the sales department
at http://www.sencha.com/contact.

Build date: 2013-05-16 14:36:50 (f9be68accb407158ba2b1be2c226a6ce1f649314)
*/
/*
 * This file is generated by Sencha Cmd and should NOT be edited. It will be replaced
 * during an upgrade.
 */

Ext.require([
    'Ext.layout.Context',
]);

Ext.theme = {
    /**
     * The array of all component manifests. These objects have the following set of
     * properties recognized by the slicer:
     * @private
     */
    _manifest: [],

    /**
     * The collection of shortcuts for a given alias (e.g., 'widget.panel'). This is an
     * object keyed by alias whose values are arrays of shortcut definitions.
     * @private
     */
    _shortcuts: {},

    doRequire : function(xtype) {
        if(xtype.indexOf("widget.") != 0) {
            xtype = "widget." + xtype;
        }
        Ext.require([xtype]);
    },

    /**
     * Adds one ore more component entries to the theme manifest. These entries will be
     * instantiated by the `Ext.theme.render` method when the page is ready.
     * 
     * Usage:
     * 
     *      Ext.theme.addManifest({
     *              xtype: 'widget.menu',
     *              folder: 'menu',
     *              delegate: '.x-menu-item-link',
     *              filename: 'menu-item-active',
     *              config: {
     *                  floating: false,
     *                  width: 200,
     *                  items: [{
     *                      text: 'test',
     *                      cls: 'x-menu-item-active'
     *                  }]
     *              }
     *          },{
     *              //...
     *          });
     * 
     * @param manifest {Object} An object with type of component, slicing information and
     * component configuration. If this parameter is an array, each element is treated as
     * a manifest entry. Otherwise, each argument passed is treated as a manifest entry.
     * 
     * @param manifest.xtype {String} The xtype ('grid') or alias ('widget.grid'). This
     * is used to specify the type of component to create as well as a potential key to
     * any `shortcuts` defined for the xtype.
     * 
     * @param manifest.config {Object} The component configuration object. The properties
     * of this depend on the `xtype` of the component.
     * 
     * @param [manifest.delegate] {String} The DOM query to use to select the element to
     * slice. The default is to slice the primary element of the component.
     * 
     * @param [manifest.parentCls] An optional CSS class to add to the parent of the
     * component.
     * 
     * @param [manifest.setup] {Function} An optional function to be called to initialize
     * the component.
     * @param manifest.setup.component {Ext.Component} The component instance
     * @param manifest.setup.container {Element} The component's container.
     * 
     * @param [manifest.folder] {String} The folder in to which to produce image slices.
     * Only applies to Ext JS 4.1 (removed in 4.2).
     * 
     * @param [manifest.filename] {String} The base filename for slices.
     * Only applies to Ext JS 4.1 (removed in 4.2).
     * 
     * @param [manifest.reverse] {Boolean} True to position the slices for linear gradient
     * background at then opposite "end" (right or bottom) and apply the stretch to the
     * area before it (left or top). Only applies to Ext JS 4.1 (removed in 4.2).
     */
    addManifest: function (manifest) {
        var all = Ext.theme._manifest;
        var add = Ext.isArray(manifest) ? manifest : arguments;

        if(manifest.xtype) {
            Ext.theme.doRequire(manifest.xtype);
        }

        for (var i = 0, n = add.length; i < n; ++i) {
            all.push(add[i]);
        }
    },

    /**
     * Adds one or more shortcuts to the rendering process. A `shortcut` is an object that
     * looks the same as a `manifest` entry. These are combined by copying the properties
     * from the shortcut over those of the manifest entry. In basic terms:
     * 
     *      var config = Ext.apply(Ext.apply({}, manfiest.config), shortcut.config);
     *      var entry = Ext.apply(Ext.apply({}, manfiest), shortcut);
     *      entry.config = config;
     * 
     * This is not exactly the process, but the idea is the same. The difference is that
     * the `ui` of the manifest entry is used to replace any `"{ui}"` substrings found in
     * any string properties of the shortcut or its `config` object.
     * 
     * Usage:
     * 
     *      Ext.theme.addShortcuts({
     *          'widget.foo': [{
     *                  config: {
     *                  }
     *              },{
     *                  config: {
     *                  }
     *              }],
     *
     *          'widget.bar': [ ... ]
     *      });
     */
    addShortcuts: function (shortcuts) {
        var all = Ext.theme._shortcuts;

        for (var key in shortcuts) {
            
            var add = shortcuts[key];
            var xtype = Ext.theme.addWidget(key);
            var existing = all[xtype];

            Ext.theme.doRequire(xtype);
            for(var i=0; i < add.length; i++) {
                var config = add[i];
                if(config.xtype) {
                    Ext.theme.doRequire(config.xtype);
                }
            }
            
            if (!existing) {
                all[xtype] = existing = [];
            }

            existing.push.apply(existing, add);
        }
    },

    /**
     * This method ensures that a given string has the specified prefix (e.g., "widget.").
     * @private
     */
    addPrefix: function (prefix, s) {
        if (!s || (s.length > prefix.length && s.substring(0,prefix.length) === prefix)) {
            return s;
        }
        return prefix + s;
    },

    /**
     * This method returns the given string with "widget." added to the front if that is
     * not already present.
     * @private
     */
    addWidget: function (str) {
        return Ext.theme.addPrefix('widget.', str);
    },

    /**
     * This method accepts an manifest entry and a shortcut entry and returns the merged
     * version.
     * @private
     */
    applyShortcut: function (manifestEntry, shortcut) {
        var ui = manifestEntry.ui;
        var config = Ext.theme.copyProps({}, manifestEntry.config);
        var entry = Ext.theme.copyProps({}, manifestEntry);

        if (ui && !config.ui) {
            config.ui = ui;
        }
        if (shortcut) {
            var tpl = { ui: ui };
            Ext.theme.copyProps(entry, shortcut, tpl);
            Ext.theme.copyProps(config, shortcut.config, tpl);
        }

        entry.xtype = Ext.theme.addWidget(entry.xtype);
        entry.config = config; // both guys have "config" so smash merged one on now...
        return entry;
    },

    /**
     * This method copies property from a `src` object to a `dest` object and reaplces
     * `"{foo}"` fragments of any string properties as defined in the `tpl` object.
     * 
     *      var obj = Ext.theme.copyProps({}, {
     *                      foo: 'Hello-{ui}'
     *                  }, {
     *                      ui: 'World'
     *                  });
     *
     *      console.log('obj.foo: ' + obj.foo); // logs "Hello-World"
     *
     * @return {Object} The `dest` object or a new object (if `dest` was null). 
     * @private
     */
    copyProps: function (dest, src, tpl) {
        var out = dest || {};
        var replacements = [];
        var token;

        if (src) {
            if (tpl) {
                for (token in tpl) {
                    replacements.push({
                        re: new RegExp('\\{' + token + '\\}', 'g'),
                        value: tpl[token]
                    });
                }
            }

            for (var key in src) {
                var val = src[key];
                if (tpl && typeof val === 'string') {
                    for (var i = 0; i < replacements.length; ++ i) {
                        val = val.replace(replacements[i].re, replacements[i].value);
                    }
                }
                out[key] = val;
            }
        }

        return out;
    },

    /**
     * Renders a component given its manifest and shortcut entries.
     * @private
     */
    renderWidget: function (manifestEntry, shortcut) {
        var entry = Ext.theme.applyShortcut(manifestEntry, shortcut);
        var config = entry.config;
        var widget = Ext.create(entry.xtype, config);
        var ct = Ext.fly(document.body).createChild({ cls: 'widget-container' });

        Ext.theme.currentWidget = widget;

        if (widget.floating === true) {
            widget.floating = { shadow: false };
        }
        if (widget.floating) {
            widget.focusOnToFront = false;
        }

        if (entry.setup) {
            entry.setup.call(widget, widget, ct);
        } else {
            widget.render(ct);
            if (widget.floating) {
                widget.showAt(0, 0);
                ct.setHeight(widget.getHeight());
            }
        }

        var el = widget.el;
        if (entry.delegate) {
            el = el.down(entry.delegate);
        }

        el.addCls('x-slicer-target'); // this is what generateSlicerManifest looks for

        if (entry.over) {
            widget.addOverCls();
        }
        if (config.parentCls) {
            el.parent().addCls(config.parentCls);
        }

        if (Ext.theme.legacy) {
            // The 4.1 approach has some interesting extra pieces
            //
            var data = {};
            if (entry.reverse) {
                data.reverse = true;
            }
            if (entry.filename) {
                data.filename = entry.filename;
            }
            if (entry.folder) {
                data.folder = entry.folder;
            }
            if (entry.offsets) {
                data.offsets = entry.offsets;
            }

            Ext.theme.setData(el.dom, data);
        }

        Ext.theme.currentWidget = null;
    },

    /**
     * Renders all of the components that have been added to the manifest.
     * @private
     */
    render: function () {
        var manifest = Ext.theme._manifest;
        var shortcuts = Ext.theme._shortcuts;

        for (var k = 0, n = manifest ? manifest.length : 0; k < n; ++k) {
            var manifestEntry = manifest[k];
            var xtype = Ext.theme.addWidget(manifestEntry.xtype);
            var widgetShortcuts = xtype ? shortcuts[xtype] : null;

            if (xtype && manifestEntry.ui && widgetShortcuts) {
                for (var i = 0; i < widgetShortcuts.length; i++) {
                    Ext.theme.renderWidget(manifestEntry, widgetShortcuts[i]);
                }
            } else {
                Ext.theme.renderWidget(manifestEntry);
            }
        }
    },

    /**
     * Renders all components (see `render`) and notifies the Slicer that things are ready.
     * @private
     */
    run: function () {
        var extjsVer = Ext.versions.extjs;
        var globalData = {};

        if (Ext.layout.Context) {
            Ext.override(Ext.layout.Context, {
                run: function () {
                    var ok = this.callParent(),
                        widget = Ext.theme.currentWidget;
                    if (!ok && widget) {
                        Ext.Error.raise("Layout run failed: " + widget.id);
                    }
                    return ok;
                }
            });
        }

        // Previous to Ext JS 4.2, themes and their manifests where defined differently.
        // So pass this along if we are hosting a pre-4.2 theme.
        //
        if (extjsVer && extjsVer.isLessThan(new Ext.Version("4.2"))) {
            globalData.format = "1.0"; // tell the Slicer tool
            Ext.theme.legacy = true; // not for our own data collection

            // Check for the Cmd3.0/ExtJS4.1 variables:
            //
            if (Ext.manifest && Ext.manifest.widgets) {
                Ext.theme.addManifest(Ext.manifest.widgets);
            }
            if (Ext.shortcuts) {
                Ext.theme.addShortcuts(Ext.shortcuts);
            }
            if (Ext.userManifest && Ext.userManifest.widgets) {
                Ext.theme.addManifest(Ext.userManifest.widgets);
            }
        }

        Ext.theme.setData(document.body, globalData);

        Ext.theme.render();

        // This function is defined by slicer.js (the framework-independent piece)
        Ext.defer(generateSlicerManifest, 1);
    },

    /**
     * Sets the `data-slicer` attribute to the JSON-encoded value of the provided data.
     * @private
     */
    setData: function (el, data) {
        if (data) {
            var json = Ext.encode(data);
            if (json !== '{}') {
                el.setAttribute('data-slicer', json);
            }
        }
    },

    /**
     * This used to be `loadExtStylesheet`.
     * @private
     */
    loadCss: function  (src, callback) {
        var xhr = new XMLHttpRequest();

        xhr.open('GET', src);

        xhr.onload = function() {
            var css = xhr.responseText,
            head = document.getElementsByTagName('head')[0],
            style = document.createElement('style');

            // There's bugginess in the next gradient syntax in WebKit r84622
            // This might be fixed in a later WebKit, but for now we're going to
            // strip it out here since compass generates it.
            //
            // TODO: Upgrade to later WebKit revision
            css = css.replace(/background(-image)?: ?-webkit-linear-gradient(?:.*?);/g, '');

            style.type = 'text/css';
            style.innerText = css;

            head.appendChild(style);
            callback();
        };

        xhr.send(null);
    }
};

Ext.onReady(Ext.theme.run, Ext.theme);
