# Source: core/geometry/point.js

    /**
     * @module montage/core/geometry/point
     * @requires montage/core/core
     */
    var Montage = require("../core").Montage;

    /**
     * @class Point
     * @extends Montage
     */

    var Point = exports.Point = Montage.specialize( /** @lends Point# */ {
        init: {
            enumerable: false,
            value: function (x, y) {
                this.x = x === null ? 0 : x;
                this.y = y === null ? 0 : y;
                return this;
            }
        },

        /**
         * The x axis point.
         * @type {number}
         * @default  0
         */
        x: {
            enumerable: true,
            value: 0
        },

        /**
         * The y axis point.
         * @type {number}
         * @default  0
         */
        y: {
            enumerable: true,
            value: 0
        }

    }, {

        /**
         * Interpolates between two points.
         * @function
         * @param {Axis} percent The interpolation percentage.
         * @param {Axis} point0 The 0 interpolation point.
         * @param {Axis} point1 The 1 interpolation point.
         * @param {Axis} precision The interpolation precision.
         * @returns new Point().init(xValue, yValue)
         */
        interpolate: {
            enumerable: false,
            value: function (percent, point0, point1, precision) {
                var xValue,
                    yValue;
                xValue = point0.x + (point1.x - point0.x) * percent;
                yValue = point0.y + (point1.y - point0.y) * percent;
                if (precision > 0) {
                    xValue = Math.round(xValue * precision) / precision;
                    yValue = Math.round(yValue * precision) / precision;
                }
                return new exports.Point().init(xValue, yValue);
            }
        }

    });

    var _offsetForElement = function (element) {
        var boundingClientRect,
            elementsDocument = element.ownerDocument,
            elementsDocumentElement,
            elementsBody,
            elementsWindow;

        if ( element && elementsDocument ) {
            elementsDocumentElement = elementsDocument.documentElement;
            elementsBody = elementsDocument.body;
            elementsWindow = elementsDocument.defaultView;

            if ( element !== elementsBody ) {
                boundingClientRect = element.getBoundingClientRect();
                if ( elementsDocumentElement.parentOf(element) ) {
                    var clientTop  = elementsDocumentElement.clientTop  || elementsBody.clientTop  || 0,
                        clientLeft = elementsDocumentElement.clientLeft || elementsBody.clientLeft || 0,
                        scrollTop  = elementsWindow.pageYOffset || elementsDocumentElement.scrollTop  || elementsBody.scrollTop,
                        scrollLeft = elementsWindow.pageXOffset || elementsDocumentElement.scrollLeft || elementsBody.scrollLeft,
                        top  = boundingClientRect.top  + scrollTop  - clientTop,
                        left = boundingClientRect.left + scrollLeft - clientLeft;
                    return { top: top, left: left };
                } else {
                    return { top: boundingClientRect.top, left: boundingClientRect.left };
                }

            } else {
                return { top: elementsBody.offsetTop, left: elementsBody.offsetLeft };
            }
        } else {
            return null;
        }
    };

    var _webKitPoint = null;

    var webkitImplementation = function () {
        Point.convertPointFromNodeToPage = function (element, point) {
            if (!element || typeof element.x !== "undefined") {
                return null;
            }
            if(point) {
                _webKitPoint.x = point.x;
                _webKitPoint.y = point.y;
            } else {
                _webKitPoint.x = 0;
                _webKitPoint.y = 0;
            }
            /* globals webkitConvertPointFromNodeToPage */
            point = webkitConvertPointFromNodeToPage(element, _webKitPoint);
            return point ? new Point().init(point.x, point.y) : null;
        };

        Point.convertPointFromPageToNode = function (element, point) {
            if (!element || typeof element.x !== "undefined") {
                return null;
            }

            if(point) {
                _webKitPoint.x = point.x;
                _webKitPoint.y = point.y;
            } else {
                _webKitPoint.x = 0;
                _webKitPoint.y = 0;
            }
            /* globals webkitConvertPointFromNodeToPage */
            point = webkitConvertPointFromPageToNode(element, _webKitPoint);
            return point ? new Point().init(point.x, point.y) : null;
        };
    };

    var shimImplementation = function () {
        Point.convertPointFromNodeToPage = function (element, point) {
            if (!element || typeof element.x !== "undefined") {
                return null;
            }
            var offset;
            if ((offset =_offsetForElement(element))) {
                return new Point().init((point ? point.x:0)+offset.left, (point ? point.y:0)+offset.top);
            } else {
                return new Point().init((point ? point.x:0), (point ? point.y:0));
            }
        };

        Point.convertPointFromPageToNode = function (element, point) {
            if (!element || typeof element.x !== "undefined") {
                return null;
            }
            var offset;
            if ((offset =_offsetForElement(element))) {
                return new Point().init((point ? point.x:0)-offset.left, (point ? point.y:0)-offset.top);
            } else {
                return new Point().init((point ? point.x:0), (point ? point.y:0));
            }
        };
    };

    if (
        typeof WebKitPoint !== "undefined" &&
            typeof webkitConvertPointFromNodeToPage !== "undefined"
    ) {
        _webKitPoint = new WebKitPoint(0,0);
        webkitImplementation();
    } else {
        shimImplementation();
    }