@license Highcharts JS v2.2.1 (2012-03-15)
MooTools adapter

(c) 2010-2011 Torstein Hønsi

License: www.highcharts.com/license

// JSLint options:

global Fx, $, $extend, $each, $merge, Events, Event, DOMEvent

(function () {

var win = window,

doc = document,
mooVersion = win.MooTools.version.substring(0, 3), // Get the first three characters of the version number
legacy = mooVersion === '1.2' || mooVersion === '1.1', // 1.1 && 1.2 considered legacy, 1.3 is not.
legacyEvent = legacy || mooVersion === '1.3', // In versions 1.1 - 1.3 the event class is named Event, in newer versions it is named DOMEvent.
$extend = win.$extend || function () {
        return Object.append.apply(Object, arguments);
};

win.HighchartsAdapter = {

     /**
 Initialize the adapter. This is run once as Highcharts is first run.
 @param {Object} pathAnim The helper object to do animations across adapters.
/
     init: function (pathAnim) {
             var fxProto = Fx.prototype,
                     fxStart = fxProto.start,
                     morphProto = Fx.Morph.prototype,
                     morphCompute = morphProto.compute;

             // override Fx.start to allow animation of SVG element wrappers
             /*jslint unparam: true*//* allow unused parameters in fx functions */
             fxProto.start = function (from, to) {
                     var fx = this,
                             elem = fx.element;

                     // special for animating paths
                     if (from.d) {
                             //this.fromD = this.element.d.split(' ');
                             fx.paths = pathAnim.init(
                                     elem,
                                     elem.d,
                                     fx.toD
                             );
                     }
                     fxStart.apply(fx, arguments);

                     return this; // chainable
             };

             // override Fx.step to allow animation of SVG element wrappers
             morphProto.compute = function (from, to, delta) {
                     var fx = this,
                             paths = fx.paths;

                     if (paths) {
                             fx.element.attr(
                                     'd',
                                     pathAnim.step(paths[0], paths[1], delta, fx.toD)
                             );
                     } else {
                             return morphCompute.apply(fx, arguments);
                     }
             };
             /*jslint unparam: false*/
     },

     /**
 Downloads a script and executes a callback when done.
 @param {String} scriptLocation
 @param {Function} callback
/
     getScript: function (scriptLocation, callback) {
             // We cannot assume that Assets class from mootools-more is available so instead insert a script tag to download script.
             var head = doc.getElementsByTagName('head')[0];
             var script = doc.createElement('script');

             script.type = 'text/javascript';
             script.src = scriptLocation;
             script.onload = callback;

             head.appendChild(script);
     },

     /**
 Animate a HTML element or SVG element wrapper
 @param {Object} el
 @param {Object} params
 @param {Object} options jQuery-like animation options: duration, easing, callback
/
     animate: function (el, params, options) {
             var isSVGElement = el.attr,
                     effect,
                     complete = options && options.complete;

             if (isSVGElement && !el.setStyle) {
                     // add setStyle and getStyle methods for internal use in Moo
                     el.getStyle = el.attr;
                     el.setStyle = function () { // property value is given as array in Moo - break it down
                             var args = arguments;
                             el.attr.call(el, args[0], args[1][0]);
                     };
                     // dirty hack to trick Moo into handling el as an element wrapper
                     el.$family = function () { return true; };
             }

             // stop running animations
             win.HighchartsAdapter.stop(el);

             // define and run the effect
             effect = new Fx.Morph(
                     isSVGElement ? el : $(el),
                     $extend({
                             transition: Fx.Transitions.Quad.easeInOut
                     }, options)
             );

             // Make sure that the element reference is set when animating svg elements
             if (isSVGElement) {
                     effect.element = el;
             }

             // special treatment for paths
             if (params.d) {
                     effect.toD = params.d;
             }

             // jQuery-like events
             if (complete) {
                     effect.addEvent('complete', complete);
             }

             // run
             effect.start(params);

             // record for use in stop method
             el.fx = effect;
     },

     /**
 MooTool's each function

/
     each: function (arr, fn) {
             return legacy ?
                     $each(arr, fn) :
                     Array.each(arr, fn);
     },

     /**
 Map an array
 @param {Array} arr
 @param {Function} fn
/
     map: function (arr, fn) {
             return arr.map(fn);
     },

     /**
 Grep or filter an array
 @param {Array} arr
 @param {Function} fn
/
     grep: function (arr, fn) {
             return arr.filter(fn);
     },

     /**
 Deep merge two objects and return a third
/
     merge: function () {
             var args = arguments,
                     args13 = [{}], // MooTools 1.3+
                     i = args.length,
                     ret;

             if (legacy) {
                     ret = $merge.apply(null, args);
             } else {
                     while (i--) {
                             // Boolean argumens should not be merged.
                             // JQuery explicitly skips this, so we do it here as well.
                             if (typeof args[i] !== 'boolean') {
                                     args13[i + 1] = args[i];
                             }
                     }
                     ret = Object.merge.apply(Object, args13);
             }

             return ret;
     },

     /**
 Get the offset of an element relative to the top left corner of the web page
/
     offset: function (el) {
             var offsets = $(el).getOffsets();
             return {
                     left: offsets.x,
                     top: offsets.y
             };
     },

     /**
 Extends an object with Events, if its not done
/
     extendWithEvents: function (el) {
             // if the addEvent method is not defined, el is a custom Highcharts object
             // like series or point
             if (!el.addEvent) {
                     if (el.nodeName) {
                             el = $(el); // a dynamically generated node
                     } else {
                             $extend(el, new Events()); // a custom object
                     }
             }
     },

     /**
 Add an event listener
 @param {Object} el HTML element or custom object
 @param {String} type Event type
 @param {Function} fn Event handler
/
     addEvent: function (el, type, fn) {
             if (typeof type === 'string') { // chart broke due to el being string, type function

                     if (type === 'unload') { // Moo self destructs before custom unload events
                             type = 'beforeunload';
                     }

                     win.HighchartsAdapter.extendWithEvents(el);

                     el.addEvent(type, fn);
             }
     },

     removeEvent: function (el, type, fn) {
             if (typeof el === 'string') {
                     // el.removeEvents below apperantly calls this method again. Do not quite understand why, so for now just bail out.
                     return;
             }
             win.HighchartsAdapter.extendWithEvents(el);
             if (type) {
                     if (type === 'unload') { // Moo self destructs before custom unload events
                             type = 'beforeunload';
                     }

                     if (fn) {
                             el.removeEvent(type, fn);
                     } else {
                             el.removeEvents(type);
                     }
             } else {
                     el.removeEvents();
             }
     },

     fireEvent: function (el, event, eventArguments, defaultFunction) {
             var eventArgs = {
                     type: event,
                     target: el
             };
             // create an event object that keeps all functions
             event = legacyEvent ? new Event(eventArgs) : new DOMEvent(eventArgs);
             event = $extend(event, eventArguments);
             // override the preventDefault function to be able to use
             // this for custom events
             event.preventDefault = function () {
                     defaultFunction = null;
             };
             // if fireEvent is not available on the object, there hasn't been added
             // any events to it above
             if (el.fireEvent) {
                     el.fireEvent(event.type, event);
             }

             // fire the default if it is passed and it is not prevented above
             if (defaultFunction) {
                     defaultFunction(event);
             }
     },

     /**
 Stop running animations on the object
/
     stop: function (el) {
             if (el.fx) {
                     el.fx.cancel();
             }
     }

};

}());