/**
 * @fileOverview FilePaste
 */
define([
    '../../base',
    './runtime',
    '../../lib/file'
], function( Base, Html5Runtime, File ) {

    var $ = Base.$,
        prefix = 'webuploader-dnd-';

    return Html5Runtime.register( 'DragAndDrop', {
        init: function() {
            var elem = this.elem = this.options.container;

            this.dragEnterHandler = Base.bindFn( this._dragEnterHandler, this );
            this.dragOverHandler = Base.bindFn( this._dragOverHandler, this );
            this.dragLeaveHandler = Base.bindFn( this._dragLeaveHandler, this );
            this.dropHandler = Base.bindFn( this._dropHandler, this );
            this.dndOver = false;

            elem.on( 'dragenter', this.dragEnterHandler );
            elem.on( 'dragover', this.dragOverHandler );
            elem.on( 'dragleave', this.dragLeaveHandler );
            elem.on( 'drop', this.dropHandler );

            if ( this.options.disableGlobalDnd ) {
                $( document ).on( 'dragover', this.dragOverHandler );
                $( document ).on( 'drop', this.dropHandler );
            }
        },

        _dragEnterHandler: function( e ) {
            var me = this,
                denied = me._denied || false,
                items;

            e = e.originalEvent || e;

            if ( !me.dndOver ) {
                me.dndOver = true;

                // 注意只有 chrome 支持。
                items = e.dataTransfer.items;

                if ( items && items.length ) {
                    me._denied = denied = !me.trigger( 'accept', items );
                }

                me.elem.addClass( prefix + 'over' );
                me.elem[ denied ? 'addClass' :
                        'removeClass' ]( prefix + 'denied' );
            }

            e.dataTransfer.dropEffect = denied ? 'none' : 'copy';

            return false;
        },

        _dragOverHandler: function( e ) {
            // 只处理框内的。
            var parentElem = this.elem.parent().get( 0 );
            if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {
                return false;
            }

            clearTimeout( this._leaveTimer );
            this._dragEnterHandler.call( this, e );

            return false;
        },

        _dragLeaveHandler: function() {
            var me = this,
                handler;

            handler = function() {
                me.dndOver = false;
                me.elem.removeClass( prefix + 'over ' + prefix + 'denied' );
            };

            clearTimeout( me._leaveTimer );
            me._leaveTimer = setTimeout( handler, 100 );
            return false;
        },

        _dropHandler: function( e ) {
            var me = this,
                ruid = me.getRuid(),
                parentElem = me.elem.parent().get( 0 ),
                dataTransfer, data;

            // 只处理框内的。
            if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {
                return false;
            }

            e = e.originalEvent || e;
            dataTransfer = e.dataTransfer;

            // 如果是页面内拖拽，还不能处理，不阻止事件。
            // 此处 ie11 下会报参数错误，
            try {
                data = dataTransfer.getData('text/html');
            } catch( err ) {
            }

            if ( data ) {
                return;
            }

            me._getTansferFiles( dataTransfer, function( results ) {
                me.trigger( 'drop', $.map( results, function( file ) {
                    return new File( ruid, file );
                }) );
            });

            me.dndOver = false;
            me.elem.removeClass( prefix + 'over' );
            return false;
        },

        // 如果传入 callback 则去查看文件夹，否则只管当前文件夹。
        _getTansferFiles: function( dataTransfer, callback ) {
            var results  = [],
                promises = [],
                items, files, file, item, i, len, canAccessFolder;

            items = dataTransfer.items;
            files = dataTransfer.files;

            canAccessFolder = !!(items && items[ 0 ].webkitGetAsEntry);

            for ( i = 0, len = files.length; i < len; i++ ) {
                file = files[ i ];
                item = items && items[ i ];

                if ( canAccessFolder && item.webkitGetAsEntry().isDirectory ) {

                    promises.push( this._traverseDirectoryTree(
                            item.webkitGetAsEntry(), results ) );
                } else {
                    results.push( file );
                }
            }

            Base.when.apply( Base, promises ).done(function() {

                if ( !results.length ) {
                    return;
                }

                callback( results );
            });
        },

        _traverseDirectoryTree: function( entry, results ) {
            var deferred = Base.Deferred(),
                me = this;

            if ( entry.isFile ) {
                entry.file(function( file ) {
                    results.push( file );
                    deferred.resolve();
                });
            } else if ( entry.isDirectory ) {
                entry.createReader().readEntries(function( entries ) {
                    var len = entries.length,
                        promises = [],
                        arr = [],    // 为了保证顺序。
                        i;

                    for ( i = 0; i < len; i++ ) {
                        promises.push( me._traverseDirectoryTree(
                                entries[ i ], arr ) );
                    }

                    Base.when.apply( Base, promises ).then(function() {
                        results.push.apply( results, arr );
                        deferred.resolve();
                    }, deferred.reject );
                });
            }

            return deferred.promise();
        },

        destroy: function() {
            var elem = this.elem;

            // 还没 init 就调用 destroy
            if (!elem) {
                return;
            }
            
            elem.off( 'dragenter', this.dragEnterHandler );
            elem.off( 'dragover', this.dragOverHandler );
            elem.off( 'dragleave', this.dragLeaveHandler );
            elem.off( 'drop', this.dropHandler );

            if ( this.options.disableGlobalDnd ) {
                $( document ).off( 'dragover', this.dragOverHandler );
                $( document ).off( 'drop', this.dropHandler );
            }
        }
    });
});
