var Util = {
    extend: function (dest, src) {
        for (var key in src) {
            if (src.hasOwnProperty(key)) {
                dest[key] = src[key];
            }
        }
        return dest;
    },
    copyArray: function (source, dest) {
        for (var i = 0, n = source.length; i < n; i++) {
            dest[i] = source[i];
        }
    },
    getScreenWidth: function () {
        return Math.max(window.screen.width, window.screen.height) *
            window.devicePixelRatio;
    },
    getScreenHeight: function () {
        return Math.min(window.screen.width, window.screen.height) *
            window.devicePixelRatio;
    },
    requestFullscreen: function (element) {
        if (this.isWebViewAndroid()) {
            return false;
        }
        if (element.requestFullscreen) {
            element.requestFullscreen();
        } else if (element.webkitRequestFullscreen) {
            element.webkitRequestFullscreen();
        } else if (element.mozRequestFullScreen) {
            element.mozRequestFullScreen();
        } else if (element.msRequestFullscreen) {
            element.msRequestFullscreen();
        } else {
            return false;
        }

        return true;
    },
    exitFullscreen: function () {
        if (document.exitFullscreen) {
            document.exitFullscreen();
        } else if (document.webkitExitFullscreen) {
            document.webkitExitFullscreen();
        } else if (document.mozCancelFullScreen) {
            document.mozCancelFullScreen();
        } else if (document.msExitFullscreen) {
            document.msExitFullscreen();
        } else {
            return false;
        }

        return true;
    },
    getFullscreenElement: function () {
        return document.fullscreenElement ||
            document.webkitFullscreenElement ||
            document.mozFullScreenElement ||
            document.msFullscreenElement;
    },
    linkProgram: function (gl, vertexSource, fragmentSource, attribLocationMap) {
        // No error checking for brevity.
        var vertexShader = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(vertexShader, vertexSource);
        gl.compileShader(vertexShader);

        var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(fragmentShader, fragmentSource);
        gl.compileShader(fragmentShader);

        var program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);

        for (var attribName in attribLocationMap)
            gl.bindAttribLocation(program, attribLocationMap[attribName], attribName);

        gl.linkProgram(program);

        gl.deleteShader(vertexShader);
        gl.deleteShader(fragmentShader);

        return program;
    },
    getProgramUniforms: function (gl, program) {
        var uniforms = {};
        var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
        var uniformName = '';
        for (var i = 0; i < uniformCount; i++) {
            var uniformInfo = gl.getActiveUniform(program, i);
            uniformName = uniformInfo.name.replace('[0]', '');
            uniforms[uniformName] = gl.getUniformLocation(program, uniformName);
        }
        return uniforms;
    },
    orthoMatrix: function (out, left, right, bottom, top, near, far) {
        var lr = 1 / (left - right),
            bt = 1 / (bottom - top),
            nf = 1 / (near - far);
        out[0] = -2 * lr;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = -2 * bt;
        out[6] = 0;
        out[7] = 0;
        out[8] = 0;
        out[9] = 0;
        out[10] = 2 * nf;
        out[11] = 0;
        out[12] = (left + right) * lr;
        out[13] = (top + bottom) * bt;
        out[14] = (far + near) * nf;
        out[15] = 1;
        return out;
    },
    isDebug: function () {
        return this.getQueryParameter('debug');
    },
    getQueryParameter: function (name,path) {
        var name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
        var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
            results = regex.exec(path); //?house=BF1ED5557F7148F2A76ACA168C42EE3A
        return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
    },
    frameDataFromPose: function (frameData, pose, vrDisplay) {
        var piOver180 = Math.PI / 180.0,
            rad45 = Math.PI * 0.25,
            defaultOrientation = new Float32Array([0, 0, 0, 1]),
            defaultPosition = new Float32Array([0, 0, 0]);

        mat4_perspectiveFromFieldOfView = function (out, fov, near, far) {
            var upTan = Math.tan(fov ? (fov.upDegrees * piOver180) : rad45),
                downTan = Math.tan(fov ? (fov.downDegrees * piOver180) : rad45),
                leftTan = Math.tan(fov ? (fov.leftDegrees * piOver180) : rad45),
                rightTan = Math.tan(fov ? (fov.rightDegrees * piOver180) : rad45),
                xScale = 2.0 / (leftTan + rightTan),
                yScale = 2.0 / (upTan + downTan);

            out[0] = xScale;
            out[1] = 0.0;
            out[2] = 0.0;
            out[3] = 0.0;
            out[4] = 0.0;
            out[5] = yScale;
            out[6] = 0.0;
            out[7] = 0.0;
            out[8] = -((leftTan - rightTan) * xScale * 0.5);
            out[9] = ((upTan - downTan) * yScale * 0.5);
            out[10] = far / (near - far);
            out[11] = -1.0;
            out[12] = 0.0;
            out[13] = 0.0;
            out[14] = (far * near) / (near - far);
            out[15] = 0.0;
            return out;
        };
        mat4_fromRotationTranslation = function (out, q, v) {
            // Quaternion math
            var x = q[0],
                y = q[1],
                z = q[2],
                w = q[3],
                x2 = x + x,
                y2 = y + y,
                z2 = z + z,

                xx = x * x2,
                xy = x * y2,
                xz = x * z2,
                yy = y * y2,
                yz = y * z2,
                zz = z * z2,
                wx = w * x2,
                wy = w * y2,
                wz = w * z2;

            out[0] = 1 - (yy + zz);
            out[1] = xy + wz;
            out[2] = xz - wy;
            out[3] = 0;
            out[4] = xy - wz;
            out[5] = 1 - (xx + zz);
            out[6] = yz + wx;
            out[7] = 0;
            out[8] = xz + wy;
            out[9] = yz - wx;
            out[10] = 1 - (xx + yy);
            out[11] = 0;
            out[12] = v[0];
            out[13] = v[1];
            out[14] = v[2];
            out[15] = 1;

            return out;
        };
        mat4_translate = function (out, a, v) {
            var x = v[0],
                y = v[1],
                z = v[2],
                a00, a01, a02, a03,
                a10, a11, a12, a13,
                a20, a21, a22, a23;

            if (a === out) {
                out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
                out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
                out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
                out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
            } else {
                a00 = a[0];
                a01 = a[1];
                a02 = a[2];
                a03 = a[3];
                a10 = a[4];
                a11 = a[5];
                a12 = a[6];
                a13 = a[7];
                a20 = a[8];
                a21 = a[9];
                a22 = a[10];
                a23 = a[11];

                out[0] = a00;
                out[1] = a01;
                out[2] = a02;
                out[3] = a03;
                out[4] = a10;
                out[5] = a11;
                out[6] = a12;
                out[7] = a13;
                out[8] = a20;
                out[9] = a21;
                out[10] = a22;
                out[11] = a23;

                out[12] = a00 * x + a10 * y + a20 * z + a[12];
                out[13] = a01 * x + a11 * y + a21 * z + a[13];
                out[14] = a02 * x + a12 * y + a22 * z + a[14];
                out[15] = a03 * x + a13 * y + a23 * z + a[15];
            }

            return out;
        };
        mat4_invert = function (out, a) {
            var a00 = a[0],
                a01 = a[1],
                a02 = a[2],
                a03 = a[3],
                a10 = a[4],
                a11 = a[5],
                a12 = a[6],
                a13 = a[7],
                a20 = a[8],
                a21 = a[9],
                a22 = a[10],
                a23 = a[11],
                a30 = a[12],
                a31 = a[13],
                a32 = a[14],
                a33 = a[15],

                b00 = a00 * a11 - a01 * a10,
                b01 = a00 * a12 - a02 * a10,
                b02 = a00 * a13 - a03 * a10,
                b03 = a01 * a12 - a02 * a11,
                b04 = a01 * a13 - a03 * a11,
                b05 = a02 * a13 - a03 * a12,
                b06 = a20 * a31 - a21 * a30,
                b07 = a20 * a32 - a22 * a30,
                b08 = a20 * a33 - a23 * a30,
                b09 = a21 * a32 - a22 * a31,
                b10 = a21 * a33 - a23 * a31,
                b11 = a22 * a33 - a23 * a32,

                // Calculate the determinant
                det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;

            if (!det) {
                return null;
            }
            det = 1.0 / det;

            out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
            out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
            out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
            out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
            out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
            out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
            out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
            out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
            out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
            out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
            out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
            out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
            out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
            out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
            out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
            out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;

            return out;
        };
        updateEyeMatrices = function (projection, view, pose, parameters, vrDisplay) {
            mat4_perspectiveFromFieldOfView(projection, parameters ? parameters.fieldOfView : null, vrDisplay.depthNear, vrDisplay.depthFar);
            var orientation = pose.orientation || defaultOrientation;
            var position = pose.position || defaultPosition;

            mat4_fromRotationTranslation(view, orientation, position);
            if (parameters)
                mat4_translate(view, view, parameters.offset);
            mat4_invert(view, view);
        }


        if (!frameData || !pose)
            return false;

        frameData.pose = pose;
        frameData.timestamp = pose.timestamp;

        updateEyeMatrices(
            frameData.leftProjectionMatrix, frameData.leftViewMatrix,
            pose, vrDisplay.getEyeParameters("left"), vrDisplay);
        updateEyeMatrices(
            frameData.rightProjectionMatrix, frameData.rightViewMatrix,
            pose, vrDisplay.getEyeParameters("right"), vrDisplay);

        return true;
    },

    isInsideCrossDomainIFrame: function () {
        var isFramed = (window.self !== window.top);
        var refDomain = Util.getDomainFromUrl(document.referrer);
        var thisDomain = Util.getDomainFromUrl(window.location.href);

        return isFramed && (refDomain !== thisDomain);
    },
    getDomainFromUrl: function () {
        var domain;
        // Find & remove protocol (http, ftp, etc.) and get domain.
        if (url.indexOf("://") > -1) {
            domain = url.split('/')[2];
        } else {
            domain = url.split('/')[0];
        }

        //find & remove port number
        domain = domain.split(':')[0];
        return domain;
    },
    /**
     * 解析四元数
     */
    decryptQuaternion: function (quaternion) {
        var ret = {}
        var sightVector = new THREE.Vector3(0, 0, -1);
        ret.rotation = 2 * Math.acos(quaternion.w);
        sightVector.applyQuaternion(quaternion);
        if (sightVector.x < 0) {
            ret.theta = sightVector.clone().projectOnPlane(new THREE.Vector3(0, 1, 0)).angleTo(new THREE.Vector3(0, 0, -1)) || 0; //水平旋转角度
        } else {
            ret.theta = -sightVector.clone().projectOnPlane(new THREE.Vector3(0, 1, 0)).angleTo(new THREE.Vector3(0, 0, -1)) || 0; //水平旋转角度
        }
        if (sightVector.y > 0) {
            // 向上看
            ret.delta = sightVector.clone().projectOnPlane(new THREE.Vector3(0, 1, 0)).angleTo(sightVector) || 0; // 绕相机X轴的角度
        } else {
            // 向下看
            ret.delta = -sightVector.clone().projectOnPlane(new THREE.Vector3(0, 1, 0)).angleTo(sightVector) || 0; // 绕相机X轴的角度
        }

        return ret;
    },
    /**
     * 转换四元数
     */
    encryptQuaternion: function (theta, delta) {
        var yAxisQuaternion = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), theta);
        var cameraXAxisQuaternion = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), delta);
        var newQuaternion = new THREE.Quaternion().multiplyQuaternions(yAxisQuaternion, cameraXAxisQuaternion);
        return newQuaternion
    },
    /**
     * 获取元素相对于屏幕顶部的相对位置
     * @param  {Object} element dom元素
     * @return {Object}         绝对位置{currentX, currentY}
     */
    getElementFixed: function (element) {　　　　
        var actualLeft = 0;　　　　
        var actualTop = 0;　　　
        var current = element;　　　　
        while (current !== null) {
            var translate = Util.getTranslate(current);
            actualLeft += (current.offsetLeft + translate[0] + element.offsetWidth * (1 - translate[2]) / 2);
            actualTop += (current.offsetTop + translate[1] + element.offsetHeight * (1 - translate[3]) / 2);　　　　　　
            current = current.offsetParent;　　　　
        }　　　　
        return {
            currentX: actualLeft,
            currentY: actualTop
        };　　
    },
    /**
     * 获取元素的css3 Translate偏移量
     * 只做了对标准和webkit内核兼容
     * 获取css属性摘自Zepto.js，做修改后只获得transform属性
     * 只处理 translate，如果有旋转或者缩放等，结果会不准确
     *
     * @param  {Object} element dom元素
     * @return {Array}          偏移量[x,y]
     */
    getTranslate: function (element) {
        // var transformMatrix = element.style["WebkitTransform"] || getComputedStyle(element, '').getPropertyValue("-webkit-transform") || element.style["transform"] || getComputedStyle(element, '').getPropertyValue("transform");
        var x = parseFloat(window.$(element).css("transform").replace(/[^0-9\-.,]/g, '').split(',')[4] || 0);
        var y = parseFloat(window.$(element).css("transform").replace(/[^0-9\-.,]/g, '').split(',')[5] || 0);
        var scaleX = parseFloat(window.$(element).css("transform").replace(/[^0-9\-.,]/g, '').split(',')[0] || 1)
        var scaleY = parseFloat(window.$(element).css("transform").replace(/[^0-9\-.,]/g, '').split(',')[3] || 1)
        // var matrix = transformMatrix.match(/\-?[0-9]+\.?[0-9]*/g);
        // var x = parseInt(matrix[12] || matrix[4] || 0); //translate x
        // var y = parseInt(matrix[13] || matrix[5] || 0); //translate y
        return [x, y, scaleX, scaleY];


    },
    getElementFixSize: function (element) {
        var actualWidth = element.offsetWidth;　　　　
        var actualHeight = element.offsetHeight;
        var current = element;
        while (current !== null) {
            var scale = Util.getScale(current);
            actualWidth *= scale[0];
            actualHeight *= scale[1];
            current = current.offsetParent;　
        }　
        return　　 {
            currentWidth: actualWidth,
            currentHeight: actualHeight
        };　　
    },
    getScale: function (element) {
        var x = parseFloat(window.$(element).css("transform").replace(/[^0-9\-.,]/g, '').split(',')[0] || 1);
        var y = parseFloat(window.$(element).css("transform").replace(/[^0-9\-.,]/g, '').split(',')[3] || 1);
        return [x, y]
    },
    isOver: function (cursorid, element) {
        var cursorElement = document.getElementById(cursorid);
        var cursorPosition = Util.getElementFixed(cursorElement);
        var cursorSize = Util.getElementFixSize(cursorElement);
        var elementPosition = Util.getElementFixed(element);
        var elem = window.$(element);

        if (elementPosition.currentY + elem.height() < cursorPosition.currentY || //
            elementPosition.currentY > cursorPosition.currentY + cursorSize.currentHeight ||
            elementPosition.currentX + elem.width() < cursorPosition.currentX ||
            elementPosition.currentX > cursorPosition.currentX + cursorSize.currentWidth) {
            return false;
        } else return true;

    },

    guid: function () {
        function s4() {
            return Math.floor((1 + Math.random()) * 0x10000)
                .toString(16)
                .substring(1);
        }
        return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
    },

    ConvertImage2Base64: function (img) {
        var canvas = document.createElement("canvas");

        if (!canvas) {
            support_h5 = false;
            window.$("#download_percent").text(window.$i18n.t("info.47"));
            return "";
        }

        canvas.width = img.width;
        canvas.height = img.height;
        var ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0, img.width, img.height);
        var ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
        var dataURL = canvas.toDataURL("image/" + ext);
        return dataURL;
    }



}

var coordinate = {
    MakeMatrix4FromSoftware: function (array) {
        var matrix4 = new THREE.Matrix4();
        matrix4.set(
            array[0].x, array[1].x, array[2].x, array[3].x,
            array[0].y, array[1].y, array[2].y, array[3].y,
            array[0].z, array[1].z, array[2].z, array[3].z,
            array[0].w, array[1].w, array[2].w, array[3].w
        );
        return matrix4;
    },
    TransformMatrix4FromSoftwareArray: function (array) {

        var matrix4 = new THREE.Matrix4();
        matrix4.set(-array[0].x, -array[1].x, -array[2].x, -array[3].x, -array[0].z, -array[1].z, -array[2].z, -array[3].z, -array[0].y, -array[1].y, -array[2].y, -array[3].y, -array[0].w, -array[1].w, -array[2].w, -array[3].w);
        return matrix4;
    },
    TransformMatrix4FromSoftwareMatrix4: function (matrix4) {
        var matrix4 = new THREE.Matrix4();
        matrix4.set(-matrix4.elements[0], -matrix4.elements[1], -matrix4.elements[2], -matrix4.elements[3], -matrix4.elements[8], -matrix4.elements[9], -matrix4.elements[10], -matrix4.elements[11], -matrix4.elements[4], -matrix4.elements[5], -matrix4.elements[6], -matrix4.elements[7], -matrix4.elements[12], -matrix4.elements[13], -matrix4.elements[14], -matrix4.elements[15]);
    }
};
