//////////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2014-present, Egret Technology.
//  All rights reserved.
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the Egret nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY EGRET AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
//  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//  IN NO EVENT SHALL EGRET AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
//  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;LOSS OF USE, DATA,
//  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
//  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////////////

namespace egret.native {
    /**
     * @private
     * @inheritDoc
     */
    export class NativeVideo extends egret.DisplayObject implements egret.Video {
        /**
         * @private
         */
        private originVideo:HTMLVideoElement;
        /**
         * @private
         */
        private loaded:boolean = false;
        /**
         * @private
         */
        private loading:boolean = false;
        /**
         * @private
         */
        private cache:boolean;

        /**
         * @private
         * @inheritDoc
         */
        constructor(url?:string, cache:boolean = true) {
            super();
            this.$renderNode = new sys.BitmapNode();
            this.cache = cache;
            if (!__global.Video) {
                egret.$error(1044);
            }
            if (url) {
                this.load(url, cache);
            }
        }

        /**
         * @inheritDoc
         */
        public load(url?:string, cache:boolean = true):void {
            if (DEBUG && !url) {
                egret.$error(3002);
                return;
            }
            if (this.loading) {
                return;
            }
            if(url.indexOf('/')==0){
                url = url.slice(1,url.length);
            }
            this.src = url;
            this.loading = true;
            this.loaded = false;

            if (cache && !egret_native.isFileExists(url)) {
                let self = this;
                let promise = egret.PromiseObject.create();
                promise.onSuccessFunc = function () {
                    self.loadEnd();
                };
                promise.onErrorFunc = function () {
                    egret.$warn(1048);
                    self.dispatchEventWith(IOErrorEvent.IO_ERROR);
                };
                egret_native.download(url, url, promise);
            } else {
                this.loadEnd();
            }
        }

        /**
         * @private
         * */
        private loadEnd() {
            let video = new __global.Video(this.src);
            video['setVideoRect'](0, 0, 1, 1);
            video['setKeepRatio'](false);
            video.addEventListener("canplaythrough", onCanPlay);
            video.addEventListener("error", onVideoError);
            video.addEventListener("playing", onPlaying);
            video.load();
            let self = this;

            function onCanPlay():void {
                video['setVideoRect'](0, 0, 1, 1);
                video.play();
            }
            function onPlaying():void {
                video['setVideoRect'](0, 0, 1, 1);
                __global.setTimeout(() => {
                    video.pause();
                    if (self._fullscreen) {
                        video.fullScreen = true;
                    }
                    video.currentTime = 0;
                    self.originVideo = video;
                    self.loaded = true;
                    self.loading = false;
                    removeListeners();
                    self.dispatchEventWith(egret.Event.COMPLETE);
                    video.addEventListener('pause', function () {
                        self.paused = true;
                    });
                    video.addEventListener('playing', function () {
                        self.paused = false;
                    });
                    video.addEventListener('ended', function () {
                        self.dispatchEventWith(egret.Event.ENDED);
                        if (self.loop) {
                            self.play(0, true);
                        }
                    });
                }, 1);
            }

            function onVideoError():void {
                removeListeners();
                self.dispatchEventWith(egret.IOErrorEvent.IO_ERROR);
            }

            function removeListeners():void {
                video.removeEventListener("canplaythrough", onCanPlay);
                video.removeEventListener("error", onVideoError);
                video.removeEventListener("playing", onPlaying);
            }
        }

        /**
         * @private
         * */
        private loop:boolean = false;

        /**
         * @inheritDoc
         */
        public play(startTime?:number, loop:boolean = false) {
            this.loop = loop;
            if (!this.loaded) {
                this.load(this.src);
                this.once(egret.Event.COMPLETE, e=>this.play(startTime, loop), this)
                return;
            }
            let haveStartTime = false;
            if (startTime != undefined && startTime != this.originVideo.currentTime) {
                this.originVideo.currentTime = startTime || 0;
                haveStartTime = true;
            }
            this.startPlay(haveStartTime);
        }

        /**
         * @private
         * */
        private isPlayed:boolean = false;
        /**
         * @private
         * */
        private firstPlay:boolean = true;

        /**
         * @private
         * */
        private startPlay(haveStartTime:boolean = false) {
            if (!this.isAddToStage || !this.loaded) {
                return;
            }
            this.firstPlay = false;
            this.setVideoSize();
            this.isPlayed = true;
            if (!haveStartTime && this.paused && this.position != 0) {
                this.originVideo['resume']();
            } else {
                this.originVideo.play();
            }
            egret.startTick(this.markDirty, this);
        }

        /**
         * @private
         * */
        private stopPlay() {
            egret.stopTick(this.markDirty, this);
            if (this.isPlayed) {
                this.isPlayed = false;
                this.originVideo.pause();
            }
        }

        /**
         * @inheritDoc
         */
        public close() {
            if (this.originVideo) {
                this.originVideo['destroy']();
            }
            this.loaded = false;
            this.loading = false;
            this.originVideo = null;
            this.loop = false;
            this.src = null;
        }

        /**
         * @inheritDoc
         */
        public src:string = "";
        /**
         * @private
         * */
        private posterData:egret.BitmapData;
        /**
         * @private
         * */
        private posterUrl:string;

        /**
         * @inheritDoc
         */
        public get poster():string {
            return this.posterUrl;
        }

        /**
         * @inheritDoc
         */
        public set poster(value:string) {
            this.posterUrl = value;
            let loader = new NativeImageLoader();
            loader.load(value);
            loader.addEventListener(egret.Event.COMPLETE, ()=> {
                this.posterData = loader.data;
                this.markDirty();
            }, this);
        }

        private _fullscreen:boolean = true;
        /**
         * @inheritDoc
         */
        public set fullscreen(value:boolean) {
            this._fullscreen = value;
            if (this.originVideo) {
                this.originVideo['fullScreen'] = value;
            }
        }

        /**
         * @inheritDoc
         */
        public get fullscreen():boolean {
            if (this.originVideo) {
                return this.originVideo['fullScreen'];
            }
            return this._fullscreen;
        }

        /**
         * @inheritDoc
         */
        public get volume():number {
            if (!this.loaded)
                return 0;
            return this.originVideo.volume;
        }

        /**
         * @inheritDoc
         */
        public set volume(value:number) {
            if (!this.loaded)
                return;
            this.originVideo.volume = value;
        }

        /**
         * @inheritDoc
         */
        public get position():number {
            return this.originVideo.currentTime;
        }

        /**
         * @inheritDoc
         */
        public set position(value) {
            if (this.loaded) {
                this.originVideo.currentTime = value;
            }
        }

        /**
         * @inheritDoc
         */
        public pause() {
            this.originVideo.pause();
        }

        private _bitmapData:BitmapData = null;
        /**
         * @inheritDoc
         */
        public get bitmapData():BitmapData {
            return this._bitmapData;
        }

        /**
         * @inheritDoc
         */
        public paused:boolean = false;

        /**
         * @inheritDoc
         */
        public get length():number {
            if (this.loaded) {
                return this.originVideo.duration;
            }
            throw new Error("Video not loaded!");
            //return 0;
        }

        /**
         * @private
         */
        private isAddToStage:boolean = false;

        /**
         * @inheritDoc
         */
        $onAddToStage(stage:Stage, nestLevel:number):void {
            this.isAddToStage = true;
            if (this.originVideo) {
                this.originVideo["setVideoVisible"](true);
            }
            super.$onAddToStage(stage, nestLevel);
        }

        /**
         * @inheritDoc
         */
        $onRemoveFromStage():void {
            this.isAddToStage = false;
            if (this.originVideo) {
                this.stopPlay();
                this.originVideo["setVideoVisible"](false);
            }
            super.$onRemoveFromStage();
        }

        /**
         * @private
         */
        private getPlayWidth():number {
            if (!isNaN(this.widthSet)) {
                return this.widthSet;
            }
            if (this.bitmapData) {
                return this.bitmapData.width;
            }
            if (this.posterData) {
                return this.posterData.width;
            }
            return NaN;
        }

        /**
         * @private
         */
        private getPlayHeight():number {
            if (!isNaN(this.heightSet)) {
                return this.heightSet;
            }
            if (this.bitmapData) {
                return this.bitmapData.height;
            }
            if (this.posterData) {
                return this.posterData.height;
            }
            return NaN;
        }

        /**
         * @private
         */
        private heightSet:number = 0;

        /**
         * @private
         */
        $setHeight(value:number):void {
            this.heightSet = +value || 0;
            this.setVideoSize();
            super.$setHeight(value);
        }

        /**
         * @private
         */
        private widthSet:number = 0;

        /**
         * @private
         */
        $setWidth(value:number):void {
            this.widthSet = +value || 0;
            this.setVideoSize();
            super.$setWidth(value);
        }

        /**
         * @inheritDoc
         */
        $setX(value:number):boolean {
            let result = super.$setX(value);
            this.setVideoSize();
            return result;
        }

        /**
         * @inheritDoc
         */
        $setY(value:number):boolean {
            let result = super.$setY(value);
            this.setVideoSize();
            return result;
        }

        /**
         * @private
         */
        private setVideoSize():void {
            let video = this.originVideo;
            if (video && !this.fullscreen) {
                if (!this.firstPlay) {
                    video['setVideoRect'](this.x, this.y, this.widthSet, this.heightSet);
                } else {
                    video['setVideoRect'](this.x, this.y, 0, 0);
                }
            }
        }

        /**
         * @private
         */
        $measureContentBounds(bounds:Rectangle) {
            let posterData = this.posterData;
            if (posterData) {
                bounds.setTo(0, 0, this.getPlayWidth(), this.getPlayHeight());
            }
            else {
                bounds.setEmpty();
            }
        }

        /**
         * @private
         */
        $updateRenderNode():void {
            let node = <sys.BitmapNode>this.$renderNode;
            let posterData = this.posterData;
            let width = this.getPlayWidth();
            let height = this.getPlayHeight();
            if (width <= 0 || height <= 0) {
                return;
            }
            if (!this.isPlayed && posterData) {
                node.image = posterData;
                node.drawImage(0, 0, posterData.width, posterData.height, 0, 0, width, height);
            } else if (this.isPlayed) {
                this.setVideoSize();
            }
        }

        private markDirty():boolean {
            this.$renderDirty = true;
            return true;
        }
    }
    if (__global.Video) {
        egret.Video = NativeVideo;
    } else {
        egret.$warn(1044);
    }
}