Ext.namespace('Card.panel', 'Ext.ux.data');

Card.MessageBus = new Ext.util.Observable();

Ext.onReady( function(){
    Ext.MessageBox.getDialog().getEl().addClass('msg-box');
    Ext.QuickTips.init();
});

(function(){
    var currentUserData={};
    Card.setCurrentUserData = function(userData){
        currentUserData=userData;
    };
    Card.getCurrentUserData = function(){
        return currentUserData;
    };
})();

Card.panel.Abstract = Ext.extend( Ext.Panel, {
    validate : function(){
        var valid = true;
        Ext.each( this.findByType('field'), function(field){
            if( !field.validate() ){
                valid = false;
            }
        });
        return valid;
    }
});

Ext.ux.data.GoogleSearchProxy = Ext.extend( Ext.data.DataProxy, {
    constructor : function(config){
        if( !config.api ){
            config.api = {};
            config.api[Ext.data.Api.actions.read] = true;
        }
        Ext.ux.data.GoogleSearchProxy.superclass.constructor.call(this,config);
        // now, lets get the facebook stuff.
        this.searcher = config.searcher;
        this.searcher.setSearchCompleteCallback(this, this.onSearchComplete );
        this.result = false;
        this.pageSize = 4;
        this.prepareData = config.prepareData;
    },
    
    doRequest : function(action, rs, params, reader, callback, scope, arg) {
        params = params || {};
        this._requestArgs = {
            scope : scope,
            arg : arg,
            callback : callback,
            params : params,
            rs : rs,
            reader : reader
        };
        var start = params.start || 0;
        var limit = this.pageSize;
        var page = Math.ceil( start/limit );
        if( !params.query || params.query.replace(/\s/,'') == '' ){
            this.result = [];
            this.onSearchComplete();
            return;
        }
        if( this.result && (this.lastParams && params.query == this.lastParams.query) && !params.forceRefresh ){
            this.lastParams = params;
            this.searcher.gotoPage(page);
        }
        else{
            this.lastParams = params;
            this.searcher.execute( params.query );
        }
    },
    
    onSearchComplete : function(){
        try{
            this.result = this.searcher.results;
            if( this.prepareData ){
                Ext.each( this.result, this.prepareData );
            }
            var params = this._requestArgs.params;
            Ext.apply(params, this.baseParams || {});
            var results = this._loadResults(params);
            var result = this._requestArgs.reader.readRecords(results);
            this._requestArgs.callback.call(this._requestArgs.scope, result, this._requestArgs.arg, true);
        }catch(e){
            // bad news...
            console.log(e);
            //console.log('yikes!', e);
        }
    },
    
    _loadResults : function(){
        try{
            return {
                'total' : (this.searcher.cursor.pages.length * this.pageSize),
                'root' : this.result
            };
        }catch(e){
            console.log(e);
        }
        return ret;
    }
});

Ext.ux.data.GoogleSearchStore = Ext.extend( Ext.data.Store, {
    constructor: function(config){
        config = config || {};
        Ext.apply(config, {
            totalProperty   :'total',
            root            :'root'
        });
        Ext.ux.data.GoogleSearchStore.superclass.constructor.call(this, Ext.apply(config, {
            reader: new Ext.data.JsonReader(config),
            proxy: new Ext.ux.data.GoogleSearchProxy(config)
        }));
    }
});

Card.panel.General = Ext.extend( Card.panel.Abstract, {
    constructor : function(config){
        config = config || {};
        
        this.themeStore = new Ext.data.JsonStore({
            autoDestroy         :true,
            url                 :'/themes.php',
            baseParams          :{'action':'list'},
            root                :'items',
            idProperty          :'key',
            fields              :['name','key','items'],
            listeners           :{
                scope               :this,
                load                :this.onThemeChange
            }
        });
        
        var searcher  = new google.search.ImageSearch();
        searcher.setResultSetSize(google.search.Search.SMALL_RESULTSET);
        searcher.setRestriction(google.search.ImageSearch.RESTRICT_IMAGESIZE, google.search.ImageSearch.IMAGESIZE_EXTRA_LARGE);
        
        this.bgSearchField = new Ext.ux.form.SearchField({
            width               :300,
            emptyText           :"Search for a background image",
            listeners           :{
                scope               :this,
                search              :function(){
                    this.bgStore.load();
                }
            }
        });
        
        this.bgStore = new Ext.ux.data.GoogleSearchStore({
            autoDestroy         :true,
            root                :'items',
            totalProperty       :'total',
            searcher            :searcher,
            idProperty          :'image',
            fields              :['tbUrl','tbWidth','tbHeight','url','width','height'],
            listeners           :{
                scope               :this,
                beforeload          :function(store, options){
                    if( !options.params ) options.params = {};
                    options.params.query = this.bgSearchField.getValue();
                },
                loadexception       :function(){
                    console.log(arguments);
                }
            }
        });
        this.bgView = new Ext.DataView({
            tpl                 :new Ext.XTemplate(
                '<table class="bg-image-table"><tr>',
                    '<tpl for=".">',
                        '<td><div class="bg-image-thumb">',
                            '<div class="bg-image-info">',
                                '<a href="{url}" target="_blank">{width} x {height} View Full Size</a>',
                            '</div>',
                            '<img src="{tbUrl}" width="{tbWidth}" height="{tbHeight}" />',
                        '</div></td>',
                    '</tpl>',
                '</table>'
            ),
            singleSelect        :true,
            overClass           :'bg-image-thumb-hover',
            itemSelector        :'div.bg-image-thumb',
            deferEmptyText      :false,
            emptyText           :[
                '<div style="padding: 10px;" class="welcome-message">',
                '<p>Use the Search Field above to find a background image.</p>',
                '<p>You should really check to make sure the image is okay to use. ',
                'Click the "View Full Image" link on the thumbnails to see if the image ',
                'comes up okay.</p>',
                '</div>',
            ].join(''),
            loadingText         :'Loading Images...',
            store               :this.bgStore,
            listeners           :{
                scope               :this,
                click               :function(view, index, node){
                    var r = view.store.getAt(index);
                    this.bgImageField.setValue(r.get('url'));
                },
                beforeclick         :function(view, index, item, e){
                    if( e.getTarget('a') ){
                        return false;
                    }
                    return true;
                }
            }
        });
        this.themeStore.load();
        
        Ext.apply( config, {
           
            layout              :'border',
            border              :false,
            
            items:[{
                
                layout              :'form',
                region              :'center',
                autoScroll          :true,
                bodyCssClass        :'padded-small',
                labelWidth          :150,
                defaults            :{anchor:'-20'},
                
                items               :[{
                    xtype               :'textfield',
                    fieldLabel          :'Card Name',
                    name                :'name',
                    allowBlank          :false,
                    emptyText           :'Give this a name so you can edit it later',
                    value               :''
                },{
                    xtype               :'textfield',
                    fieldLabel          :'Heading',
                    name                :'heading',
                    emptyText           :'The BIG text displayed on the card',
                    allowBlank          :false,
                    value               :''
                },{
                    xtype               :'textarea',
                    fieldLabel          :'Message',
                    name                :'message',
                    allowBlank          :true
                },{
                    xtype               :'combo',
                    fieldLabel          :'Theme',
                    ref                 :'../themeField',
                    hiddenName          :'theme',
                    forceSelection      :true,
                    triggerAction       :'all',
                    name                :'themeDisplay',
                    mode                :'local',
                    store               :this.themeStore,
                    displayField        :'name',
                    valueField          :'key',
                    listeners           :{
                        scope               :this,
                        select              :this.onThemeChange,
                        render              :this.onThemeChange
                    }
                },{
                    xtype               :'textfield',
                    name                :'bgImage',
                    fieldLabel          :'Background Image URL',
                    ref                 :'../bgImageField',
                    emptyText           :"Leave this blank for the default image"
                },{
                    xtype               :'combo',
                    forceSelection      :true,
                    hiddenName          :'bgPosition',
                    name                :'bgPositionDisplay',
                    fieldLabel          :'Background Position',
                    emptyText           :"Leave this blank for the default position",
                    displayField        :'text',
                    valueField          :'value',
                    triggerAction       :'all',
                    allowBlank          :true,
                    mode                :'local',
                    store               :new Ext.data.ArrayStore({
                        id                  :0,
                        fields              :['value','text'],
                        data                :[
                            ['top left', 'Top Left'],
                            ['top center', 'Top Center'],
                            ['top right', 'Top Right'],
                            ['left center', 'Left Center'],
                            ['center center', 'Centered'],
                            ['right center', 'Right Center'],
                            ['bottom left', 'Bottom Left'],
                            ['bottom center', 'Bottom Center'],
                            ['bottom right', 'Bottom Right']
                        ]
                    })
                }]
            },{
                layout              :'form',
                region              :'east',
                split               :true,
                width               :300,
                autoScroll          :true,
                defaults            :{anchor:'0'},
                bodyCssClass        :'padded-small',
                ref                 :'themePanel',
                title               :'Theme Settings',
                html                :'Please select a theme',
                listeners           :{
                    scope               :this,
                    render              :function(){ this.onThemeChange.defer(100,this) }
                }
            },{
                region              :'south',
                height              :170,
                tbar                :new Ext.PagingToolbar({
                    prependButtons: true,
                    pageSize: 4,
                    store: this.bgStore,
                    items: [this.bgSearchField,'->']
                }),
                items               :[this.bgView]
                
            }]
        });
        Card.panel.General.superclass.constructor.call(this, config);
        this.on('show', this._onShow, this);
        window.settingsPanel = this;
    },
    
    onThemeChange : function(){
        try{
            if( !this.themeField || !this.themePanel ) return;
            var value = this.themeField.getValue();
            if( (!value || value =='') && this.themeField.store.getCount() > 0 ){
                this.themeField.setValue( this.themeField.store.getAt(0).get('key') );
                value = this.themeField.getValue();
            }
            var r = this.themeStore.getById(value);
            if( !r ) return;
            var items = r.get('items');
            this.themePanel.removeAll();
            if( this.themePanel.body ){
                this.themePanel.body.update('');
            }
            this.themePanel.add( items );
            
            this.themePanel.doLayout();
            
            // filter out anything that is not a form parameter
            if( this.form ){
                this.form.processAdd(this.themePanel);
                
                function getUpdateObject(items, scope, obj){
                    Ext.each(items, function(item){
                        if( item.name && this.state[item.name] ){
                            obj[item.name] = this.state[item.name];
                        }
                        if( item.items){
                            getUpdateObject(item.items, scope, obj);
                        }
                    }, scope);
                }
                var update = {};
                getUpdateObject(items, this, update);
                this.form.getForm().setValues(update);
                // this is absolutely retarded.
                Ext.each(this.themePanel.findByType('radiogroup'), function(field){
                    // grab their stupid items
                    field.items.each( function(f){
                        var n = f.initialConfig.name;
                        if( this.state[n] ){
                            f.setValue(f.initialConfig.inputValue == this.state[n]);
                        }
                    }, this);
                }, this);
            }
            
            
        }catch(e){
            // shh.... 
            //console.log(e);
        }
    },
    
    _onShow : function(){
        (function(){
            Ext.each( this.findByType('field'), function(field){
                field.clearInvalid();
            });
        }).defer(100, this);
    },
    
    validate : function(){
        if( !Card.panel.General.superclass.validate.call(this) ){
            return "Looks like you might be missing some information. Hover your mouse over the squigglies on the form to see what you need to fix.";
        }
        return true;
    }
});
Ext.reg('card-general', Card.panel.General );

Ext.ux.data.FacebookProxy = Ext.extend( Ext.data.DataProxy, {
    constructor : function(config){
        if( !config.api ){
            config.api = {};
            config.api[Ext.data.Api.actions.read] = true;
        }
        Ext.ux.data.FacebookProxy.superclass.constructor.call(this,config);
        // now, lets get the facebook stuff.
        this.method = config.method;
        this.result = false;
        this.prepareData = config.prepareData;
    },
    
    doRequest : function(action, rs, params, reader, callback, scope, arg) {
        params = params || {};
        params.arguments = params.arguments || {};
        if( this.result && (this.lastArgs && params.arguments == this.lastArgs) && !params.forceRefresh ){
            var results = this._loadResults(params);
            var result = reader.readRecords(results);
            callback.call(scope, result, arg, true);
        }
        this.lastArgs = params.arguments;
        FB.Facebook.apiClient.callMethod( this.method, params.arguments, function(records){
            try{
                this.result = records;
                if( this.prepareData ){
                    Ext.each( records, this.prepareData );
                }
                Ext.apply(params, this.baseParams);
                var results = this._loadResults(params);
                var result = reader.readRecords(results);
                callback.call(scope, result, arg, true);
            }catch(e){
                // bad news...
                //console.log('yikes!', e);
            }
        }.createDelegate(this));
    },
    
    _loadResults : function(params){
        var ret ={
            'total' : this.result.length
        };
        var start = params.start || 0;
        var limit = params.limit || (this.pageSize || false);
        if( !limit ){
            ret.root = this.result;
        }
        else{
            ret.root = this.result.splice(start, (start+limit) > this.result.length ? this.result.length : (start+limit) );
        }
        return ret;
    }
});

Ext.ux.data.FacebookStore = Ext.extend( Ext.data.Store, {
    constructor: function(config){
        config = config || {};
        Ext.apply(config, {
            totalProperty   :'total',
            root            :'root'
        });
        Ext.data.JsonStore.superclass.constructor.call(this, Ext.apply(config, {
            reader: new Ext.data.JsonReader(config),
            proxy: new Ext.ux.data.FacebookProxy(config)
        }));
    }
});

Card.panel.Images = Ext.extend( Ext.Panel, {
    constructor : function(config){
        
        this.tpls={};
        this.tpls.albums = new Ext.XTemplate(
            '<div class="facebook-albums"></div>'
        );
        
        this.tpls.album = new Ext.XTemplate(
            '<tpl for=".">',
                '<div class="album" id="{div_id}">',
                    '<img src="{thumb}" width="{thumb_width}" height="{thumb_height}" />',
                    '<span>{name}</span>',
                '</div>',
            '</tpl>'
        );
        
        this.tpls.imageView = new Ext.XTemplate(
            '<div class="images-ct">',
                '<tpl for=".">',
                    '<div class="image-wrap">',
                        '<div class="image">',
                            '<img src="{thumb}" width="{thumb_x}" height="{thumb_y}"/>',
                            '<div class="checkbox"></div>',
                        '</div>',
                    '</div>',
                '</tpl>',
            '</div>'
        );
        
        this.albums = [];
        var fields = ['title','src','id','thumb','thumb_x','thumb_y','small','small_x','small_y','large','large_x','large_y'];
        
        this.albumStore = new Ext.ux.data.FacebookStore({
            autoDestroy         :true,
            storeId             :'albumStore',
            method              :'photos.get',
            idProperty          :'id',
            prepareData         :this.prepareFacebookPhotoData,
            fields              :fields
        });
        
        this.imageStore = new Ext.data.JsonStore({
            autoDestroy         :true,
            storeId             :'imageStore',
            idProperty          :'id',
            fields              :fields
        });
        this.albumStore.on('load', this.onAlbumStoreLoad, this);
        
        var self = this;
        var loadData = this.albumStore.loadData;
        this.albumStore.loadData = function(){
            self.loading=true;
            loadData.apply(this, arguments);
        };
        
        this.albumView = new Ext.DataView({
            store               :this.albumStore,
            tpl                 :this.tpls.imageView,
            multiSelect         :true,
            simpleSelect        :true,
            overClass           :'image-hover',
            itemSelector        :'div.image',
            data                :[],
            deferEmptyText      :false,
            emptyText           :'<p>Please select an album on the left to add some pictures.</p>',
            loadingText         :'Loading Images...',
            listeners           :{
                selectionchange     :this.onImageSelectionChange,
                scope               :this
            }
        });
        
        var obl = this.albumView.onBeforeLoad;
        this.albumView.onBeforeLoad = function(){
            self.loading = true;
            obl.apply(this, arguments);
            self.loading = false;
        };
        
        config = config || {};
        this.friendStore = new Ext.ux.data.FacebookStore({
            method: 'fql.query',
            baseParams : {
                arguments: {
                    'query' : "SELECT uid, name, username FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = "+FB.Connect.get_loggedInUser()+" )"
                }
            },
            fields: ['uid', 'name', 'username']
        });
        Ext.apply( config, {
            
            layout              :'border',
            html                :'',
            
            items               :[{
                region              :'west',
                layout              :'border',
                margins             :'2 1 2 2',
                title               :'Choose an Album',
                width               :180,
                split               :false,
                items               :[{
                    region              :'north',
                    autoHeight          :true,
                    layout              :'form',
                    hideLabels          :true,
                    border              :false,
                    bodyStyle           :'padding: 1px 3px;',
                    items               :[{
                        ref                 :'../../friendCombo',
                        xtype               :'combo',
                        store               :this.friendStore,
                        anchor              :'0',
                        mode                :'local',
                        valueField          :'uid',
                        triggerAction       :'all',
                        displayField        :'name',
                        listeners           :{
                            scope               :this,
                            select              :function(combo, record, index){
                                this.loadFacebookAlbums(record.get('uid'));
                            }
                        }
                    }]
                },{
                    border              :false,
                    region              :'center',
                    ref                 :'../albumPanel',
                    bodyCssClass        :'padded-small albums-panel',
                    autoScroll          :true,
                    listeners           :{
                        render              :this.renderAlbumPanel,
                        scope               :this
                    }
                }]
            },{
                region              :'center',
                title               :'Choose Images',
                bodyCssClass        :'padded-small images-panel',
                margins             :'2 2 2 1',
                ref                 :'imagePanel',
                autoScroll          :true,
                
                tbar                :[{
                    text                :'Select All',
                    ref                 :'../../selectAllBtn',
                    handler             :this.selectAll,
                    scope               :this,
                    disabled            :true
                }],
                
                items               :[this.albumView]
            }]
            
        });
        
        Card.panel.Images.superclass.constructor.call(this, config);
    },
    
    renderAlbumPanel : function(panel){
        this.tpls.albums.overwrite(panel.body.dom, {});
        panel.body.on('click', this.onAlbumPanelClick, this);
        FB.Connect.ifUserConnected(this.loadFacebookAlbums.createDelegate(this), this.addFacebookLoginButton.createDelegate(this) );
        this.friendStore.load({
            scope               :this,
            callback            :function(){
                var d = Card.getCurrentUserData();
                this.friendStore.insert(0, [new this.friendStore.reader.recordType(d)]);
                this.friendCombo.setValue(d.uid);
            }
        });
    },
    
    addFacebookLoginButton : function(){
        var albumsDiv = this.albumPanel.body.child('.facebook-albums');
        albumsDiv.update('');
        
        var loginDiv = this.albumPanel.body.child('.facebook-login');
        loginDiv.update('');
        loginDiv.createChild({
            tag			    :'fb:login-button'
        });
        FB.XFBML.Host.parseDomTree(albumsDiv.dom);
    },
    
    loadFacebookAlbums : function(uid){
        var albumsDiv = this.albumPanel.body.child('.facebook-albums');
        albumsDiv.update('<div class="albums-loading">Loading Albums<br /><img src="image/ajax-loader.gif" /></div>');
        
        // also want to add the name and logout link
        
        FB.Facebook.apiClient.photos_getAlbums(uid||FB.Connect.get_loggedInUser(),[],function(albums){
            if( Ext.type(albums) != 'array' || albums.length == 0 ){
                albumsDiv.update('<strong>Uh-oh!</strong> <br /><br />No albums to display.');
                return;
            }
            
            var pids = [];
            var albumMap = {};
            Ext.each(albums, function(album){
                pids.push(album.cover_pid);
                album.type = 'facebook';
                album.div_id = 'facebook-'+album.aid;
                albumMap[album.aid] = album;
                this.albums[album.div_id] = album;
            }, this);
            
            // this.tpl.album.overwrite(albumsDiv.dom, albums);
            FB.Facebook.apiClient.photos_get(null, null, pids, function(photos){
                Ext.each(photos, function(photo){
                    var album = albumMap[photo.aid];
                    album.thumb = photo.src;
                    album.thumb_width = photo.src_width;
                    album.thumb_height = photo.src_height;
                    
                });
                this.tpls.album.overwrite(albumsDiv.dom, albums);
                FB.XFBML.Host.parseDomTree(albumsDiv.dom);
            
            }.createDelegate(this));
        }.createDelegate(this));
    },
    
    onAlbumPanelClick : function(e, t){
        var el;
        if( !(el = e.getTarget('.album')) ){
            return;
        }
        
        // get the id...
        var album = this.albums[el.id];
        if( !album ){
            // wtf???
            alert('error.');
        }
        this.selectAllBtn.enable();
        
        if( this.activeAlbumId ){
            try{
                Ext.fly(this.activeAlbumId).removeClass('active-album');
            }catch(e){
                // this might have gone away after
                // a new user album load
            }
        }
        this.activeAlbumId = el.id;
        Ext.fly(this.activeAlbumId).addClass('active-album');
        
        var type = album.type;
        var handler = 'on'+ type.substr(0,1).toUpperCase()+type.substr(1)+ 'AlbumClick';
        
        // try to launch the proper albumHanlder
        if( this[handler] ){
            this[handler](album);
        }
    },
    
    selectAll : function(){
        this.albumView.selectRange(0, this.albumView.store.getCount());
    },
    
    onImageSelectionChange : function(view, nodes){
        if( this.loading || this.imagesLoading ) return;
        // remove any items that aren't selected.
        var selections = view.getSelectedRecords();
        view.store.each(function(image){
            if( selections.indexOf(image) != -1 ){
                this.imageStore.add(image.copy());
            }else{
                if( (record = this.imageStore.getById(image.get('id'))) ){
                    this.imageStore.remove(record);
                }
            }
        }, this);
    },
   
    onAlbumStoreLoad : function(store){
        this.loading = false;
        var s = [];
        store.each( function(record, i){
            if( this.imageStore.getById(record.get('id')) ){
                s.push(i);
            }
        }, this);
        if( s.length > 0 ){
            this.albumView.select(s, true, false);
        }
    },
    
    onFacebookAlbumClick : function(album){
        // update the store with the album images...
        this.albumStore.load({params:{arguments:{aid:album.aid}}});
        /*
        FB.Facebook.apiClient.photos_get(null, album.aid, null, function(photos){
            this.albumStore.load(photos);
        }.createDelegate(this));
        */
    },
    
    prepareFacebookPhotoData : function(photo){
        photo.thumb = photo.src;
        photo.thumb_x = photo.src_width;
        photo.thumb_y = photo.src_height;
        photo.large = photo.src_big;
        photo.large_x = photo.src_big_width;
        photo.large_y = photo.src_big_height;
        photo.small = photo.src_small;
        photo.small_x = photo.src_small_width;
        photo.small_y = photo.src_small_height;
        photo.id = 'facebook-'+photo.pid;
    },
    
    setImages : function(data){
        this.imageStore.loadData(data);
    },
    
    validate : function(){
        return this.imageStore.getCount() > 0 ? true :
            "Please select at least one picture to display. You must have at least one...";
    },
    
    getImages : function(){
        var data= [];
        this.imageStore.each(function(record){
            data.push(record.data);
        });
        return data;
    }
});
Ext.reg('card-images', Card.panel.Images );

Card.panel.Music = Ext.extend( Ext.Panel, {
    
    constructor : function( config ){
        
        var fields = ['url','title','isDefault'];
        
        this.badTracks = {};
        
        this.musicStore = new Ext.data.JsonStore({
            autoDestroy         :true,
            storeId             :'musicStore',
            idProperty          :'url',
            fields              :fields,
            listeners           :{
                scope               :this,
                add                 :this.onAddTrack,
                remove              :this.onRemoveTrack
            }
        });
        
        window.previewPlayer = this.player = new Fabs.boombox.Player();
        this.player.on('trackloaderror', this.onTrackLoadError, this);
        this.player.on('statechange', this.onPlayerStateChange,this);
        this.player.on('trackchange', this.onPlayerStateChange,this);
        this.player.on('pause', this.onPlayerStateChange,this);
        config = config || {};
        
        this.searchStore = new Ext.data.JsonStore({
            autoDestroy         :true,
            url                 :'music-search.php',
            storeId             :'musicSearchStore',
            root                :'results',
            totalProperty       :'total',
            idProperty          :'url',
            fields              :fields,
            listeners           :{
                beforeload          :function(store, options){
                    this.lastQuery = this.searchField.getValue();
                    options.params = options.params || {};
                    if( !options.params.donotchange ){
                        options.params.q =this.searchField.getValue();
                    }
                },
                load                :function(store){
                    this.parseSearchView.defer(100,this);
                    if( !store.lastOptions.add && this.searchPanel ){
                        this.searchPanel.body.dom.scrollTop=0;
                    }
                },
                scope               :this
            }
        });
        
        this.tpl = {};
        var player = this.player;
        var musicStore = this.musicStore;
        var self = this;
        this.tpl.search = new Ext.XTemplate(
            '<tpl for=".">',
                '<tpl if="xindex==1 && isDefault==true">',
                    '<p>Here are some good songs to get started with...</p>',
                '</tpl>',
                '<div class="status<tpl if="this.isAdded(url)"> added</tpl><tpl if="this.isPlaying(url)"> playing</tpl><tpl if="this.isError(url)"> error</tpl>">',
                    '<div class="song">',
                        '<div class="button addBtn"></div>',
                        '<div class="button statusBtn"></div>',
                        '<div class="title">{title}</div>',
                    '</div>',
                '</div>',
                '<tpl if="this.hasMoreRecords(xindex, xcount)===true">',
                    '<a class="more-records" href="javascript:;">',
                        'Load more songs...',
                    '</a>',
                '</tpl>',
            '</tpl>',
            {
                isAdded : function(url){
                    return musicStore.getById(url) ? true : false;
                },
                isPlaying : function(url){
                    return player._record && player._record.get('url') == url && player.isPlaying();
                },
                isError : function(url){
                    return self.badTrack(url);
                },
                hasMoreRecords : function(index, count){
                    var lastOpts = self.searchStore.lastOptions;
                    var total = self.searchStore.getTotalCount();
                    var pages = Math.ceil(total / 10);
                    var start = parseInt(lastOpts.params && lastOpts.params.start ? lastOpts.params.start : 0);
                    var page =  Math.ceil( (start+1) / 10);
                    return (index == count) && (page < pages);
                }
            }
        );
        
        this.tpl.music = new Ext.XTemplate(
            '<tpl for=".">',
                '<div class="status {[xindex]} {[xcount]} added {[xindex === 1 ? " first" : ""]}{[xindex === xcount ? " last" : ""]}<tpl if="this.isPlaying(url)"> playing</tpl><tpl if="this.isError(url)"> error</tpl>">',
                    '<div class="song">',
                        '<div class="button addBtn"></div>',
                        '<div class="button statusBtn"></div>',
                        '<div class="button orderUpBtn" title="Move Up"></div>',
                        '<div class="button orderDownBtn" title="Move Down"></div>',
                        '<div class="title">{title}</div>',
                    '</div>',
                '</div>',
            '</tpl>',
            {
                isPlaying : function(url){
                    return player._record && player._record.get('url') == url && player.isPlaying();
                },
                isError : function(url){
                    return self.badTrack(url);
                }
            }
        );
        
        this.searchView= new Ext.DataView({
            store               :this.searchStore,
            tpl                 :this.tpl.search,
            multiSelect         :true,
            simpleSelect        :true,
            overClass           :'song-hover',
            itemSelector        :'div.song',
            data                :[],
            deferEmptyText      :false,
            emptyText           :'<p>That search didn\'t bring anything up. Sorry bout that!</p><br /><p>Try a different search.</p>',
            listeners           :{
                click               :function(view, index, node, e){
                    
                    var record = this.searchStore.getAt(index);
                    
                    if( e.getTarget('.addBtn') ){
                        if( (existing = this.musicStore.getById(record.get('url'))) ){
                            this.musicStore.remove(existing);
                        }
                        else{
                            this.musicStore.add([record.copy()]);
                        }
                    }
                    else if(e.getTarget('.statusBtn')){
                        // get the record
                        this.playSong(record, this.searchStore);
                    }
                },
                scope               :this
            }
        });
        var refresh = this.searchView.refresh;
        this.searchView.refresh = function(){
            refresh.apply(this.searchView,arguments);
            this.parseSearchView.defer(100,this);
        }.createDelegate(this);
        var onAdd = this.searchView.onAdd;
        this.searchView.onAdd = function(){
            onAdd.apply(this, arguments);
            this.refresh.defer(10,this);
        };
        
        this.musicView= new Ext.DataView({
            store               :this.musicStore,
            tpl                 :this.tpl.music,
            multiSelect         :true,
            simpleSelect        :true,
            overClass           :'song-hover',
            itemSelector        :'div.song',
            data                :[],
            deferEmptyText      :false,
            emptyText           :'<p>You do not have any music yet! Add some from the left panel or click next to continue without any music for your card.</p>',
            listeners           :{
                scope               :this,
                click               :function(view, index, node, e){
                    
                    var record = this.musicStore.getAt(index);
                    
                    if( e.getTarget('.addBtn') ){
                        this.musicStore.remove(record);
                    }
                    else if(e.getTarget('.statusBtn')){
                        this.playSong(record, this.musicStore);
                    }
                    else if(e.getTarget('.orderUpBtn')){
                        if( index != 0 ){
                            this.musicStore.remove(record);
                            this.musicStore.insert(index-1,record);
                            this.musicView.refresh();
                        }
                        
                    }
                    else if(e.getTarget('.orderDownBtn')){
                        if( index < this.musicStore.getCount()-1 ){
                            this.musicStore.remove(record);
                            this.musicStore.insert(index+1,record);
                            this.musicView.refresh();
                        }
                    }
                }
            }
        });
        
        
        Ext.apply( config, {
            
            layout              :'border',
            html                :'',
            
            bbar                :[new Ext.Toolbar.TextItem({
                text                :'Now Playing:'
            }),' ',new Ext.Toolbar.TextItem({
                text                :'',
                ref                 :'../songStatus'
            }),'->',{
                text                :'',
                cls			        :'x-btn-icon',
                iconCls             :'playPause',
                disabled            :true,
                ref                 :'../playPauseBtn',
                handler             :this.togglePlay,
                scope               :this
            },{
                text                :'',
                cls			        :'x-btn-icon',
                iconCls             :'add',
                disabled            :true,
                ref                 :'../addRemoveBtn',
                handler             :this.addRemoveCurrentTrack,
                scope               :this
            }],
            
            items               :[{
                region              :'west',
                title               :"Find some sweet tunes...",
                bodyCssClass        :'padded-small music-panel',
                width               :330,
                ref                 :'searchPanel',
                autoScroll          :true,
                split               :true,
                
                tbar                :['Search:',' ',{
                    ref                 :'../../searchField',
                    xtype               :'searchfield',
                    width               :240,
                    value               :'',
                    emptyText           :"Look up some good tunes...",
                    listeners           :{
                        search              :this.search,
                        render              :function(){this.search.defer(100, this)},
                        scope               :this
                    }
                },'->',{
                    
                }],
                margins             :'2 0 2 2',
                items               :[this.searchView]
            },{
                title               :"Your Card's Playlist",
                autoScroll          :true,
                region              :'center',
                bodyCssClass        :'padded-small music-panel',
                margins             :'2 2 2 0',
                items               :[this.musicView]
            }]
        });
        Card.panel.Music.superclass.constructor.call(this, config);
        
        this.on('beforehide', this._onBeforeHide, this);
    },
    
    onTrackLoadError : function(player, track){
        var url = track.url;
        this.badTracks[url] = true;
    },
    
    badTrack : function(url){
        return this.badTracks[url];
    },
    
    _onBeforeHide : function(){
        if( this.player.isPlaying() ){ this.player.pause(); }
    },
    
    togglePlay : function(){
        this.player.togglePlay();
    },
    
    addRemoveCurrentTrack : function(){
        if( (record = this.musicStore.getById(this.player._record.get('url'))) ){
            this.musicStore.remove(record);
        }
        else{
            this.musicStore.add([this.player._record.copy()]);
        }
        this.updateAddRemoveBtn();
    },
    
    updateAddRemoveBtn : function(){
        if( this.player._record ){
            var cls = this.musicStore.getById(this.player._record.get('url')) ? 'remove' : 'add';
            this.addRemoveBtn.setIconClass(cls);
        }
    },
    
    onPlayerStateChange : function(refresh){
        if( !this.isVisible() ){ return; }
        if( this.player.isPlaying() ){
            this.playPauseBtn.enable();
            this.addRemoveBtn.enable();
            if( this.player._record ){
                this.songStatus.setText('<strong>'+this.player._record.get('title')+'</strong>');
            }
            this.playPauseBtn.setIconClass('playing');
            this.updateAddRemoveBtn();
        }
        else{
            this.playPauseBtn.setIconClass('paused');
        }
        if( refresh !== false ){
            this.musicView.refresh();
            this.searchView.refresh();
        }
    },
    
    playSong : function(record, store){
        if( this.player._record && this.player._record.get('url') == record.get('url')){
            this.togglePlay();
            return;
        }
        this.player._record = record.copy();
        soundManager.pauseAll();
        var t = new Fabs.boombox.Track(record.data);
        var oldTracks = this.player.getPlaylist().tracks;
        
        this.player.getPlaylist().clear();
        this.player.getPlaylist().addTrack(t);
        this.player.play(t);
    },
    
    onAddTrack : function(store, records, i){
        Ext.each(records, function(record){
            if( (other = this.searchStore.getById(record.get('url'))) ){
                var x = this.searchStore.indexOf(other);
                var n = this.searchView.getNode(x);
                Ext.fly(n).up('.status').addClass('added');
            }
        }, this);
        this.musicView.refresh.defer(50, this.musicView);
        this.updateAddRemoveBtn();
    },
    
    onRemoveTrack : function(store, records, i){
        Ext.each(records, function(record){
            if( (other = this.searchStore.getById(record.get('url'))) ){
                var x = this.searchStore.indexOf(other);
                var n = this.searchView.getNode(x);
                Ext.fly(n).up('.status').removeClass('added');
            }
        }, this);
        this.musicView.refresh.defer(50, this.musicView);
        this.updateAddRemoveBtn();
    },
    
    parseSearchView : function(){
        this.searchStore.each(function(record){
            if( this.musicStore.getById(record.get('url')) ){
                var x = this.searchStore.indexOf(record);
                var n = this.searchView.getNode(x);
                Ext.fly(n).up('.status').addClass('added');
            }
            // check if its playing too.
        }, this);
        var more = this.searchView.getEl().child('.more-records');
        if( more ){
            var lastOpts = this.searchStore.lastOptions;
            var total = this.searchStore.getTotalCount();
            var pages = Math.ceil(total / 10);
            var start = parseInt(lastOpts.params && lastOpts.params.start ? lastOpts.params.start : 0);
            var page =  Math.ceil( (start+1) / 10);
            if( page == pages ){
                more.remove();
            }
            else if( !more.hasClass('isListening') ){
                more.on('click', function(){
                    var lastOpts = this.searchStore.lastOptions;
                    var s = parseInt(lastOpts.params && lastOpts.params.start ? lastOpts.params.start : 0);
                    this.searchStore.load({params:{start:s+10, q:this.lastQuery, donotchange:1}, add:true});
                }, this);
                more.addClass('isListening');
            }
        }
    },
    
    search : function(){
        this.searchStore.load();
    },
    
    getMusic : function(){
        var music = [];
        this.musicStore.each(function(record){
            music.push(record.data);
        });
        return music;
    },
    
    setMusic : function(data){
        this.musicStore.loadData(data);
    }
    
});

Ext.reg('card-music', Card.panel.Music );

Card.panel.Share = Ext.extend( Ext.Panel, {
    
    constructor : function(config){
        config = config || {};
        config.bodyCssClass = "padded-body welcome-message";
        config.html = "<p>Saving your card...</p>";
        Card.panel.Share.superclass.constructor.call(this,config);
    },
    
    initComponent : function(){
        Card.panel.Share.superclass.initComponent.apply(this, arguments);
    },
    
    afterRender : function(){
        Card.panel.Share.superclass.afterRender.apply(this, arguments);
        if( this.data ){
            this.loadCard(this.data);
        }
    },
    
    loadCard : function(state){
        var url = Card.getUrl(state);
        this.body.update([
            '<p style="font-weight: bold; font-size: 1.8em;"><a target="_blank" href="',url,'">'+url+'</a></p>',
            
            '<p>Your card is done. ',
            'You can use the url above to share it with your friends, or use one of the following buttons!</p>',
            
            '<p><fb:share-button href="',url,'" type="box_count"></fb:share-button>',
            '</p>',
            
            '<p><span class="add-this"></span></p>',
            
            '<p>You can come back to <a href="http://facebookcard.com">www.facebookcard.com</a> ',
            'and get to your card whenever you like. Just connect with facebook and you will ',
            'see a button for "Your Cards".</p>'
            
        ].join(''));
        var at = this.body.child('.add-this');
        FB.XFBML.Host.parseDomTree(this.body.dom);
        addthis.button(at.dom, {
            ui_use_addressbook: true,
            services_exclude: 'print',
            services_compact: 'email,google,twitter,myspace,delicious,digg,reddit,tumblr'
        }, {url:url, title:state.heading, email_template:'facebookcard'});
    }
});

Ext.reg('card-share', Card.panel.Share );

Card.Creator = Ext.extend( Ext.form.FormPanel, {
    constructor : function(config){
        config = config || {};
        
        this.state = {card_id:0};
        
        var items = [{
            xtype               :'panel',
            title               :'Get Started',
            ref                 :'welcomePanel',
            autoScroll          :true,
            html                :Ext.fly('welcome').dom.innerHTML,
            listeners           :{
                scope               :this,
                render              :function(){ this.onWelcomeRender.defer(20,this); }
            },
            validate            :this.validateLoggedIn.createDelegate(this)
        },{
            title               :'Add Images',
            xtype               :'card-images',
            ref                 :'imagesPanel'
        },{
            title               :'Manage Music',
            xtype               :'card-music',
            ref                 :'musicPanel'
        },{
            title               :'Wrap it up',
            xtype               :'card-general',
            ref                 :'settingsPanel',
            state               :this.state
        },{
            title               :'Share Your Card!',
            xtype               :'card-share',
            ref                 :'sharePanel',
            
            listeners           :{
                scope               :this,
                show                :function(){
                    this.save( (function(){
                        this.sharePanel.loadCard(this.state);
                    }).createDelegate(this));
                }
            }
        }];
        
        var tbar = [];
        Ext.each(items, function(item, i){
            if( item.xtype != 'hidden'){
                tbar[tbar.length] = {
                    disabled            :i==0 ? false : true,
                    text                :''+(i+1)+'. '+item.title,
                    handler             :this.onStepBtnClick,
                    scope               :this
                }
            }
        }, this);
        
        Ext.apply( config, {
            
            /* General Settings */
            layout              :'card',
            buttonAlign         :'left',
            layoutConfig        :{
                deferredRender      :true
            },
            activeItem          :0,
            
            /* Item Settings */
            defaults            :{
                border              :false,
                bodyCssClass        :'padded-body',
                header              :false
            },
            items               :items,
            
            /* Top Bar */
            tbar                :tbar,
            
            /* Footer Bar */
            fbar                :[{
                text                :'Previous',
                ref                 :'./prevBtn',
                hidden              :false,
                handler             :this.previous,
                scope               :this
            },'->',{
                text                :'Next',
                ref                 :'./nextBtn',
                handler             :this.next,
                scope               :this
            },{
                text                :'Finish',
                ref                 :'./saveBtn',
                hidden              :false,
                handler             :this.finish,
                scope               :this
            }]
            
        });
        
        Card.Creator.superclass.constructor.call(this, config);
    },
    
    initComponent : function(){
        Card.Creator.superclass.initComponent.apply(this, arguments);
        this.addEvents('panelchange', 'save', 'finish');
        this.on({
            'panelchange'       :this.onPanelChange,
            scope               :this
        });
    },
    
    validateLoggedIn : function(){
        if( !FB.Connect.get_loggedInUser() ){
            return "In order to create your own card, you must log in with Facebook.\n\nIf you don't have a Facebook account, we can't help you out.";
        }
        // need to load the profile...
        if( Card.getCurrentUserData().uid == FB.Connect.get_loggedInUser() ){
            return true;
        }
        FB.Facebook.apiClient.users_getInfo(FB.Connect.get_loggedInUser(), ['username', 'name', 'uid', 'pic'], function(users){
            Card.setCurrentUserData(users[0]);
            this.fireEvent('validated', this, true);
        }.createDelegate(this));
        return {waitMsg: "Loading your profile..."};
    },
    
    onWelcomeRender : function(panel){
        var ct = this.welcomePanel.body.child('.fb-login-area');
        FB.Connect.ifUserConnected(
            function loggedIn(){
                ct.update('');
                ct.createChild({
                    tag             :'fb:profile-pic',
                    uid             :'loggedinuser',
                    size            :'normal'
                });
                ct.createChild({
                    tag             :'div',
                    cls             :'logged-in-status',
                    children        :[{
                        tag             :'span',
                        html            :'Logged in as: '
                    },{
                        tag             :'fb:name',
                        uid             :'loggedinuser',
                        useyou          :false,
                        linked          :true
                        
                    }]
                });
                var logout = ct.createChild({
                    tag             :'div',
                    cls             :'logout-ct',
                    children        :[{
                        tag             :'a',
                        cls             :'logout',
                        html            :'Log out',
                        href            :'javascript:;'
                    }]
                });
                logout.on('click', function(){
                    FB.Connect.logout();
                });
                FB.XFBML.Host.parseDomTree(ct.dom);
                FB.Facebook.apiClient.users_getInfo([FB.Connect.get_loggedInUser()],['name','pic','username','uid'],function(users){
                    Card.setCurrentUserData(users[0]);
                });
                this.updateState({uid:FB.Connect.get_loggedInUser()});
            }.createDelegate(this),
            function notLoggedIn(){
                ct.update('');
                ct.createChild({
                    tag             :'div',
                    cls             :'fb-login-button-ct',
                    children        :[{
                        tag			    :'fb:login-button'
                    }]
                });
                FB.XFBML.Host.parseDomTree(ct.dom);
            }
        );
    },
    
    afterRender : function(){
        Card.Creator.superclass.afterRender.apply(this,arguments);
        this.onPanelChange.defer(200, this, [0, this.items.getCount()] );
    },
    
    getState : function(){
        var state = this.state;
        if( this.settingsPanel && this.settingsPanel.rendered) Ext.apply( state, this.getForm().getValues() );
        if( this.imagesPanel && this.imagesPanel.rendered ) state.images = this.imagesPanel.getImages();
        if( this.musicPanel && this.musicPanel.rendered ) state.music = this.musicPanel.getMusic();
        for(var name in state){
            if( name.indexOf('ext-comp') == 0 ){
                delete state[name];
            }
        }
        return state;
    },
    
    updateState : function(object){
        this.state = Ext.apply(this.state, object);
    },
    
    onPanelChange : function(index, count){
        if( index == 0 ){
            this.saveBtn.hide();
            this.prevBtn.hide();
            this.nextBtn.show();
        }
        else if( index == count-1 ){
            this.saveBtn.show();
            this.prevBtn.show();
            this.nextBtn.hide();
        }
        else{
            this.saveBtn.hide();
            this.prevBtn.show();
            this.nextBtn.show();
        }
        this.doLayout.defer(100,this);
        this.getTopToolbar().items.itemAt(index).enable();
    },
    
    onStepBtnClick : function(btn){
        this.changePanel( this.getTopToolbar().items.indexOf(btn) );
    },
    
    changePanel : function(i){
        this.layout.setActiveItem(i);
        this.fireEvent('panelchange', i, this.items.getCount() );
    },
    
    next : function(){
        
        var i = this.items.indexOf( this.layout.activeItem )+1;
        if( i >= this.items.getCount() ){return;}
        
        if( this.layout.activeItem.validate ){
            var v = this.layout.activeItem.validate();
            if( Ext.type(v) == 'object' && v.waitMsg ){
                this.body.mask(v.waitMsg);
                this.layout.activeItem.on('validated', function(panel, valid, message){
                    this.body.unmask();
                    if( valid ){
                        this.changePanel(i);
                    }
                    else{
                        Ext.MessageBox.alert('Yikes!', v);
                    }
                }, this);
                return;
            }
            else if( Ext.type(v) == 'string' ){
                Ext.MessageBox.alert('Yikes!', v);
                return;
            }
            else if( !v ){
                return;
            }
        }
        if( this.getState().card_id ){
            this.save();
        }
        this.changePanel(i);
    },
    
    previous : function(){
        
        // if( this.layout.activeItem.validate && this.layout.activeItem.validate() ){ // go to next ;
        
        var i = this.items.indexOf( this.layout.activeItem )-1;
        // run the validation...
        if( i > -1 ){
            this.changePanel(i);
        }
        
    },
    
    save : function(cb, mask){
        var data = Ext.encode(this.getState());
        Ext.Ajax.request({
            url:'/card.php',
            params:{
                'action':'save',
                'data':data
            },
            success: function(response){
                // this should contain the card id.
                var result  = {};
                try{
                    result = Ext.decode(response.responseText);
                }catch(e){
                    result = {};
                }
                if( result.card_id ){
                    this.updateState(result);
                    if( cb ) cb();
                }
                Card.MessageBus.fireEvent('save', this.getState());
                this.fireEvent('save', this);
            },
            scope: this
        });
    },
    
    finish : function(){
        this.save();
        this.fireEvent('finish');
    }
    
});

Ext.reg('card-creator', Card.Creator);

Card.CreatorWindow = Ext.extend( Ext.Window, {
    
    constructor : function(cfg){
        cfg = cfg || {};
        Ext.apply(cfg,{
            
            title               :'Create Your Own Card',
            layout              :'fit',
            width               :750,
            height              :500,
            constrainHeader     :true,
            border              :false,
            maximizable         :true,
            
            /* Items */
            items               :[{
                xtype               :'card-creator',
                listeners           :{
                    'finish'            :this.close,
                    scope               :this
                }
            }]
        });
        Card.CreatorWindow.superclass.constructor.call(this,cfg);
        
    }
    
});
Ext.reg('card-creator-window', Card.CreatorWindow );

Card.Editor = Ext.extend( Ext.form.FormPanel, {
    constructor : function(config){
        config = config || {};
        this.state = config.data || {};
        
        var items = [{
            title               :'Manage Images',
            xtype               :'card-images',
            ref                 :'../imagesPanel',
            html                :'Add Images (log into Facebook / other social things)'
        },{
            title               :'Manage Music',
            xtype               :'card-music',
            ref                 :'../musicPanel',
            html                :'Add Music (Choose your songs with Skreemr)'
        },{
            title               :'Settings',
            bodyCssClass        :'padded-body',
            xtype               :'card-general',
            ref                 :'../settingsPanel',
            state               :this.state,
            form                :this
        },{
            title               :'Share Your Card!',
            bodyCssClass        :'padded-body',
            xtype               :'card-share',
            ref                 :'../sharePanel',
            html                :'Choose who you want to share with...',
            data                :this.state
        }];
        /*
        var tbar = [];
        Ext.each(items, function(item, i){
            if( item.xtype != 'hidden'){
                tbar[tbar.length] = {
                    disabled            :i==0 ? false : true,
                    text                :''+(i+1)+'. '+item.title,
                    handler             :this.onStepBtnClick,
                    scope               :this
                }
            }
        }, this);
        */
        
        Ext.apply( config, {
            
            /* General Settings */
            layout              :'fit',
            buttonAlign         :'left',
            layoutConfig        :{
                deferredRender      :true
            },
            
            /* Item Settings */
            defaults            :{
                border              :false
            },
            items               :[{
                xtype               :'tabpanel',
                activeItem          :0,
                items               :[items],
                listeners           :{
                    tabchange           :this.onTabChange,
                    scope               :this
                }
            }],
            
            /* Footer Bar */
            fbar                :[{
                text                :'Delete',
                ref                 :'./deleteBtn',
                handler             :this.del,
                scope               :this
            },new Ext.Toolbar.TextItem({
                ref                 :'./statusText'
            }),'->',{
                text                :'Cancel',
                ref                 :'./cancelBtn',
                hidden              :false,
                handler             :this.cancel,
                scope               :this
            },{
                text                :'Apply',
                ref                 :'./applyBtn',
                handler             :this.apply,
                scope               :this
            },{
                text                :'Save',
                ref                 :'./saveBtn',
                hidden              :false,
                handler             :this.save,
                scope               :this
            }]
            
        });
        Card.Editor.superclass.constructor.call(this, config);
        this.addEvents('save', 'cancel');
        
    },
    
    getState : function(){
        var state = this.state;
        if( this.settingsPanel && this.settingsPanel.rendered) Ext.apply( state, this.getForm().getValues() );
        if( this.imagesPanel &&  this.imagesPanel.rendered ) state.images = this.imagesPanel.getImages();
        if( this.musicPanel && this.musicPanel.rendered ) state.music = this.musicPanel.getMusic();
        for(var name in state){
            if( name.indexOf('ext-comp') == 0 ){
                delete state[name];
            }
        }
        return state;
    },
    
    updateState : function(object){
        this.state = Ext.apply(this.state, object);
        // also, lets update
    },
    
    onTabChange : function(tabPanel, tab){
        if( tab._stateLoaded ){
            return;
        }
        if( this.imagesPanel && tab == this.imagesPanel ){
            // update images
            this.imagesPanel.setImages(this.state.images);
            tab._stateLoaded = true;
        }
        else if( this.musicPanel && tab == this.musicPanel ){
            this.musicPanel.setMusic(this.state.music);
            tab._stateLoaded = true;
        }
        else if( this.settingsPanel && tab == this.settingsPanel ){
            this.getForm().setValues(this.state);
            tab._stateLoaded = true;
        }
    },
    
    _save : function(cb, mask){
        
        var data = Ext.encode(this.getState());
        if( mask ){
            this.getEl().mask('Saving...', 'x-mask-loading');
        }
        this.statusText.setText('Saving...');
        Ext.Ajax.request({
            url:'/card.php',
            params:{
                'action':'save',
                'data':data
            },
            success: function(response){
                // this should contain the card id.
                if( mask ){
                    this.getEl().unmask();
                }
                var result  = {};
                try{
                    result = Ext.decode(response.responseText);
                }catch(e){
                    result = {};
                }
                this.statusText.setText('<span style="color:green">Card Saved!</span>');
                this.statusText.setText.defer(2000, this.statusText, ['']);
                if(cb) cb(result);
                Card.MessageBus.fireEvent('save', this.getState());
            },
            scope: this
        })
        
    },
    
    apply : function(){
        this._save(function(result){
            this.fireEvent('apply');
        }.createDelegate(this));
    },
    
    save : function(mask){
        this._save(function(result){
            this.fireEvent('save');
        }.createDelegate(this), true);
    },
    
    cancel : function(){
        this.fireEvent('cancel');
    },
    
    del : function(){
        Ext.MessageBox.confirm(
            "Delete Card",
            "Are you sure you want to delete this card?",
            function(btn){
                var state = this.getState();
                this.statusText.setText('<span style="color:red">Deleting...</span>');
                if( btn == 'ok' || btn == 'yes' ){
                    Ext.Ajax.request({
                        url:'/card.php',
                        params:{
                            'action':'delete',
                            'card_id':state.card_id
                        },
                        scope: this,
                        success: function(response){
                            this.statusText.setText('Deleted');
                            this.fireEvent('delete',state.card_id);
                            this.fireEvent('cancel');
                            Card.MessageBus.fireEvent('delete', state.card_id );
                        }
                    });
                }
            },
            this
        );
    }
    
});

Ext.reg('card-editor', Card.Editor);

Card.EditorWindow = Ext.extend( Ext.Window, {
    
    constructor : function(cfg){
        cfg = cfg || {};
        Ext.apply(cfg,{
            
            title               :'Edit your card'+(cfg.data?': '+cfg.data.name:''),
            iconCls             :'edit-card',
            layout              :'fit',
            width               :750,
            height              :500,
            constrainHeader     :true,
            border              :false,
            maximizable         :true,
            
            /* Items */
            items               :[{
                xtype               :'card-editor',
                data                :cfg.data || {},
                listeners           :{
                    'cancel'            :this.close,
                    'save'              :this.close,
                    scope               :this
                }
            }]
        });
        Card.EditorWindow.superclass.constructor.call(this,cfg);
    }
    
});
Ext.reg('card-editor-window', Card.EditorWindow );

(function(){
    
    Card.getUrl = function(data){
        return 'http://'+data.uid+'.facebookcard.com/'+data.card_id;
    }
    
    var win=false;
    Card.create = function(){
        Ext.onReady(function(){
            if( !win ){
                win = new Card.CreatorWindow({
                    listeners : {
                        close : function(){
                            win = false;
                            onClose();
                        },
                        show : onShow
                    }
                });
            }
            win.show();
            win.focus();
        });
        return false; 
    };
    var cards={};
    Card.open = function(data){
        var card_id = data.card_id;
        Ext.onReady(function(){
            if( !cards[card_id] ){
                cards[card_id] = new Card.EditorWindow({
                    data: data,
                    listeners : {
                        close : function(){
                            cards[card_id] = false;
                            onClose();
                        },
                        show : onShow
                    }
                });
            }
            cards[card_id].show();
            cards[card_id].focus();
            window.cardWindow = cards[card_id];
        });
    }
    var cardCount = 0;
    function onShow(){
        cardCount++;
        if( window.snowStorm ){
            window.snowStorm.doNotResumeOnFocus=true;
            window.snowStorm.freeze();
        }
        if( window.xlsf ){
            window.xlsf.stopSequence();
        }
    }
    function onClose(){
        cardCount--;
        if( cardCount > 0 ){
            return;
        }
        if( window.snowStorm ){
            window.snowStorm.doNotResumeOnFocus=false;
            window.snowStorm.resume();
        }
        if( window.xlsf ){
            window.xlsf.startSequence();
        }
    }
})();
