/*
 * TrackList (player)
 * Requires: 
 *   jquery.js, mediaplayer_control.js, util.js
 *   jquery plugins: ui.draggable.js, ui.droppable.js
 * 
 * Handles display and filter interface for track listing.
 */

var TrackList = function() {
    return this.init.apply(this, arguments);
};

TrackList.prototype = {
    track_url: '/licensing/audiotrack/', // post url to get track listing from server
    links: 'a.track-link',  // selector used to get track links
    curent_track_id: null,
    trackCache: {},

    /*
     * player: an MediaPlayer object
     */
    init: function(player, options) {
        var self = this;
        self.player = player;
        self.container = $('#track-listing');
        $.extend(self, options);

        // Scroller
        var track_width = 455;
        $('#track-listing .scroller').bind('scrollreset', function() {
            // Listen for scroller reset to add extra padding at end.
            // This hack will allow tracks to be scrolled all the way to the left edge
            var $scroller = $(this);
            var $$ = $('<td class="scroll-pad"><div></div></td>').appendTo($('> table > tbody > tr', this));
            var $div = $$.find('div');
            var resize = function() {
                $div.css('width', $scroller.width() - track_width);
                $scroller.width( $scroller.parent().width() );
            };
            $(window).unbind('resize', resize).bind('resize', resize);
            $(window).trigger('resize');
        }).Scroller({
            horizontal: true,
            nextButtonHTML: '<a>more &#9658;</a>',
            prevButtonHTML: '<a>&#9668; back</a>',
            animate: true, animateSpeed: (track_width*2), wheelSpeed: 50
        });

        /*// Add extra buttons to track info box.
        $('<a class="addlink more-info button" href="#">more info</a>').insertBefore('#media-player')
            .click(function() {
                var $info = $(this).parent().find('#track-info');
                var $p1 = $info.find('.pane:visible');
                var $p2 = $info.find('.pane:hidden');
                $p1.hide(); 
                $p2.show();
                return false;
            });*/
        
        // Track links
        self.track_events();
    },
    
    /* 
     * Fetches track info by id and stores it in cache
     * Fires trackFeteched event when info is ready.
     */
    fetchTrackInfo: function(id) {
        var self = this;
        if (self.trackCache[id]) {
            $(self.container).trigger('trackFetched');
        } else { 
            // fetch the track with ajax call
            var url = self.track_url + id + '/';
            $.getJSON(url, function(data) {
                self.trackCache[id] = data;
                $(self.container).trigger('trackFetched');
            });
        }
    },

    /*
     * Returns the jquery dom object for the track
     * specified by id.
     */
    trackInfoDOM: function(id, animate) {
        var self = this;
        var track_data = self.trackCache[id];
        var $$ = $('<div class="track-wrapper wrapper"></div>').hide();

        // Append track info
        var $title = $('<p class="title">').appendTo($$).text(track_data.track.title);

        var $pane1 = $('<div class="pane pane-1"></div>').appendTo($$);
        var $pane2 = $('<div class="pane pane-2"></div>').appendTo($$).hide();

        var image_src = '/thumbnails/img/licensing/track_photo.jpg?size=80x80&options=detail,crop,upscale';
        var image2_src = '/thumbnails/img/licensing/track_logo.gif?size=80x80&options=detail,crop,upscale';
        if (track_data.track.logo2) {
            image2_src = '/thumbnails/' + track_data.track.logo2 + '?size=80x80&options=detail,crop,upscale';
        }
        if (track_data.track.logo) {
            image_src = '/thumbnails/' + track_data.track.logo + '?size=80x80&options=detail,crop';
        }

        /*var genres = $.map(track_data.genres, function(g) {
            return g.name            
        });
        $('<dl></dl>').append('<dt>id: </dt><dd>' + track_data.track.id + '</dd><dt>tempo: </dt><dd>' + track_data.tempo.name + '</dd>')
        .append('<dt>genres: </dt><dd>'+ genres.join(', ') +'</dd>').appendTo($pane1); */

        var $logo = $('<a></a>').attr({
            rel: track_data.track.id,
            title: 'drag me to the right to save.'
        }).addClass('track-logo').prependTo($pane1);
       
        var $img = $('<img src="" alt="" />').prependTo($logo);
        $img.attr({'src': image_src});

        var $logo2 = $('<a></a>').attr({
            rel: track_data.track.id,
            title: 'drag me to the right to save.'
        }).addClass('track-logo').appendTo($pane2);
       
        var $img2 = $('<img src="" alt="" />').prependTo($logo2);
        $img2.attr({'src': image2_src});

        $pane2.append('<div class="description">' + track_data.track.description + '</div>');

        if (animate) {
            $$.fadeIn('slow');
        } else {
            $$.show();
        }
        return $$;
    },
    
    /*
     * Shows info about the given track in the page's info box
     * Track data is an object representing the track to display
     */
    showInfo: function(id) {
        var self = this;
        var $container = $('#track-info').empty().hide();
        var $info = self.trackInfoDOM(id, true);
        $container.append($info).show();
        $('#player').show();
        
        // Hook up the Drag & Drop bookmark
        $info.find('.track-logo').draggable({
            revert: true,
            helper: 'clone',
            zIndex: 200,
            cursor: 'move',
            scroll: false
        });

        // Bookmarks Message
        $('.bookmark-list:empty').append('<li class="empty-bookmarks">drag & drop track image here to save.</li>');
    },

    /*
     * Update the track listing based on the given query.
     * query is the query string passed to the licensing index view.  
     * This method is called externally to filter the track list by genre, tempo, etc.
     */
    filter: function(query) {
        var self = this;
        $('> div.scroller', self.container).empty().load('/licensing/'+query, function(data) {
            self.track_events();
            if (self.current_track_id) {
                $('a[rel='+self.current_track_id+']').parents('.track').addClass("hover");
            }
            var scroller = $.data(this, 'scroller');
            scroller.reset();
        });
    },

    /*
     * Set up link events for playing tracks
     */
    track_events: function() {
        var self = this;
        var $links = $(self.links);

        // Link clicks
        $links.unbind('click').click(function(e, data) {
            self.track_clicked.apply(self, [this, data]);
            return false;
        }).each(function() {
            $(this).parents('.track').css('cursor', 'pointer').click(function() {
                $(this).find('a').eq(0).click();
            });
        });        
    },
    
    /*
     * Loads a track into the media player by id
     * And updates the track list.
     */
    load_track: function(id, play) {
        var self = this;
        var data = self.trackCache[id];
        var obj = {
            file : '/media/' + data.track.compressed_file,
            title: data.track.title,
            image: '/media/' + data.track.logo
        };
        
        // Load the track object
        self.player.loadTrack(obj);
        self.current_track_id = id;
        if (play) {
            self.player.playpause();                
        }
        // CSS hover effect
        var $elem = $('a[rel='+self.current_track_id+']').parents('.track');
        $('.track').removeClass('hover').removeClass('active');
        $elem.addClass('hover').addClass('active');
        
        $elem.mouseout(); // hide popup

        // Show the track info
        self.showInfo(id);
        
        // Scroll to current track
        var scroller = $.data($('.scroller', self.container)[0], 'scroller');
        scroller.scrollTo($elem);               
    },

    /*
     * Event handle when track is clicked.
     * play: boolean - whether to only load the track or play it as well.
     */
    track_clicked: function(target, play) {
        var self = this;
        var id = target.rel;
        var $$ = $(target);
        play = (typeof play == 'undefined')? true : play;

        self.require_track(id, function() {
            self.load_track(id, play);
        });

        return false;
    },

    /*
     * Fetches track by id before executing the function f
     */
    require_track: function(id, f) {
        var self = this;
        $(self.container).one('trackFetched', f);
        self.fetchTrackInfo(id);
    }
};

/*
 * TrackFilterList
 *
 * Handles the UI menu & events that will be used to filter
 * the TrackList object.
 *
 * <a class="track_filter" rel="FILTER_TYPE" href="FILTER URL"></a> 
 */

var TrackFilterList = function() {
    return this.init.apply(this, arguments);
}
TrackFilterList.prototype = {
    filter_types :['genre', 'tempo', 'scene', 'vocals', 'featured', 'featured_pop', 'usage'],
    
    /*
     * track_list: a TrackList instance
     */
    init: function(track_list) {
        var self = this;
        self.track_list = track_list;
        self.filter_links = $('#menu a.track_filter');

        // Events
        self.filter_links.toggle(
            function(e, skip_load){return self.filterOn(this, skip_load)},
            function(e, skip_load){return self.filterOff(this, skip_load)}
        );

        $('#menu a.filter-reset').click(function() {return self.reset()});

        // Set up filtes based on query string in url
        $.each(self.filter_types, function(i, type) {
            var filter_query = $.query.GET(type, true);
            $.each(filter_query, function(i, filter) {
                $('#menu a[rel='+filter+']').click();
            });
        });
    },

    /*
     * Based on a clicked link filter the TrackList by
     * the filter type.
     *
     * link: the clicked link
     * skip_load: if true, then only update the ui but do not filter the TrackList
     *            This is really only used internally.
     */
    filterOn: function(link, skip_load) {
        var self = this;
        var $$ = $(link);
        var value = link.rel;
        var type;
        $.each(self.filter_types, function(i, filter_type) {
            if ($$.is('.'+filter_type))
                type = filter_type;
        });
        if (!type) return;
        var filter = $.query.GET(type, true)
        $.each(filter, function(i, item) {
            $('#menu a.'+type+'[rel='+item+']').trigger('click', [true]);
        });
        filter = [];
        filter.push(value);
        var query = $.query.SET(type, filter);
        if (!skip_load) self.track_list.filter(query);
        $$.addClass('selected');

        // Add label indicating current filter.
        var $dt = $$.closest('dd').prev();
        $('#menu dl').accordion('activate', false);
        $dt.find('.current-filter').remove();
        var $cur = $('<span class="current-filter">'+$$.text()+'</span>')
            .hide().appendTo($dt).fadeIn();
        
        $('<a class="clear-filter">(x)</a>').appendTo($cur).click(function(e) {
            $dt.next().find('a.selected').click();
            $dt.find('> a').removeClass('active').mouseout();
            e.stopPropagation();
        });

        $dt.find("> a").addClass('active');

        return false;
    },

     /*
     * Based on a clicked link unset the TrackList filter. 
     *
     * link: the clicked link
     * skip_load: if true, then only update the ui but do not filter the TrackList
     *            This is really only used internally.
     */
    filterOff: function(link, skip_load) {
        var self = this;
        var $$ = $(link);
        var value = link.rel;
        var type;
        $.each(self.filter_types, function(i, filter_type) {
            if ($$.is('.'+filter_type))
                type = filter_type;
        });
        if (!type) return;
        var filter = $.query.GET(type, true);
        filter = $.grep(filter, function(item, i) {
            return item != value;
        });
        var query = $.query.SET(type, filter);
        if (!skip_load) self.track_list.filter(query);
        $$.removeClass('selected');

        var $dt = $$.parent().parent().prev();
        $dt.find('.current-filter').remove();

        return false;
    },

    /* 
     * Reset event to unfilter the TrackList entirely
     */
    reset: function() {
        var self = this;
        $selected = $('#menu a.selected');
        if ($selected.length > 0) {
            $selected.trigger('click', [true]);
            var query = $.query.EMPTY();
            self.track_list.filter(query);
        }
        return false;
    }
};
