/**
 * @class ST.supports
 * This singleton contains various boolean properties to describe the supported features
 * of the current browser.
 * @singleton
 */
(function() {
    var testEl = document.createElement('div'),
        name, supports, value;
 
    ST.supports = supports = {
        _methods: {
            ExtJSPointerEventMode: false,
            
            /**
             * Set to `true` if this browser supports the Pointer Events W3C specification.
             * At this time this is only supported by IE11 and Microsoft Edge.
             * @property {Boolean} PointerEvents 
             * @readonly
             */
            PointerEvents: function () {
                // no Ext JS; check PointerEvent existence 
                if (!ST.Ext) {
                    return !!window.PointerEvent;
                } 
                // version prior to new PointerEvent fixes; check pointerEnabled 
                else if (!ST.supports.ExtJSPointerEventMode) {
                    return navigator.pointerEnabled;
                } 
                // has PointerEvent fixes; do the needful 
                else {
                    return !!(window.PointerEvent && !ST.supports._methods.TouchEvents());
                }
            },
 
            /**
             * Set to `true` if this browser supports the "ms" vendor prefixed version of
             * the Pointer Events W3C specification. These events are slightly different than
             * the final W3C specification.
             *
             * At this time this is only supported by IE10 and IE11.
             * @property {Boolean} MSPointerEvents 
             * @readonly
             */
            MSPointerEvents: function () {
                return !!(navigator.msPointerEnabled && !ST.supports._methods.PointerEvents());
            },
 
            /**
             * Set to `true` if this browser supports touch events ("touchstart" et.al.).
             *
             * At this time this is true for mobile devices such as iOS and Android but also
             * Chrome on other touch-screen devices.
             * @property {Boolean} TouchEvents 
             * @readonly
             */
            TouchEvents: function () {
                return 'ontouchend' in testEl;
            },
 
            /**
             * Set to `true` if this browser supports the standard `wheel` event. When this
             * is `false`, code generally falls back to the older "mousewheel" event.
             * @property {Boolean} Wheel 
             * @readonly
             */
            Wheel: function() {
                return 'onwheel' in testEl;
            },
 
            /**
             * Set to `true` if this browser can create synthetic `MouseEvent` instances.
             * @property {Boolean} EventConstructors 
             * @readonly
             */
            EventConstructors: function() {
                var m;
 
                if (window.MouseEvent) {
                    try {
                        m = new MouseEvent('mousedown', { clientX: 100 });
                        // In Edge 12 pageX and pageY can't be set via the MouseEvent or 
                        // PointerEvent constructors.  Here we detect that bug by checking 
                        // if pageX on the constructed event is different from the clientX 
                        // value specified on the config (assumes no document scroll). 
                        // If the bug is detected we'll have to fall back to the old-school 
                        // initEvent pattern of constructing events 
                        if (m.pageX !== 100) {
                            m = false;
                        }
                    } catch(e) {
                        // Some older browsers have event contstructors on the window object 
                        // but throw errors when they are called 
                    }
                }
 
                return !!m;
            },
 
            /**
             * Set to `true` if this browser can create synthetic `KeyboardEvent` instances.
             * @property {Boolean} KeyboardEventConstructor 
             * @readonly
             */
            KeyboardEventConstructor: function() {
                var k;
 
                if (window.KeyboardEvent) {
                    try {
                        k = new KeyboardEvent('keydown', { keyCode: 65 });
                        // In Chrome/Edge keyCode can't be set via the KeyboardEvent constructor 
                        // so we have to fall back to the old way of firing key events in those 
                        // browsers. 
                        if (!k.keyCode) {
                            k = false;
                        }
                    } catch(e) {
                        // Some older browsers have event contstructors on the window object 
                        // but throw errors when they are called 
                    }
                }
 
                return !!k;
            }    
        }
        
    }
 
    for (name in supports._methods) {
        if (typeof(value = supports._methods[name]) === 'function') {
            supports[name.replace('_', '')] = value();
        }
    }
 
    ST.supports._updateFromExt = function (pointerMode) {
        // fix PointerEvents 
        ST.supports.ExtJSPointerEventMode = pointerMode;
        // update dependent values 
        ST.supports.PointerEvents = supports._methods.PointerEvents();
        ST.supports.MSPointerEvents = supports._methods.MSPointerEvents();
    }
})();