var Avatar = require("../avatar/Avatar");
var UIUtil = require("../util/UIUtil");
var UIEvents = require("../../../service/UI/UIEvents");
var xmpp = require("../../xmpp/xmpp");
var video = $('#largeVideo');
var currentVideoWidth = null;
var currentVideoHeight = null;
// By default we use camera
var getVideoSize = getCameraVideoSize;
var getVideoPosition = getCameraVideoPosition;
var currentSmallVideo = null;
var oldSmallVideo = null;
/**
 * Sets the size and position of the given video element.
 *
 * @param video the video element to position
 * @param width the desired video width
 * @param height the desired video height
 * @param horizontalIndent the left and right indent
 * @param verticalIndent the top and bottom indent
 */
function positionVideo(video,
                       width,
                       height,
                       horizontalIndent,
                       verticalIndent,
                       animate) {
    if(animate)
    {
        video.animate({
                width: width,
                height: height,
                top: verticalIndent,
                bottom: verticalIndent,
                left: horizontalIndent,
                right: horizontalIndent
            },
            {
                queue: false,
                duration: 500
            });
    }
    else
    {
        video.width(width);
        video.height(height);
        video.css({  top: verticalIndent + 'px',
            bottom: verticalIndent + 'px',
            left: horizontalIndent + 'px',
            right: horizontalIndent + 'px'});
    }
}
/**
 * Returns an array of the video dimensions, so that it keeps it's aspect
 * ratio and fits available area with it's larger dimension. This method
 * ensures that whole video will be visible and can leave empty areas.
 *
 * @return an array with 2 elements, the video width and the video height
 */
function getDesktopVideoSize(videoWidth,
                             videoHeight,
                             videoSpaceWidth,
                             videoSpaceHeight) {
    if (!videoWidth)
        videoWidth = currentVideoWidth;
    if (!videoHeight)
        videoHeight = currentVideoHeight;
    var aspectRatio = videoWidth / videoHeight;
    var availableWidth = Math.max(videoWidth, videoSpaceWidth);
    var availableHeight = Math.max(videoHeight, videoSpaceHeight);
    videoSpaceHeight -= $('#remoteVideos').outerHeight();
    if (availableWidth / aspectRatio >= videoSpaceHeight)
    {
        availableHeight = videoSpaceHeight;
        availableWidth = availableHeight * aspectRatio;
    }
    if (availableHeight * aspectRatio >= videoSpaceWidth)
    {
        availableWidth = videoSpaceWidth;
        availableHeight = availableWidth / aspectRatio;
    }
    return [availableWidth, availableHeight];
}
/**
 * Returns an array of the video horizontal and vertical indents,
 * so that if fits its parent.
 *
 * @return an array with 2 elements, the horizontal indent and the vertical
 * indent
 */
function getCameraVideoPosition(videoWidth,
                                videoHeight,
                                videoSpaceWidth,
                                videoSpaceHeight) {
    // Parent height isn't completely calculated when we position the video in
    // full screen mode and this is why we use the screen height in this case.
    // Need to think it further at some point and implement it properly.
    var isFullScreen = document.fullScreen ||
        document.mozFullScreen ||
        document.webkitIsFullScreen;
    if (isFullScreen)
        videoSpaceHeight = window.innerHeight;
    var horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
    var verticalIndent = (videoSpaceHeight - videoHeight) / 2;
    return [horizontalIndent, verticalIndent];
}
/**
 * Returns an array of the video horizontal and vertical indents.
 * Centers horizontally and top aligns vertically.
 *
 * @return an array with 2 elements, the horizontal indent and the vertical
 * indent
 */
function getDesktopVideoPosition(videoWidth,
                                 videoHeight,
                                 videoSpaceWidth,
                                 videoSpaceHeight) {
    var horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
    var verticalIndent = 0;// Top aligned
    return [horizontalIndent, verticalIndent];
}
/**
 * Returns an array of the video dimensions, so that it covers the screen.
 * It leaves no empty areas, but some parts of the video might not be visible.
 *
 * @return an array with 2 elements, the video width and the video height
 */
function getCameraVideoSize(videoWidth,
                            videoHeight,
                            videoSpaceWidth,
                            videoSpaceHeight) {
    if (!videoWidth)
        videoWidth = currentVideoWidth;
    if (!videoHeight)
        videoHeight = currentVideoHeight;
    var aspectRatio = videoWidth / videoHeight;
    var availableWidth = Math.max(videoWidth, videoSpaceWidth);
    var availableHeight = Math.max(videoHeight, videoSpaceHeight);
    if (availableWidth / aspectRatio < videoSpaceHeight) {
        availableHeight = videoSpaceHeight;
        availableWidth = availableHeight * aspectRatio;
    }
    if (availableHeight * aspectRatio < videoSpaceWidth) {
        availableWidth = videoSpaceWidth;
        availableHeight = availableWidth / aspectRatio;
    }
    return [availableWidth, availableHeight];
}
/**
 * Updates the src of the active speaker avatar
 * @param jid of the current active speaker
 */
function updateActiveSpeakerAvatarSrc() {
    var avatar = $("#activeSpeakerAvatar")[0];
    var jid = currentSmallVideo.peerJid;
    var url = Avatar.getGravatarUrl(jid);
    if(avatar.src === url)
        return;
    var isMuted = null;
    if(!LargeVideo.VideoLayout.isInLastN(currentSmallVideo.resourceJid)) {
        isMuted = true;
    }
    else
    {
        isMuted = APP.RTC.isVideoMuted(jid);
    }
    if (jid && isMuted !== null) {
        avatar.src = url;
        $("#largeVideo").css("visibility", isMuted ? "hidden" : "visible");
        currentSmallVideo.showAvatar(isMuted);
    }
}
function changeVideo(isVisible) {
    updateActiveSpeakerAvatarSrc();
    APP.RTC.setVideoSrc($('#largeVideo')[0], currentSmallVideo.getSrc());
    var videoTransform = document.getElementById('largeVideo')
        .style.webkitTransform;
    var flipX = currentSmallVideo.flipX;
    if (flipX && videoTransform !== 'scaleX(-1)') {
        document.getElementById('largeVideo').style.webkitTransform
            = "scaleX(-1)";
    }
    else if (!flipX && videoTransform === 'scaleX(-1)') {
        document.getElementById('largeVideo').style.webkitTransform
            = "none";
    }
    var isDesktop = APP.RTC.isVideoSrcDesktop(currentSmallVideo.peerJid);
    // Change the way we'll be measuring and positioning large video
    getVideoSize = isDesktop
        ? getDesktopVideoSize
        : getCameraVideoSize;
    getVideoPosition = isDesktop
        ? getDesktopVideoPosition
        : getCameraVideoPosition;
    // Only if the large video is currently visible.
    // Disable previous dominant speaker video.
    if (oldSmallVideo) {
        oldSmallVideo.enableDominantSpeaker(false);
    }
    // Enable new dominant speaker in the remote videos section.
    if (currentSmallVideo) {
        currentSmallVideo.enableDominantSpeaker(true);
    }
    if (isVisible) {
        // using "this" should be ok because we're called
        // from within the fadeOut event.
        $(this).fadeIn(300);
    }
    if(oldSmallVideo)
        oldSmallVideo.showAvatar();
}
var LargeVideo = {
    init: function (VideoLayout, emitter) {
        this.VideoLayout = VideoLayout;
        this.eventEmitter = emitter;
        var self = this;
        // Listen for large video size updates
        document.getElementById('largeVideo')
            .addEventListener('loadedmetadata', function (e) {
                currentVideoWidth = this.videoWidth;
                currentVideoHeight = this.videoHeight;
                self.position(currentVideoWidth, currentVideoHeight);
            });
    },
    /**
     * Indicates if the large video is currently visible.
     *
     * @return true if visible, false - otherwise
     */
    isLargeVideoVisible: function() {
        return video.is(':visible');
    },
    /**
     * Updates the large video with the given new video source.
     */
    updateLargeVideo: function(resourceJid, forceUpdate) {
        console.log('hover in', resourceJid);
        var newSmallVideo = this.VideoLayout.getSmallVideo(resourceJid);
        if ((currentSmallVideo && currentSmallVideo.resourceJid !== resourceJid)
            || forceUpdate) {
            $('#activeSpeaker').css('visibility', 'hidden');
            if(currentSmallVideo) {
                oldSmallVideo = currentSmallVideo;
            } else {
                oldSmallVideo = null;
            }
            currentSmallVideo = newSmallVideo;
            var oldJid = null;
            if(oldSmallVideo)
                oldJid = oldSmallVideo.peerJid;
            if (oldJid !== resourceJid) {
                // we want the notification to trigger even if userJid is undefined,
                // or null.
                this.eventEmitter.emit(UIEvents.SELECTED_ENDPOINT,
                    resourceJid);
            }
            video.fadeOut(300, changeVideo.bind(video, this.isLargeVideoVisible()));
        } else {
            if(currentSmallVideo) {
                currentSmallVideo.showAvatar();
            }
        }
    },
    /**
     * Shows/hides the large video.
     */
    setLargeVideoVisible: function(isVisible) {
        if (isVisible) {
            $('#largeVideo').css({visibility: 'visible'});
            $('.watermark').css({visibility: 'visible'});
            if(currentSmallVideo)
                currentSmallVideo.enableDominantSpeaker(true);
        }
        else {
            $('#largeVideo').css({visibility: 'hidden'});
            $('#activeSpeaker').css('visibility', 'hidden');
            $('.watermark').css({visibility: 'hidden'});
            if(currentSmallVideo)
                currentSmallVideo.enableDominantSpeaker(false);
        }
    },
    onVideoTypeChanged: function (jid) {
        if(jid && currentSmallVideo && jid === currentSmallVideo.peerJid)
        {
            var isDesktop = APP.RTC.isVideoSrcDesktop(jid);
            getVideoSize = isDesktop
                ? getDesktopVideoSize
                : getCameraVideoSize;
            getVideoPosition = isDesktop
                ? getDesktopVideoPosition
                : getCameraVideoPosition;
            this.position(null, null);
        }
    },
    /**
     * Positions the large video.
     *
     * @param videoWidth the stream video width
     * @param videoHeight the stream video height
     */
    position: function (videoWidth, videoHeight,
                        videoSpaceWidth, videoSpaceHeight, animate) {
        if(!videoSpaceWidth)
            videoSpaceWidth = $('#videospace').width();
        if(!videoSpaceHeight)
            videoSpaceHeight = window.innerHeight;
        var videoSize = getVideoSize(videoWidth,
            videoHeight,
            videoSpaceWidth,
            videoSpaceHeight);
        var largeVideoWidth = videoSize[0];
        var largeVideoHeight = videoSize[1];
        var videoPosition = getVideoPosition(largeVideoWidth,
            largeVideoHeight,
            videoSpaceWidth,
            videoSpaceHeight);
        var horizontalIndent = videoPosition[0];
        var verticalIndent = videoPosition[1];
        positionVideo($('#largeVideo'),
            largeVideoWidth,
            largeVideoHeight,
            horizontalIndent, verticalIndent, animate);
    },
    isLargeVideoOnTop: function () {
        var Etherpad = require("../etherpad/Etherpad");
        var Prezi = require("../prezi/Prezi");
        return !Prezi.isPresentationVisible() && !Etherpad.isVisible();
    },
    resize: function (animate, isVisible, completeFunction) {
        var availableHeight = window.innerHeight;
        var availableWidth = UIUtil.getAvailableVideoWidth(isVisible);
        if (availableWidth < 0 || availableHeight < 0) return;
        var avatarSize = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE;
        var top = availableHeight / 2 - avatarSize / 4 * 3;
        $('#activeSpeaker').css('top', top);
        if(animate)
        {
            $('#videospace').animate({
                    right: window.innerWidth - availableWidth,
                    width: availableWidth,
                    height: availableHeight
                },
                {
                    queue: false,
                    duration: 500,
                    complete: completeFunction
                });
            $('#largeVideoContainer').animate({
                    width: availableWidth,
                    height: availableHeight
                },
                {
                    queue: false,
                    duration: 500
                });
        }
        else
        {
            $('#videospace').width(availableWidth);
            $('#videospace').height(availableHeight);
            $('#largeVideoContainer').width(availableWidth);
            $('#largeVideoContainer').height(availableHeight);
        }
        return [availableWidth, availableHeight];
    },
    resizeVideoAreaAnimated: function (isVisible, completeFunction) {
        var size = this.resize(true, isVisible, completeFunction);
        this.position(null, null, size[0], size[1], true);
    },
    getResourceJid: function () {
        if(!currentSmallVideo)
            return null;
        return currentSmallVideo.resourceJid;
    },
    updateAvatar: function (resourceJid) {
        if (resourceJid === this.getResourceJid()) {
            updateActiveSpeakerAvatarSrc();
        }
    },
    showAvatar: function (resourceJid, show) {
        if(this.getResourceJid() === resourceJid
            && LargeVideo.isLargeVideoOnTop())
        {
            $("#largeVideo").css("visibility", show ? "hidden" : "visible");
            $('#activeSpeaker').css("visibility", show ? "visible" : "hidden");
            return true;
        }
        return false;
    }
}
module.exports = LargeVideo;