ShootQ = {};
ShootQ.shared = {};
ShootQ.shared.utils = {};
ShootQ.shared.data = {};
ShootQ.shared.cookies = {};

/* Define some common namespaces */
ShootQ.guide = {};
ShootQ.correspondence = {};
ShootQ.tasks = {};
ShootQ.feeds = {};
ShootQ.marketplace = {};
ShootQ.shoots = {};
ShootQ.shoots.contract = {};
ShootQ.shoots.schedule = {};
ShootQ.relationships = {};
ShootQ.business = {};
ShootQ.business.billing = {};
ShootQ.proofing = {};
ShootQ.settings = {};
ShootQ.reminders = {};
ShootQ.csr = {};
ShootQ.search = {};
ShootQ.squad = {};
ShootQ.settings.account = {};
ShootQ.settings.account.tiers = {};
ShootQ.settings.account.branding = {};
ShootQ.settings.account.billing = {};
ShootQ.settings.account.merchant = {};
ShootQ.settings.account.datetime = {};
ShootQ.settings.account.password = {};
ShootQ.settings.account.signature = {};
ShootQ.settings.account.personnel = {};
ShootQ.settings.account.types = {};
ShootQ.settings.controlpanels = {};
ShootQ.settings.controlpanels.public = {};
ShootQ.settings.controlpanels.scheduling = {};
ShootQ.settings.controlpanels.pricing = {};
ShootQ.settings.controlpanels.workflow = {};
ShootQ.settings.controlpanels.correspondence = {};
ShootQ.settings.controlpanels.referrers = {};
ShootQ.settings.controlpanels.contracts = {};
ShootQ.settings.controlpanels.integrations = {};
ShootQ.twitter = {};

/* Support for hashchange event firing */
_lastHash = null;
_hashInterval = window.setInterval(function(){
    if(_lastHash != window.location.hash && _lastHash){
        if(ShootQ.settings.mainTabs){
            if(window.location.hash)
                ShootQ.settings.mainTabs.activate(window.location.hash.split("#")[1]);
            else
                ShootQ.settings.mainTabs.activate(0);
        }else
            window.clearInterval(_hashInterval);
    }
    _lastHash = window.location.hash;
}, 250);

if(navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i)){
    Ext.QuickTips.init = Ext.emptyFn;
    Ext.QuickTips.enable = Ext.emptyFn;
    Ext.QuickTips.disable = Ext.emptyFn;
    Ext.QuickTips.isEnabled = function(){ return false };
    Ext.QuickTips.register = Ext.emptyFn;
    Ext.QuickTips.unregister = Ext.emptyFn;
}

/* Send error reports to ErrorStack */
window.onerror = function(msg,url,l){
	try{
		var txt="_s=85daa1b738f516fd9dfcf6b569324706&_r=img";
		txt+="&Msg="+escape(msg);
		txt+="&URL="+escape(url);
		txt+="&Line="+l;
		txt+="&Platform="+escape(navigator.platform);
		txt+="&UserAgent="+escape(navigator.userAgent);
		var i = document.createElement("img");
		i.setAttribute("src", (("https:" == document.location.protocol) ? 
			"https://errorstack.appspot.com" : "http://www.errorstack.com") + "/submit?" + txt);
		i.setAttribute("style", "display:none;");			
		document.body.appendChild(i);
	}catch(e){}
};

/* Throw a default header into Ajax requests to specify to the server that it's an XHTTPRequest */
Ext.lib.Ajax.useDefaultXhrHeader = true;

/* To avoid issues w/ certain browsers, modify all Ajax requests to shove a proprietary header, 
   X-Expects-Json, onto all requests that have the 'Accept: application/json' header. */
Ext.lib.Ajax.request = Ext.lib.Ajax.request.createInterceptor(function(method, uri, cb, data, options){
    var hs = options.headers;
    if(hs && hs['Accept'] && hs['Accept'].indexOf('application/json') != -1)
        hs['X-Expects-Json'] = '1';
});

/* Some nice utility functions that are missing from JS! */
String.join = function(arr, delim){
    var str = '', delim = delim || '';
    for(var i=0;i<arr.length;i++)
        str += arr[i]+(i<(arr.length-1) ? delim : '');
    return str;
};

String.prototype.strip = function(){
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
};

String.prototype.startswith = function(term){
    return RegExp("^"+term, "g").test(this);
};

String.prototype.endswith = function(term){
    return RegExp(term+"$", "g").test(this);
};

String.prototype.truncate = function(length, suffix){
    length = length || 30;
    suffix = suffix != null ? suffix : '...';
    return this.length > length ? this.slice(0, length - suffix.length) + suffix : String(this);
};

String.prototype.capitalize = function(){ //v1.0
    return this.replace(/\w+/g, function(a){
        return a.charAt(0).toUpperCase() + a.substr(1).toLowerCase();
    });
};

/* A global Object cloning function
 * Clones a Javascript object, copying no references
*/
function clone(obj){
    if(obj == null || typeof(obj) != 'object')
        return obj;

    var temp = new obj.constructor();
    for(var key in obj)
        temp[key] = clone(obj[key]);

    return temp;
}

function sum(l){
    for(var i = 0, L = l.length, sum = 0; i < L; sum += l[i++]);
    return sum;
}

/*
 * Some functions for making a color darker or lighter
 */
var pad = function(num, totalChars) {
    var pad = '0';
    num = num + '';
    while (num.length < totalChars) {
        num = pad + num;
    }
    return num;
};

 // Ratio is between 0 and 1
 var changeColor = function(color, ratio, darker) {
    // Trim trailing/leading whitespace
    color = color.replace(/^\s*|\s*$/, '');

    // Expand three-digit hex
    color = color.replace(
     /^#?([a-f0-9])([a-f0-9])([a-f0-9])$/i,
     '#$1$1$2$2$3$3'
    );

    // Calculate ratio
    var difference = Math.round(ratio * 256) * (darker ? -1 : 1),

    // Determine if input is RGB(A)
    rgb = color.match(new RegExp('^rgba?\\(\\s*' +
        '(\\d|[1-9]\\d|1\\d{2}|2[0-4][0-9]|25[0-5])' +
        '\\s*,\\s*' +
        '(\\d|[1-9]\\d|1\\d{2}|2[0-4][0-9]|25[0-5])' +
        '\\s*,\\s*' +
        '(\\d|[1-9]\\d|1\\d{2}|2[0-4][0-9]|25[0-5])' +
        '(?:\\s*,\\s*' +
        '(0|1|0?\\.\\d+))?' +
        '\\s*\\)$'
    , 'i')),
    alpha = !!rgb && rgb[4] != null ? rgb[4] : null,
    
    // Convert hex to decimal
    decimal = !!rgb? [rgb[1], rgb[2], rgb[3]] : color.replace(
        /^#?([a-f0-9][a-f0-9])([a-f0-9][a-f0-9])([a-f0-9][a-f0-9])/i,
        function() {
            return parseInt(arguments[1], 16) + ',' +
                parseInt(arguments[2], 16) + ',' +
                parseInt(arguments[3], 16);
        }
    ).split(/,/),
    returnValue;

    // Return RGB(A)
    return !!rgb ?
    'rgb' + (alpha !== null ? 'a' : '') + '(' +
        Math[darker ? 'max' : 'min'](
            parseInt(decimal[0], 10) + difference, darker ? 0 : 255
        ) + ', ' +
        Math[darker ? 'max' : 'min'](
            parseInt(decimal[1], 10) + difference, darker ? 0 : 255
        ) + ', ' +
        Math[darker ? 'max' : 'min'](
            parseInt(decimal[2], 10) + difference, darker ? 0 : 255
        ) +
        (alpha !== null ? ', ' + alpha : '') +
        ')' :
    // Return hex
    [
        '#',
        pad(Math[darker ? 'max' : 'min'](
            parseInt(decimal[0], 10) + difference, darker ? 0 : 255
        ).toString(16), 2),
        pad(Math[darker ? 'max' : 'min'](
            parseInt(decimal[1], 10) + difference, darker ? 0 : 255
        ).toString(16), 2),
        pad(Math[darker ? 'max' : 'min'](
            parseInt(decimal[2], 10) + difference, darker ? 0 : 255
        ).toString(16), 2)
    ].join('');
 };

/* US Money validation type */
Ext.apply(Ext.form.VTypes,{
     'currency': function(){
         var re = /^\d+(\.\d{2,})?$/;
         return function(v){
             if(typeof(v) == 'string' && !v.strip()) return false;
             return re.test(parseCurrency(v));
         }
     }(),
     'currencyText' : 'Value must be a valid decimal price without commas.'
        +'<br /><br /><i>For example:</i>'
        +'<div style="margin:0 20px;">'
        +'  <img src="/images/tick.png" /> 1250.75'
        +'  <br /><img src="/images/cross.png" /> $1,250.75.'
        +'</div>'
});

/* Add a generic, "click" event to Ext.form.Fields */
Ext.form.Field.prototype.initEvents = Ext.form.Field.prototype.initEvents.createSequence(function(){
    this.el.on('click', this.fireEvent.createDelegate(this, ['click']));
});

/* TimeField's full list of AM date ranges are very obnoxious */
(function(){
    
    var times = [
        ['8:00 AM'], ['8:15 AM'], ['8:30 AM'], ['8:45 AM'], 
        ['9:00 AM'], ['9:15 AM'], ['9:30 AM'], ['9:45 AM'],
        ['10:00 AM'], ['10:15 AM'], ['10:30 AM'], ['10:45 AM'],
        ['11:00 AM'], ['11:15 AM'], ['11:30 AM'], ['11:45 AM'], 
        ['12:00 PM'], ['12:15 PM'], ['12:30 PM'], ['12:45 PM'], 
        ['1:00 PM'], ['1:15 PM'], ['1:30 PM'], ['1:45 PM'],
        ['2:00 PM'], ['2:15 PM'], ['2:30 PM'], ['2:45 PM'], 
        ['3:00 PM'], ['3:15 PM'], ['3:30 PM'], ['3:45 PM'],
        ['4:00 PM'], ['4:15 PM'], ['4:30 PM'], ['4:45 PM'],
        ['5:00 PM'], ['5:15 PM'], ['5:30 PM'], ['5:45 PM'],
        ['6:00 PM'], ['6:15 PM'], ['6:30 PM'], ['6:45 PM'],
        ['7:00 PM'], ['7:15 PM'], ['7:30 PM'], ['7:45 PM'],
        ['8:00 PM'], ['8:15 PM'], ['8:30 PM'], ['8:45 PM'], 
        ['9:00 PM'], ['9:15 PM'], ['9:30 PM'], ['9:45 PM'],
        ['10:00 PM'], ['10:15 PM'], ['10:30 PM'], ['10:45 PM'],
        ['11:00 PM'], ['11:15 PM'], ['11:30 PM'], ['11:45 PM'],
        ['12:00 AM'], ['12:15 AM'], ['12:30 AM'], ['12:45 AM'],
        ['1:00 AM'], ['1:15 AM'], ['1:30 AM'], ['1:45 AM'],
        ['2:00 AM'], ['2:15 AM'], ['2:30 AM'], ['2:45 AM'],
        ['3:00 AM'], ['3:15 AM'], ['3:30 AM'], ['3:45 AM'],
        ['4:00 AM'], ['4:15 AM'], ['4:30 AM'], ['4:45 AM'],
        ['5:00 AM'], ['5:15 AM'], ['5:30 AM'], ['5:45 AM'],
        ['6:00 AM'], ['6:15 AM'], ['6:30 AM'], ['6:45 AM'],
        ['7:00 AM'], ['7:15 AM'], ['7:30 AM'], ['7:45 AM'] 
    ];
     
    Ext.form.TimeField.prototype.store = new Ext.data.SimpleStore({
        fields: ['text'],
        data : times
    });
    Ext.form.TimeField.prototype.displayField = 'text';
})();

/* Ext's email regular expression is broken due to a
 * Safari regex bug that will plague most users
*/
Ext.apply(Ext.form.VTypes,{
     'email': function(){
         var re = /^[a-zA-Z0-9._%'+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
         return function(v){
             return re.test(v);
         }
     }()
});

/* Used to format money to 2 decimal places */
parseCurrency = function(v){
    var o = v;
    v = (Math.round((v-0)*100))/100;
    v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
    if(isNaN(v))
        return o;
    return String(v);
};

/* Used to format percentages to X decimal places */
parsePercentage = function(v, x){
    var o = v;
    var b = Math.pow(10, x);
    v = (Math.round((v-0)*b))/b;
    v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
    if(isNaN(v))
        return o;
    return String(v);
};


/* A Javascript Math.round that doesn't blow */
var round = Math.round;
Math.round = function(number, precision){
    if(precision)
        return round(number * Math.pow(10, precision)) / Math.pow(10, precision);
    return round(number)
}

/* Disable selection styles on the grid element */
ShootQ.shared.utils.disableSelection = function(element) {
    element.onselectstart = function() {
        return false;
    };
    element.unselectable = "on";
    element.style.MozUserSelect = "none";
    element.style.cursor = "default";
}

ShootQ.shared.utils.injectContent = function(dom, url){
    Ext.Ajax.request({
        url: url,
        method: 'GET',
        success: function(response){
            dom.innerHTML = '';
            dom.innerHTML = response.responseText;
        }
    });
      
};
    
Ext.form.HtmlEditor.prototype.createLink = function(){
    var url = prompt(this.createLinkText, this.defaultLinkValue);
    if(url && url != 'http:/'+'/'){
        if(!url.startswith('http'))
            url = 'http://'+url;
        if(!String(this.win.getSelection()).length)
            this.relayCmd('inserthtml', '<a href="'+url+'">'+url+'</a>');
        else
            this.relayCmd('createlink', url);
    }
};
Ext.form.HtmlEditor.prototype.createToolbar = Ext.form.HtmlEditor.prototype.createToolbar.createSequence(function(editor){
        
    function btn(id, toggle, handler){
        return {
            itemId : id,
            cls : 'x-btn-icon',
            iconCls: 'x-edit-'+id,
            enableToggle:toggle !== false,
            scope: editor,
            handler:handler||editor.relayBtnCmd,
            clickEvent:'mousedown',
            tooltip: Ext.QuickTips && Ext.QuickTips.isEnabled() ? editor.buttonTips[id] || undefined : undefined,
            tabIndex:-1
        };
    }
        
    if(Ext.isSafari){    
        if(this.enableLinks)
            this.tb.add('-', btn('createlink', false, this.createLink));

        if(this.enableLists)
            this.tb.add('-', btn('insertorderedlist'), btn('insertunorderedlist'));
    }
        
    this.createImageText = 'Please enter the URL for the image:';
    
    var index = this.tb.items.findIndex('itemId', 'createlink');
    if(index < 0) return;
    this.tb.insertButton(index+1, btn('insertimage', false, function(){
        var url = prompt(this.createImageText, this.defaultLinkValue);
        if(url && url != 'http:/'+'/'){
            this.relayCmd('inserthtml', '<img src="'+url+'" alt="An image" />');
        } 
    }.createDelegate(this)));
        
});

/* Add an option to Ext.form.ComboBox to auto-load remote stores directly after rendering */
Ext.form.ComboBox.prototype.doForce = function(){
    if(this.forceSelection){
        if(this.el.dom.value.length > 0){
            this.f =
                this.lastSelectionText === undefined ? '' : this.lastSelectionText;
            this.applyEmptyText();
        }
    }
};
Ext.form.ComboBox.prototype.onRender = Ext.form.ComboBox.prototype.onRender.createSequence(function(){
    if(this.triggerAction == 'all' && this.autoLoadStore){
        this.doQuery(this.allQuery, true);
        this.store.on('load', function(){
            this.store.loaded = true;
            this.setValue(this.getValue());
        }, this);
    }
});

/* Give Ext.grid.EditorGridPanel a new event for determining when editing has been cancelled */
Ext.data.Store.prototype.loadData = Ext.data.Store.prototype.loadData.createInterceptor(function(){
    this.on("load", function(){
        this.loaded = true;
    }, this);
});
Ext.data.Store.prototype.loadRecords = Ext.data.Store.prototype.loadRecords.createInterceptor(function(){
    this.on("load", function(){
        this.loaded = true;
    }, this);
});

/* Add support for metaKey detection to Ext's KeyMap */
Ext.KeyMap.prototype.checkModifiers = function(config, e){
    var val, key, keys = ['shift', 'ctrl', 'alt', 'meta'];
    for (var i = 0, len = keys.length; i < len; ++i){
        key = keys[i];
        val = config[key];
        if(!(val === undefined || (val === e[key + 'Key']))){
            return false;
        }
    }
    return true;
},

/* Add a date events to Ext.DatePicker */
Ext.DatePicker.prototype.onRender = Ext.DatePicker.prototype.onRender.createSequence(function(){
    this.addEvents({
        'update': true
    });
});
Ext.DatePicker.prototype.update = Ext.DatePicker.prototype.update.createSequence(function(){
    this.fireEvent('update', this);
});

/* Give Ext.grid.GridPanel a global QuickTip event handler */
Ext.grid.GridPanel.prototype.onRender = Ext.grid.GridPanel.prototype.onRender.createSequence(function(){
    this.addEvents({'beforetooltipshow': true});
    Ext.ToolTip.prototype.onTargetOver = Ext.ToolTip.prototype.onTargetOver.createInterceptor(function(e) {
		this.baseTarget = e.getTarget();
    });
    Ext.ToolTip.prototype.onMouseMove = Ext.ToolTip.prototype.onMouseMove.createInterceptor(function(e) {
		if (!e.within(this.baseTarget)) {
			this.onTargetOver(e);
			return false;
		}
	});    
    this.tooltip = new Ext.ToolTip({
    	renderTo: Ext.getBody(),
    	target: this.view.mainBody,
    	autoHide: true,
    	listeners: {
    		beforeshow: function(qt){
    			var v = this.getView();
	            var row = v.findRowIndex(qt.baseTarget);
	            var cell = v.findCellIndex(qt.baseTarget);
	            this.fireEvent("beforetooltipshow", this, row);
	            return qt.body.dom.innerHTML != ""; // If the tooltip is empty, don't display it!
    		},
    		scope: this
    	}
    });
});

/* A RowExpander extension for Ext.grid.GridPanel */

/*
 * Ext JS Library 2.2.1
 * Copyright(c) 2006-2009, Ext JS, LLC.
 * licensing@extjs.com
 * 
 * http://extjs.com/license
 */

Ext.grid.RowExpander = function(config){
    Ext.apply(this, config);

    this.addEvents({
        beforeexpand : true,
        expand: true,
        beforecollapse: true,
        collapse: true
    });

    Ext.grid.RowExpander.superclass.constructor.call(this);

    if(this.tpl){
        if(typeof this.tpl == 'string'){
            this.tpl = new Ext.Template(this.tpl);
        }
        this.tpl.compile();
    }

    this.state = {};
    this.bodyContent = {};
};

Ext.extend(Ext.grid.RowExpander, Ext.util.Observable, {
    header: "",
    width: 20,
    sortable: false,
    fixed:true,
    dataIndex: 'expander',
    id: 'expander',
    lazyRender: true,

    getRowClass : function(record, rowIndex, p, ds){
        p.cols = p.cols-1;
        var content = this.bodyContent[record.id];
        if(!content && !this.lazyRender){
            content = this.getBodyContent(record, rowIndex);
        }
        if(content){
            p.body = content;
        }
        return this.state[record.id] ? 'x-grid3-row-expanded' : 'x-grid3-row-collapsed';
    },

    init : function(grid){
        this.grid = grid;

        var view = grid.getView();
        view.getRowClass = this.getRowClass.createDelegate(this);

        view.enableRowBody = true;

        grid.on('render', function(){
            view.mainBody.on('mousedown', this.onMouseDown, this);
        }, this);
    },

    getBodyContent : function(record, index, body){
        content = this.tpl.apply(record.data);
        return content;
    },

    onMouseDown : function(e, t){
        if(t.className == 'x-grid3-row-expander'){
            e.stopEvent();
            var row = e.getTarget('.x-grid3-row');
            this.toggleRow(row);
        }
    },

    renderer : function(v, p, record){
        p.cellAttr = 'rowspan="2"';
        return '<div class="x-grid3-row-expander">&#160;</div>';
    },

    beforeExpand : function(record, body, rowIndex){
        if(this.fireEvent('beforeexpand', this, record, body, rowIndex) !== false){
            if(this.tpl && this.lazyRender){
                body.innerHTML = this.getBodyContent(record, rowIndex, body);
            }
            return true;
        }else{
            return false;
        }
    },

    toggleRow : function(row){
        if(typeof row == 'number'){
            row = this.grid.view.getRow(row);
        }
        this[Ext.fly(row).hasClass('x-grid3-row-collapsed') ? 'expandRow' : 'collapseRow'](row);
    },

    expandRow : function(row){
        this.collapseAll();
        if(typeof row == 'number'){
            row = this.grid.view.getRow(row);
        }        
        var record = this.grid.store.getAt(row.rowIndex);
        var body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row);
        this.grid.getSelectionModel().selectRecords([record]);
        if(this.beforeExpand(record, body, row.rowIndex)){
            this.state[record.id] = true;
            Ext.fly(row).replaceClass('x-grid3-row-collapsed', 'x-grid3-row-expanded');
            this.fireEvent('expand', this, record, body, row.rowIndex);
        }
    },

    collapseRow : function(row){
        if(typeof row == 'number'){
            row = this.grid.view.getRow(row);
        }
        var record = this.grid.store.getAt(row.rowIndex);
        var body = Ext.fly(row).child('tr:nth(1) div.x-grid3-row-body', true);
        if(this.fireEvent('beforecollapse', this, record, body, row.rowIndex) !== false){
            this.state[record.id] = false;
            Ext.fly(row).replaceClass('x-grid3-row-expanded', 'x-grid3-row-collapsed');
            this.fireEvent('collapse', this, record, body, row.rowIndex);
        }
    },
    
    collapseAll: function(){
        Ext.each(this.grid.view.getRows(), function(r){
            this.collapseRow(r);
        }, this)
    }
    
});

/* Inject all ComboBoxes with a custom class property */
Ext.form.ComboBox.prototype.defaultAutoCreate['cls'] = 'x-combobox';


/* Shared static data sets */

ShootQ.shared.data.states = [
    ['AL', 'Alabama'],
    ['AK', 'Alaska'],
    ['AZ', 'Arizona'],
    ['AR', 'Arkansas'],
    ['CA', 'California'],
    ['CO', 'Colorado'],
    ['CT', 'Connecticut'],
    ['DE', 'Delaware'],
    ['DC', 'District of Columbia'],
    ['FL', 'Florida'],
    ['GA', 'Georgia'],
    ['GU', 'Guam'],
    ['HI', 'Hawaii'],
    ['ID', 'Idaho'],
    ['IL', 'Illinois'],
    ['IN', 'Indiana'],
    ['IA', 'Iowa'],
    ['KS', 'Kansas'],
    ['KY', 'Kentucky'],
    ['LA', 'Louisiana'],
    ['ME', 'Maine'],
    ['MD', 'Maryland'],
    ['MA', 'Massachusetts'],
    ['MI', 'Michigan'],
    ['MN', 'Minnesota'],
    ['MS', 'Mississippi'],
    ['MO', 'Missouri'],
    ['MT', 'Montana'],
    ['NE', 'Nebraska'],
    ['NV', 'Nevada'],
    ['NH', 'New Hampshire'],
    ['NJ', 'New Jersey'],
    ['NM', 'New Mexico'],
    ['NY', 'New York'],
    ['NC', 'North Carolina'],
    ['ND', 'North Dakota'],
    ['OH', 'Ohio'],
    ['OK', 'Oklahoma'],
    ['OR', 'Oregon'],
    ['PA', 'Pennsylvania'],
    ['PR', 'Puerto Rico'],
    ['RI', 'Rhode Island'],
    ['SC', 'South Carolina'],
    ['SD', 'South Dakota'],
    ['TN', 'Tennessee'],
    ['TX', 'Texas'],
    ['UT', 'Utah'],
    ['VI', 'Virgin Islands'],
    ['VT', 'Vermont'],
    ['VA', 'Virginia'],
    ['WA', 'Washington'],
    ['WV', 'West Virginia'],
    ['WI', 'Wisconsin'],
    ['WY', 'Wyoming']
];
ShootQ.shared.data.provinces = {
    'US': ShootQ.shared.data.states,
    'CA': [
        ["AB", "Alberta"],
        ["BC", "British Columbia"],
        ["MB", "Manitoba"],
        ["NB", "New Brunswick"],
        ["NL", "Newfoundland and Labrador"],
        ["NS", "Nova Scotia"],
        ["NT", "Northwest Territories"],
        ["NU", "Nunavut"],
        ["ON", "Ontario"],
        ["PE", "Prince Edward Island"],
        ["QC", "Quebec"],
        ["SK", "Saskatchewan"],
        ["YT", "Yukon"]
    ]
};

ShootQ.shared.data.months = [
    [1, 'January'],
    [2, 'February'],
    [3, 'March'],
    [4, 'April'],
    [5, 'May'],
    [6, 'June'],
    [7, 'July'],
    [8, 'August'],
    [9, 'September'],
    [10, 'October'],
    [11, 'November'],
    [12, 'December']
];


ShootQ.shared.data.countries = [
    ['US', 'United States'],
    ['CA', 'Canada'],
    ['AF', 'Afghanistan'],
    ['AL', 'Albania'],
    ['DZ', 'Algeria'],
    ['AS', 'American Samoa'],
    ['AD', 'Andorra'],
    ['AO', 'Angola'],
    ['AI', 'Anguilla'],
    ['AQ', 'Antarctica'],
    ['AG', 'Antigua and Barbuda'],
    ['AR', 'Argentina'],
    ['AM', 'Armenia'],
    ['AW', 'Aruba'],
    ['AU', 'Australia'],
    ['AT', 'Austria'],
    ['AZ', 'Azerbaidjan'],
    ['BS', 'Bahamas'],
    ['BH', 'Bahrain'],
    ['BD', 'Bangladesh'],
    ['BB', 'Barbados'],
    ['BY', 'Belarus'],
    ['BE', 'Belgium'],
    ['BZ', 'Belize'],
    ['BJ', 'Benin'],
    ['BM', 'Bermuda'],
    ['BT', 'Bhutan'],
    ['BO', 'Bolivia'],
    ['BA', 'Bosnia-Herzegovina'],
    ['BW', 'Botswana'],
    ['BV', 'Bouvet Island'],
    ['BR', 'Brazil'],
    ['IO', 'British Indian Ocean Territory'],
    ['BN', 'Brunei Darussalam'],
    ['BG', 'Bulgaria'],
    ['BF', 'Burkina Faso'],
    ['BI', 'Burundi'],
    ['KH', 'Cambodia'],
    ['CM', 'Cameroon'],
    ['CV', 'Cape Verde'],
    ['KY', 'Cayman Islands'],
    ['CF', 'Central African Republic'],
    ['TD', 'Chad'],
    ['CL', 'Chile'],
    ['CN', 'China'],
    ['CX', 'Christmas Island'],
    ['CC', 'Cocos (Keeling) Islands'],
    ['CO', 'Colombia'],
    ['KM', 'Comoros'],
    ['CG', 'Congo'],
    ['CK', 'Cook Islands'],
    ['CR', 'Costa Rica'],
    ['HR', 'Croatia'],
    ['CU', 'Cuba'],
    ['CY', 'Cyprus'],
    ['CZ', 'Czech Republic'],
    ['DK', 'Denmark'],
    ['DJ', 'Djibouti'],
    ['DM', 'Dominica'],
    ['DO', 'Dominican Republic'],
    ['TP', 'East Timor'],
    ['EC', 'Ecuador'],
    ['EG', 'Egypt'],
    ['SV', 'El Salvador'],
    ['GQ', 'Equatorial Guinea'],
    ['ER', 'Eritrea'],
    ['EE', 'Estonia'],
    ['ET', 'Ethiopia'],
    ['FK', 'Falkland Islands'],
    ['FO', 'Faroe Islands'],
    ['FJ', 'Fiji'],
    ['FI', 'Finland'],
    ['CS', 'Former Czechoslovakia'],
    ['SU', 'Former USSR'],
    ['FR', 'France'],
    ['FX', 'France (European Territory)'],
    ['GF', 'French Guyana'],
    ['TF', 'French Southern Territories'],
    ['GA', 'Gabon'],
    ['GM', 'Gambia'],
    ['GE', 'Georgia'],
    ['DE', 'Germany'],
    ['GH', 'Ghana'],
    ['GI', 'Gibraltar'],
    ['GB', 'Great Britain'],
    ['GR', 'Greece'],
    ['GL', 'Greenland'],
    ['GD', 'Grenada'],
    ['GP', 'Guadeloupe (French)'],
    ['GU', 'Guam (USA)'],
    ['GT', 'Guatemala'],
    ['GN', 'Guinea'],
    ['GW', 'Guinea Bissau'],
    ['GY', 'Guyana'],
    ['HT', 'Haiti'],
    ['HM', 'Heard and McDonald Islands'],
    ['HN', 'Honduras'],
    ['HK', 'Hong Kong'],
    ['HU', 'Hungary'],
    ['IS', 'Iceland'],
    ['IN', 'India'],
    ['ID', 'Indonesia'],
    ['INT', 'International'],
    ['IR', 'Iran'],
    ['IQ', 'Iraq'],
    ['IE', 'Ireland'],
    ['IL', 'Israel'],
    ['IT', 'Italy'],
    ['CI', 'Ivory Coast (Cote D\'Ivoire)'],
    ['JM', 'Jamaica'],
    ['JP', 'Japan'],
    ['JO', 'Jordan'],
    ['KZ', 'Kazakhstan'],
    ['KE', 'Kenya'],
    ['KI', 'Kiribati'],
    ['KW', 'Kuwait'],
    ['KG', 'Kyrgyzstan'],
    ['LA', 'Laos'],
    ['LV', 'Latvia'],
    ['LB', 'Lebanon'],
    ['LS', 'Lesotho'],
    ['LR', 'Liberia'],
    ['LY', 'Libya'],
    ['LI', 'Liechtenstein'],
    ['LT', 'Lithuania'],
    ['LU', 'Luxembourg'],
    ['MO', 'Macau'],
    ['MK', 'Macedonia'],
    ['MG', 'Madagascar'],
    ['MW', 'Malawi'],
    ['MY', 'Malaysia'],
    ['MV', 'Maldives'],
    ['ML', 'Mali'],
    ['MT', 'Malta'],
    ['MH', 'Marshall Islands'],
    ['MQ', 'Martinique (French)'],
    ['MR', 'Mauritania'],
    ['MU', 'Mauritius'],
    ['YT', 'Mayotte'],
    ['MX', 'Mexico'],
    ['FM', 'Micronesia'],
    ['MD', 'Moldavia'],
    ['MC', 'Monaco'],
    ['MN', 'Mongolia'],
    ['MS', 'Montserrat'],
    ['MA', 'Morocco'],
    ['MZ', 'Mozambique'],
    ['MM', 'Myanmar'],
    ['NA', 'Namibia'],
    ['NR', 'Nauru'],
    ['NP', 'Nepal'],
    ['NL', 'Netherlands'],
    ['AN', 'Netherlands Antilles'],
    ['NT', 'Neutral Zone'],
    ['NC', 'New Caledonia (French)'],
    ['NZ', 'New Zealand'],
    ['NI', 'Nicaragua'],
    ['NE', 'Niger'],
    ['NG', 'Nigeria'],
    ['NU', 'Niue'],
    ['NF', 'Norfolk Island'],
    ['KP', 'North Korea'],
    ['MP', 'Northern Mariana Islands'],
    ['NO', 'Norway'],
    ['OM', 'Oman'],
    ['PK', 'Pakistan'],
    ['PW', 'Palau'],
    ['PA', 'Panama'],
    ['PG', 'Papua New Guinea'],
    ['PY', 'Paraguay'],
    ['PE', 'Peru'],
    ['PH', 'Philippines'],
    ['PN', 'Pitcairn Island'],
    ['PL', 'Poland'],
    ['PF', 'Polynesia (French)'],
    ['PT', 'Portugal'],
    ['PR', 'Puerto Rico'],
    ['QA', 'Qatar'],
    ['RE', 'Reunion (French)'],
    ['RO', 'Romania'],
    ['RU', 'Russian Federation'],
    ['RW', 'Rwanda'],
    ['GS', 'S. Georgia & S. Sandwich Isls.'],
    ['SH', 'Saint Helena'],
    ['KN', 'Saint Kitts & Nevis Anguilla'],
    ['LC', 'Saint Lucia'],
    ['PM', 'Saint Pierre and Miquelon'],
    ['ST', 'Saint Tome (Sao Tome) and Principe'],
    ['VC', 'Saint Vincent & Grenadines'],
    ['WS', 'Samoa'],
    ['SM', 'San Marino'],
    ['SA', 'Saudi Arabia'],
    ['SN', 'Senegal'],
    ['SC', 'Seychelles'],
    ['SL', 'Sierra Leone'],
    ['SG', 'Singapore'],
    ['SK', 'Slovak Republic'],
    ['SI', 'Slovenia'],
    ['SB', 'Solomon Islands'],
    ['SO', 'Somalia'],
    ['ZA', 'South Africa'],
    ['KR', 'South Korea'],
    ['ES', 'Spain'],
    ['LK', 'Sri Lanka'],
    ['SD', 'Sudan'],
    ['SR', 'Suriname'],
    ['SJ', 'Svalbard and Jan Mayen Islands'],
    ['SZ', 'Swaziland'],
    ['SE', 'Sweden'],
    ['CH', 'Switzerland'],
    ['SY', 'Syria'],
    ['TJ', 'Tadjikistan'],
    ['TW', 'Taiwan'],
    ['TZ', 'Tanzania'],
    ['TH', 'Thailand'],
    ['TG', 'Togo'],
    ['TK', 'Tokelau'],
    ['TO', 'Tonga'],
    ['TT', 'Trinidad and Tobago'],
    ['TN', 'Tunisia'],
    ['TR', 'Turkey'],
    ['TM', 'Turkmenistan'],
    ['TC', 'Turks and Caicos Islands'],
    ['TV', 'Tuvalu'],
    ['UG', 'Uganda'],
    ['UA', 'Ukraine'],
    ['AE', 'United Arab Emirates'],
    ['GB', 'United Kingdom'],
    ['UY', 'Uruguay'],
    ['MIL', 'USA Military'],
    ['UM', 'USA Minor Outlying Islands'],
    ['UZ', 'Uzbekistan'],
    ['VU', 'Vanuatu'],
    ['VA', 'Vatican City State'],
    ['VE', 'Venezuela'],
    ['VN', 'Vietnam'],
    ['VG', 'Virgin Islands (British)'],
    ['VI', 'Virgin Islands (USA)'],
    ['WF', 'Wallis and Futuna Islands'],
    ['EH', 'Western Sahara'],
    ['YE', 'Yemen'],
    ['YU', 'Yugoslavia'],
    ['ZR', 'Zaire'],
    ['ZM', 'Zambia'],
    ['ZW', 'Zimbabwe']
];

ShootQ.twitter.newTweet = function(v){
    
    var un = Ext.get('twitter-un').dom.value;
    var d = new Ext.Window({
        modal: true,
        layout: 'fit',
        shadow: true,
        proxyDrag: true,
        resizable: false,
        title: '<img src="/images/twitter_icon.png" style="float: left; margin-right: 5px; margin-top: -1px" height="16" /> Send a Tweet (@'+un+')',
        items: [{
            id: 'tweetBox',
            xtype: 'textarea',
            width: 325,
            height: 75,
            value: v
        }],
        buttons: [{
            text: 'Post',
            handler: function(){
                var textarea = Ext.getCmp('tweetBox');
                var value = textarea.getValue();
                if(value){
                    var mask = Ext.Msg.wait('Sending...', 'Sending...');                
                    Ext.Ajax.request({
                        url: '/tw/tweet',
                        method: "POST",
                        params: {
                            'msg': value
                        },
                        success: function(response){
                            mask.hide();
                            var r = Ext.decode(response.responseText);
                            var success = r.success;
                            ShootQ.twitter.tweetDialog.hide();
                            ShootQ.twitter.tweetDialog.destroy();
                            if(!success)
                                Ext.Msg.alert('Error', r.error);   
                        }
                    });
                }
            }
        }]
    });
    
    ShootQ.twitter.tweetDialog = d;
    d.show();
    
    ShootQ.twitter.tweetDialog.footer.child('div').createChild({tag: 'span', html: v ? v.length : '0', cls: 'counter', style:'position:absolute;bottom:20px;opacity:.5;font-size:16px;'});
    
    var textarea = Ext.getCmp('tweetBox');
    var updateCounter = function(){
        var length = textarea.getValue().length;
        var counter = Ext.query('span.counter', ShootQ.twitter.tweetDialog.footer.child('div').dom)[0];        
        counter.innerHTML = Math.min(140, length);
        if(length > 139){
            textarea.setValue(textarea.getValue().truncate(140, ''));
            return false;
        }
    };
    textarea.el.on('keyup', updateCounter);    
    textarea.el.on('keydown', updateCounter);
    textarea.el.dom.focus();
};

/* Global `Current Brand` selection */
ShootQ.shared.selectBrand = function(brandID, path){
    var conn = new Ext.data.Connection();
    conn.request({
        url: '/login',
        params: {
            'brandID': brandID
        },
        method: 'POST',
        callback: function(){
            if (path) window.location = path;
            else window.location.reload();
        }
    });
}

ShootQ.shared.toggleBrandSelection = function(){
    ShootQ.shared.toggleBrandTask = new Ext.util.DelayedTask(
        ShootQ.shared.hideBrandSelection
    );
    
    var i = Ext.query("#topnav div.brand-menu")[0];
    Ext.get(i).setStyle('display', (Ext.get(i).getStyle('display') == 'block') ?
        'none' : 'block');
    if(Ext.get(i).getStyle('block') == 'block')
        ShootQ.shared.toggleBrandTask.delay(1200);
    
    Ext.get(Ext.query("#topnav div.brand-menu")[0]).on('mouseover', function(){
        Ext.get(Ext.query("#topnav div.brand-menu")[0]).setStyle('display', 'block');
        ShootQ.shared.toggleBrandTask.delay(1200);
    });
    
};

ShootQ.shared.hideBrandSelection = function(){
    Ext.each(Ext.query("#topnav div.brand-menu")[0], function(i){
        Ext.get(i).setStyle('display', 'none');
    });
};


ShootQ.shared.toggleCSRMenu = function(){
    ShootQ.shared.toggleCSRTask = new Ext.util.DelayedTask(
        ShootQ.shared.hideCSRMenu
    );
    
    var i = Ext.query("#topnav div.csr-menu")[0];
    Ext.get(i).setStyle('display', (Ext.get(i).getStyle('display') == 'block') ?
        'none' : 'block');
    if(Ext.get(i).getStyle('block') == 'block')
        ShootQ.shared.toggleCSRTask.delay(1200);
    
    Ext.get(Ext.query("#topnav div.csr-menu")[0]).on('mouseover', function(){
        Ext.get(Ext.query("#topnav div.csr-menu")[0]).setStyle('display', 'block');
        ShootQ.shared.toggleCSRTask.delay(1200);
    });
    
};

ShootQ.shared.hideCSRMenu = function(){
    Ext.each(Ext.query("#topnav div.csr-menu")[0], function(i){
        Ext.get(i).setStyle('display', 'none');
    });
};


/* Tooltips */
ShootQ.shared.initToolTips = function(force) {
    if (Ext.get('enable-tooltips')) {
        Ext.get('enable-tooltips').on('mouseover', function() {
            Ext.get('enable-tooltips').dom.childNodes[1].src = '/images/lightbulb.png';
        });
        Ext.get('enable-tooltips').on('mouseout', function() {
            Ext.get('enable-tooltips').dom.childNodes[1].src = '/images/lightbulb_off.png';
        });
        Ext.get('disable-tooltips').on('mouseover', function() {
            Ext.get('disable-tooltips').dom.childNodes[1].src = '/images/lightbulb_off.png';
        });
        Ext.get('disable-tooltips').on('mouseout', function() {
            Ext.get('disable-tooltips').dom.childNodes[1].src = '/images/lightbulb.png';
        });
    }
    
    if (!force && Ext.get('show_tooltips') && Ext.get('show_tooltips').getValue() != "1") return;
    
    Ext.apply(Ext.QuickTips.getQuickTip(), {
        maxWidth: 200,
        minWidth: 100,
        showDelay: 50,
        trackMouse: false,
        dismissDelay: 0
    });
    
    var items = Ext.query('a[title]');
    for (var i = 0; i < items.length; i++) {
        var html = '';
        var target = items[i];
        var nodes = items[i].childNodes;
        for(var index in nodes){
            var node = nodes[index];
            if(!node.tagName && node.nodeValue && node.nodeValue.trim()) {
                html = node.nodeValue;
                html = Ext.util.Format.trim(html);
                break;
            }
        }
        if(!html || html.length == 0) {
            for(var index in nodes){
                var node = nodes[index];
                if(node.tagName && (node.tagName.toLowerCase() == 'img')) {
                    html = node.alt;
                    target = node;
                }
            }
        };
        
        ShootQ.shared.registerTooltip(target, html, items[i].title);
        items[i].title = null;
    };
};


ShootQ.shared.registerTooltip = function(target, title, text) {
    Ext.QuickTips.register({
         target: target,
         title: '<div style="padding: 5px; font-size: 12px; text-transform: capitalize">'+
                '<img src="/images/lightbulb.png" align="top" style="margin-right: 5px;" />'+
                title+'</div>',
         text: '<div style="padding: 5px">'+text+'</div>',
         width: 200,
         dismissDelay: 0
    });
};


ShootQ.shared.toggleToolTips = function(enable) {
    Ext.get('enable-tooltips').setVisibilityMode(Ext.Element.DISPLAY);
    Ext.get('disable-tooltips').setVisibilityMode(Ext.Element.DISPLAY);
    
    var conn = new Ext.data.Connection();
    conn.request({
        url: '/toggle_tooltips',
        method: 'POST',
        jsonData: {dummy: 'dummy'},
        callback: function(options, success, response) {
            if (success) {
                if (enable) {
                    Ext.QuickTips.enable();
                    ShootQ.shared.initToolTips(true);
                    Ext.get('enable-tooltips').hide();
                    Ext.get('disable-tooltips').show();
                } else {
                    Ext.QuickTips.disable();
                    Ext.get('enable-tooltips').show();
                    Ext.get('disable-tooltips').hide();
                }
            }
        }
    });
};

/* help enable and disable */
ShootQ.shared.disableToolTips = function() {
    ShootQ.shared.toggleToolTips(false);
};

ShootQ.shared.enableToolTips = function() {
    ShootQ.shared.toggleToolTips(true);
};

/* Prefetch account-wide categories */
ShootQ.reminders.categoryMap = {};
ShootQ.reminders.categories = [];
ShootQ.reminders.fetchCategories = function(callbacks) {
    Ext.Ajax.request({
      url: '/categories',
      method: 'GET',
      success: function(response){
          var cats = Ext.decode(response.responseText)['categories'];
          Ext.each(cats, function(t){
              ShootQ.reminders.categoryMap[t.id] = t.category;
              ShootQ.reminders.categories.push({
                  id      : t.id,
                  label   : t.category
              });
          });
          Ext.each(callbacks, function(callback) {if(typeof(callback) == 'function'){ callback(); }});
      }
    });
};

/* quick task form */
ShootQ.shared.reminderForm = null;
ShootQ.shared.createForm = function(cb, shootUUID) {
    var makeForm = function() {
        ShootQ.shared.reminderForm = new Ext.ux.Reminder({
            'url': '/tasks/create',
            'categories': ShootQ.reminders.categories,
            'columns': false,
            'allowCancel': false,
            'hideButton': true,
            'uuid': shootUUID,
            'success': function(){
                if (!shootUUID) {
                    Ext.MessageBox.show({
                        title: 'Task Created',
                        msg: 'Your task was created! You can find it in your <b>Tasks</b> tab.',
                        icon: Ext.MessageBox.INFO,
                        buttons: {ok:'Take Me There', cancel: 'Stay Here'},
                        closable: false,
                        fn: function(btn) {
                            if (btn == 'ok') 
                                window.location = Ext.get('nav-Tasks').dom.href;
                            this.hide();
                        }
                    });
                } else {
                    ShootQ.shoots.mainTabs.setActiveGroup('tasksPanel');
                    var group = ShootQ.shoots.mainTabs.lookupGroup('tasksPanel');
                    group.setActiveTab(group.getMainItem());
                    ShootQ.shoots.mainTabs.fireEvent('groupchange', ShootQ.shoots.mainTabs, ShootQ.shoots.mainTabs.activeGroup);
                    this.hide();
                }
            }
        });
        cb();
    };
    
    if (ShootQ.reminders.categories.length == 0)
        ShootQ.reminders.fetchCategories(makeForm);
    else
        makeForm();
};


ShootQ.shared.createNewReminder = function() {
    var shootUUID = null;
    if (Ext.get('currentShootUUID'))
        shootUUID = Ext.get('currentShootUUID').getValue();
    
    ShootQ.shared.createForm(function() {
        var dialog = new Ext.Window({
            modal: true,
            width: 300,
            autoHeight: true,
            shadow: true,
            y: (window.innerHeight / 2) - 150,
            proxyDrag: true,
            resizable: false,
            title: '<img src="/images/time_add.png" /> New Task',
            buttons: [{
                text: 'Cancel',
                handler: function(){
                    dialog.hide();
                    dialog.destroy();
                }
            },{
                text: 'Create',
                handler: function() {
                    dialog.hide();
                    dialog.destroy();
                    ShootQ.shared.reminderForm.submit();
                }
            }]
        });

        dialog.show();
        ShootQ.shared.reminderForm.render(dialog.body.dom);
        ShootQ.shared.reminderForm.show('fadeIn');        
    }, shootUUID);    
};


/* change calendar user */
ShootQ.shared.changeCalendarUser = function(el){
    var value = el.options[el.selectedIndex].value;
    var wait = new Ext.LoadMask(Ext.getBody());
    wait.show();
    Ext.Ajax.request({
        url: '/calendar/switch/'+value,
        success: function(){
            window.location.reload();
        },
        failure: function(){
            wait.hide();
        }
    })
};


/* quick lead form */
ShootQ.shared.updateQuickLeadName = function() {
    var first_name = Ext.get('ql_first_name').getValue();    
    var last_name = Ext.get('ql_last_name').getValue();
    var shoot_type = ShootQ.shared.quickLeadTypeSelector.getValue();
    var shoot_name = '';
    if (first_name.length > 0)
        shoot_name += first_name + ' ';    
    if (last_name.length > 0)
        shoot_name += last_name + ' ';
    if (shoot_type != 'Select a shoot type...') {
        if (shoot_type == 'job') shoot_type = 'shoot';
        shoot_name += shoot_type.substring(0,1).toUpperCase() + shoot_type.substring(1, shoot_type.length);
    }
    
    Ext.get('ql_shoot_name').dom.value = shoot_name;
};

ShootQ.shared.doQuickLeadMatch = function() {
    ShootQ.shared.performFuzzyContactSearch({
        first_name: Ext.get('ql_first_name').getValue(),
        last_name: Ext.get('ql_last_name').getValue(),
        company_name: ''
    }, ShootQ.shared.showMatchDialog);  
};

ShootQ.shared.performFuzzyContactSearch = function(values, callback) {
    var conn = new Ext.data.Connection();
    conn.request({
        url: '/relationships/fuzzy_search',
        method: 'GET',
        params: {
            first_name: values.first_name,
            last_name: values.last_name,
            company_name: values.company_name
        },
        callback: function(options, success, response) {
            if (success) {
                var result = Ext.util.JSON.decode(response.responseText);
                if (result.matches.length > 0) {
                    callback(result.matches);
                } else {
                    Ext.get('ql_contact_id').dom.value = null;
                }
            }
        }
    });
};

ShootQ.shared.match_dialog = null;
ShootQ.shared.matches = null;
ShootQ.shared.showMatchDialog = function(matches) {
    ShootQ.shared.matches = matches;
    
    if(ShootQ.shared.match_dialog == null){
        var dialog = new Ext.Window({
            y: 75,
            modal: true,
            width: 400,
            autoHeight: true,
            shadow: true,
            proxyDrag: true,
            resizable: true,
            title: 'Potential Matches',
            buttons: [{
                text: 'Cancel',
                handler: function(){
                    dialog.hide();
                }
            }]
        })
        ShootQ.shared.match_dialog = dialog;
    }

    var contents = '<div style="padding: 10px; background: white;">';
    contents += '<p>The following people are already in your relationship database.  ';
    contents += 'If any of the following people match the person you are entering, click on ';
    contents += 'their name.  Otherwise, click the cancel button.</p><br/>';
    Ext.each(matches, function(match, i) {
        contents += '&nbsp;&nbsp;&bull;&nbsp;&nbsp;'
        contents += '<a href="#" onclick="ShootQ.shared.selectMatch('+i+'); return false;">';
        contents += match.first_name + ' ' + match.last_name;
        if(match.is_company)
            contents += ' ('+match.company_name+')';
        contents += '</a>';
        if (match.phones.length > 0) {
            contents += ' &mdash; ';
            contents += match.phones[0].number;
        }
        if (match.emails.length > 0) {
            contents += ' &mdash; ';
            contents += match.emails[0].email;
        }
        contents += '<br />';
    });
    contents += '</ul>';
    
    ShootQ.shared.match_dialog.show();
    ShootQ.shared.match_dialog.body.dom.innerHTML = contents;
};

ShootQ.shared.selectMatch = function(index) {
    var match = ShootQ.shared.matches[index];
    
    Ext.get('ql_first_name').dom.value = match.first_name;
    Ext.get('ql_last_name').dom.value = match.last_name;
    Ext.get('ql_contact_id').dom.value = match.id;
    
    if (match.phones.length > 0)
        Ext.get('ql_home_phone').dom.value = match.phones[0].number;
    else
        Ext.get('ql_home_phone').dom.value = '';
    
    if (match.emails.length > 0)
        Ext.get('ql_home_email').dom.value = match.emails[0].email;
    else
        Ext.get('ql_home_email').dom.value = '';
        
    ShootQ.shared.match_dialog.hide();
};


ShootQ.shared.currentCheckDate = null;
ShootQ.shared.checkAvailability = function(date, excludes, callback) {
    if (!callback) callback = ShootQ.shared.showConflicts;
    if (ShootQ.shared.currentCheckDate == date.toUTCString()) return;
    ShootQ.shared.currentCheckDate = date.toUTCString();
    if (ShootQ.shared.availability[date] == undefined) {
        var c = Ext.get('availablility-results-contents');
        if(c)
            c.dom.innerHTML = ['<div class="head">',
                '   <img src="/images/search.png" style="float: left;"/>',
                '   <h3 style="font-size: 12px">Searching for Conflicts...</h3>',
                '</div>',
                '<div class="body">',
                '   <center><img width="25" src="/images/loading.gif" /></center>',
                '</div>',
                '<div class="foot" />'].join('')
        Ext.Ajax.request({
            url: '/availability',
            method: 'POST',
            params: {
                date: date.getTime(),
                excludes: excludes ? Ext.encode([excludes]) : null
            },
            headers: {'Accept': 'application/json'},
            success: function(response) {
                var conflicts = Ext.decode(response.responseText).conflicts;
                ShootQ.shared.availability[date] = conflicts;
                callback(date);
            }
        });
    } else {
        callback(date);
    }
};


ShootQ.shared.generateConflictHTML = function(date) {
    var conflicts = ShootQ.shared.availability[date];
    
    var header_html = '<div class="head">';
    if (conflicts.length) {
        header_html += '<img src="/images/warning.png" style="float: left;"/>' +
                       '<h3 style="font-size: 12px">Potential Conflicts</h3>';
    } else {
        header_html += '<img src="/images/tick.png" style="float: left"/>' +
                       '<h3 style="font-size: 12px">No Known Conflicts</h3>';
    }
    header_html += '</div>';
    
    var body_html = '<div class="body">';
    if(conflicts.length) {
        Ext.get('availability-results').addClass('warning');
        var contents = new Ext.XTemplate('<ul>'
            +'  <tpl for="conflicts">'
            +'      <tpl if="values.msg">'
            +'          <tpl for="values.msg">'
            +'              <li style="padding:5px 0 0 22px;">'
            +'                  <a href="#" onclick="return false;" ext:qtip="{list}">'
            +'                      {message}'
            +'                  </a>'
            +'              </li>'
            +'          </tpl>'
            +'      </tpl>'
            +'      <tpl if="values.feed_name">'
            +'          <li style="clear:both;"><img src="/images/feed.png" style="float:left;margin:-2px 7px 0 0;" /> {feed_name} - {name}</li>'
            +'      </tpl>'
            +'      <tpl if="values.uuid">'
            +'          <li style="clear:both;"><img src="/images/camera.png" style="float:left;margin:-2px 7px 0 0;" /> <a href="/shoots/{uuid}" target="_blank" ext:qtip="{[values.photographer_names && values.photographer_names.length ? \"<b>Assigned Photographers</b>:<br /> \"+values.photographer_names.join(\", \") : \"\"]}">{name}</a><tpl if="status">- <b>{status}</b></tpl></li>'
            +'      </tpl>'
            +'  </tpl>'
            +'</ul>'
        ).apply({
            conflicts: conflicts
        });
        body_html += contents;
    } else {
        body_html += 'No known conflicts on this date.';
    }
    body_html += '</div><div class="foot" />';
    
    return header_html + body_html;
};


ShootQ.shared.showConflicts = function(date) {
    var cloned = clone(ShootQ.shared.availability[date]);
    var conflicts = ShootQ.shared.availability[date];
    var limit = 3;
    if(conflicts.length > limit){
        var num = conflicts.length - limit;
        var list = [];
        while(conflicts.length > limit){
            var c = conflicts.pop();
            var match = false;
            Ext.each(['feed_owner', 'feed_brand'], function(t){
                if(c[t]){
                    list.push([
                        c[t],
                        c.name   
                    ].join(' - '))
                    match = true;
                }
            });
            if(!match)
                list.push([c.name, c.status].join(' - '));
        }
        conflicts.push({
            'msg': {
                'message':  [num, ' more...'].join(' '),
                'list': list.join('<br />')
            }
        })
    }
    var html = ShootQ.shared.generateConflictHTML(date);
    ShootQ.shared.availability[date] = cloned;
    
    var box = Ext.get('availability-results');
    box.setVisibilityMode(Ext.Element.DISPLAY);
    if (box.isVisible()) {
        box.fadeOut({
            callback: function() {
                Ext.get('availablility-results-contents').dom.innerHTML = html;
                box.fadeIn();
            }
        })
    } else {
        Ext.get('availablility-results-contents').dom.innerHTML = html;
        box.fadeIn();
    }
};


ShootQ.shared.submitQuickLead = function() {
    Ext.get('ql-create').dom.disabled = 'disabled';
    
    /* gather params */
    var params = {
        relationships: [
            {
                roles      : [],
                contact_id : Ext.get('ql_contact_id').getValue(),
                first_name : Ext.get('ql_first_name').getValue(),
                last_name  : Ext.get('ql_last_name').getValue(),
                phone      : Ext.get('ql_home_phone').getValue(),
                email      : Ext.get('ql_home_email').getValue()
            }
        ],
        job_type                : ShootQ.shared.quickLeadTypeSelector.getValue(),
        name                    : Ext.get('ql_shoot_name').getValue(),
        remarks                 : Ext.get('ql_remarks').getValue(),
        date                    : ShootQ.shared.quickLeadDatePicker.getValue(),
        all_day                 : Ext.get('ql_all_day').dom.checked ? true : false,
        photography_start_time  : ShootQ.shared.quickLeadStartTime ? ShootQ.shared.quickLeadStartTime.getValue() : null,
        photography_end_time    : ShootQ.shared.quickLeadStopTime ? ShootQ.shared.quickLeadStopTime.getValue() : null,
        job_status              : 'Lead'
    };
    
    /* validate */
    var validate_email = function(email) {
        if (email.length == 0) return true;
        return Ext.form.VTypes.email(email);
    };
    
    var errors = '';
    if ((params.relationships[0].first_name.length == 0) || (params.relationships[0].last_name.length == 0))
        errors += '&bull; You must enter a first and last name.<br/>';
    if (!validate_email(params.relationships[0].email))
        errors += '&bull; You must enter a valid email address.<br/>';
    if (params.job_type == '')
        errors += '&bull; Please select a shoot type.<br/>';
    if (params.name.length == 0)
        errors += '&bull; You must enter a name for this shoot.<br/>';
    if ((!ShootQ.shared.quickLeadDatePicker.isValid()))
        errors += '&bull; Please select a valid date for this shoot.<br/>';
    
    /* display validation message */
    if (errors.length > 0) {
        Ext.Msg.show({
           title: 'Missing Information',
           style: 'text-align: left;',
           msg: '<div style="border: 1px solid #666; background: white; padding: 10px;">' +
                errors +
                '</div>',
           width: 350,
           buttons: Ext.MessageBox.OK,
           animEl: 'ql-create'
        });
        Ext.get('ql-create').dom.disabled = '';
        return false;
    }
    
    /* format date */
    if(params.date)
        params.date = (params.date.getMonth()+1)+'/'+params.date.getDate()+'/'+params.date.getFullYear();
    
    /* submit the lead to the server */
    Ext.Ajax.request({
        url: '/shoots/create/create',
        method: 'POST',
        params: {shoot:Ext.encode(params)},
        headers: {'Accept': 'application/json'},
        success: function(response) {
            var r = Ext.decode(response.responseText);
            if (r.result) {
                window.location = '/shoots/'+r.uuid;
            };
        }
    });
};


ShootQ.shared.getShootTypeSelector = function(target, config) {
    if (target) Ext.get(target).dom.innerHTML = '';
    
    if (!config) config = {};
    config = Ext.apply({
        store: config.store ? config.store : new Ext.data.ArrayStore({
            url: '/account/custom_types/types',
            fields: ['type', {name: 'locked', type: 'boolean'}],
            autoLoad: true
        }),
        fieldLabel: 'Shoot Type',
        displayField: 'type',
        valueField: 'type',
        editable: false,
        width: 150,
        style: 'clear: both',
        mode: 'remote',
        triggerAction: 'all',
        msgTarget: 'qtip',
        renderTo: target        
    }, config);
    
    return new Ext.form.ComboBox(config);
};


ShootQ.shared.quickLeadDatePicker = null;
ShootQ.shared.availability = {};
ShootQ.shared.quickLead = function() {        
    /* render the date field */
    ShootQ.shared.quickLeadDatePicker = new Ext.ux.AvailabilityField({
        fieldLabel: 'Lead Date',
        name: 'shoot_date',
        allowBlank: true,
        lazy: false
    });
        
    /* render and display the form */
    var q = Ext.get('quick-lead');
    q.enableDisplayMode('display');
    scroll(0,0);
    
    if (q.isVisible()) {
        q.slideOut('t');
    } else {
        q.slideIn('t', {callback: function() { 
            Ext.get('ql_shoot_date').dom.innerHTML = '';
            ShootQ.shared.quickLeadDatePicker.render('ql_shoot_date');
            
            Ext.get('ql_all_day').on('click', function(){
                var start = Ext.get('ql_start_time').dom;
                var stop = Ext.get('ql_stop_time').dom; 
                
                if(this.dom.checked){
                    start.innerHTML = '';
                    stop.innerHTML = '';
                    Ext.get('ql_time').hide();
                    delete ShootQ.shared.quickLeadStartTime;
                    delete ShootQ.shared.quickLeadStopTime;
                }else{
                    Ext.get('ql_time').show();                    
                    ShootQ.shared.quickLeadStartTime = new Ext.form.TimeField({
                        width: 80
                    });
                    ShootQ.shared.quickLeadStartTime.render(start);
                    ShootQ.shared.quickLeadStopTime = new Ext.form.TimeField({
                        width: 80
                    });
                    ShootQ.shared.quickLeadStopTime.render(stop);
                }
            });
            
            /* render the shoot type selector */
            ShootQ.shared.quickLeadTypeSelector = ShootQ.shared.getShootTypeSelector('ql_shoot_type');
            ShootQ.shared.quickLeadTypeSelector.on('select', ShootQ.shared.updateQuickLeadName);
        }});
    }
};

Ext.TabPanel.prototype.afterRender = Ext.TabPanel.prototype.afterRender.createSequence(function(){
    if(this.initialConfig.cls == 'tabs-center'){
        var width = 0;
        Ext.each(Ext.query('li', this.stripWrap.dom), function(li){
           width += Ext.get(li).getComputedWidth();
        });
        this.stripWrap.child('ul').setWidth(width + 15);
    }
});

ShootQ.settings.confirmTo = function(uri){
    if(ShootQ.settings.changesMade){
        ShootQ.settings.wrapConfirmation(
            function(args){
                window.location = uri;
            }, []
        )();
    }else
        window.location = uri;
};

ShootQ.settings.confirmDo = function(cb){
    if(ShootQ.settings.changesMade){
        ShootQ.settings.wrapConfirmation(cb, [])();
    }else
        cb();
};

ShootQ.settings.goBack = function() {
    var location = '/controlpanels';
    if (Ext.get('control-panels-back-location'))
        location = Ext.get('control-panels-back-location').getValue();
    window.location = location;
};

ShootQ.settings.initTabs = function(wrap){
    
    if(!Ext.get('tabpanel'))
        return;
    
    if(wrap != false)
        wrap = true;
        
    var items = [];
    ShootQ.settings.mainTabs = new Ext.TabPanel({
        renderTo: 'tabpanel',
        activeTab: 0,
        width: 1172,
        autoShow: true,
        plain: true,
        border: false,
        cls: window.location.toString().indexOf('/relationships') != -1 ? '' : 'tabs-center',
        defaults: {autoHeight: true},
        bodyStyle: {background: 'transparent'},
        items: (function(){
            Ext.select('.panelbody').each(function(t, o, index){
                if(t.dom.title){
                    items.push({
                        contentEl   : t.dom.id, 
                        title       : t.dom.title,
                        id          : t.dom.id,
                        itemId      : t.dom.id,
                        cls         : (function(){
                            if(t.hasClass('x-side-bar')) return 'x-side-bar';
                            if(t.hasClass('x-pricing-bg')) return 'x-pricing-bg';
                            return null;
                        })(),
                        tabCls      : (function(){
                            var i = index;
                            if(Ext.query('.panelbody').length == 1)
                                return 'x-tab-first x-tab-last';
                            if(i == 0)
                                return 'x-tab-first';
                            if(Ext.query('.panelbody').length == i+1)
                                return 'x-tab-last';
                        })()
                    }); 
                    t.dom.removeAttribute('title');
                }
            });
            return items;
        })(),
        listeners: {
            'tabchange': function(panel, tab){
                var wrap = Ext.get(tab.contentEl).parent('.x-tab-panel-body');
                if(Ext.get(tab.contentEl).hasClass('x-side-bar'))
                    wrap.setStyle('background-image', 'url(/images/settings-side-bar.png)');
                else if(Ext.get(tab.contentEl).hasClass('x-pricing-bg')){
                    wrap.setStyle('background-image', 'url(/images/settings-pricing-bar.png)');
                }else
                    wrap.setStyle('background', 'transparent');
                wrap.setStyle('background-repeat', 'repeat-y');
            },
            'afterrender': function(){
                if(window.location.toString().indexOf('/relationships') == -1){
                    Ext.get('pagecontent').createChild({
                        html:'<br/><button onclick="ShootQ.settings.goBack();">Back</button>'
                    });
                
                    if(window.location.hash){
                        var id = window.location.hash.split("#")[1];
                        this.setActiveTab(id);
                        /* 
                         * Defer momentarily so that we can wait for other
                         * other sources to register tabchange listeners
                         * 
                         * Otherwise, we'll fire the initial tabchange before
                         * listeners have had a chance to register.
                         */
                        (function(){
                            this.fireEvent('beforetabchange', this, this.getComponent(id));                        
                            this.fireEvent('tabchange', this, this.getComponent(id));
                        }).defer(50, this);
                    }
                }
            }
        }
    });
    
    /* When a tab is switch, notify the user of unsaved changes */
    if(wrap){
        var switchTabs = function(tabpanel, newTab, currentTab){
            if(ShootQ.settings.changesMade){
                ShootQ.settings.wrapConfirmation(
                    function(args){
                        ShootQ.settings.changesMade = false; // Otherwise `beforetabchange` will fire again!
                        args[0].activate(args[1]);
                    },
                    [tabpanel, newTab, currentTab]
                )();
                return false;
            }
        };

        ShootQ.settings.mainTabs.on('beforetabchange', switchTabs);
    }
    
    ShootQ.settings.mainTabs.on('tabchange', function(c, tab){
        window.location = window.location.pathname+'#'+tab.id;
        window.scroll(0, 0);
    });    
    
    // Switch the tab style to bottom positioning
    var strips = Ext.select('.x-tab-strip-top');
    strips.removeClass('x-tab-strip-top');
    strips.addClass('x-tab-strip-bottom');
    
    // Hide the tabs if there's only one
    if(items.length == 1)
        strips.hide();
    
};

ShootQ.settings.playHelpVideo = function(){
    Ext.get('help-bar-video').setStyle('display', 'block');
    window.scrollTo(0, Ext.get('help-bar-video').getTop());
};

/*
 * Detect unsaved changes and warn the user before they leave the page
 */
window.onbeforeunload = function(){
    if(ShootQ.settings.changesMade && ShootQ.shared.cookies.readCookie('shootq-show-warnings') != 'no')
        return 'It looks like you might have unsaved changes. Are you sure you want to navigate away without saving your changes?';
};

/* Used to wrap a given function with a `Potential Lost Changes` warning.
   Anytime the function is called, a warning dialog will display if the
   user still has unsaved changes
   @param - fn - The function to wrap
   @param - args - An array of arguments to pass to the wrapped function
   @returns The wrapped function
*/
ShootQ.settings.wrapConfirmation = function(fn, args){
    var msg = 'It looks like you might have unsaved changes. '+
              'Are you sure you want to navigate away without saving your changes?';
              
    if(!ShootQ.settings.changesMade)
        return fn;
        
    return fn.createInterceptor(function(){
        if (ShootQ.shared.cookies.readCookie('shootq-show-warnings') != 'no') {
            var dialog = new Ext.Window({
                modal: true,
                width: 400,
                height: 170,
                shadow: true,
                title: 'Unsaved Changes',
                items: [{              
                    xtype: 'labelfield',
                    html: msg,
                    style: 'padding: 15px;'
                },{
                    xtype: 'checkbox',
                    style: 'margin: 10px 0 10px 20px',
                    boxLabel: 'Don\'t show me this message again.',
                    id: 'dont-show-message'
                }],
                buttons: [{
                    text: 'Yes',
                    handler: function(){
                        if (Ext.getCmp('dont-show-message').getValue()) {
                            ShootQ.shared.cookies.createCookie('shootq-show-warnings', 'no', 360);
                        } else {
                            ShootQ.shared.cookies.eraseCookie('shootq-show-warnings');
                        }
                        fn(args);                 
                        dialog.hide();
                    }
                },{
                    text: 'No, Keep Me Here',
                    handler: function(){
                        dialog.hide();
                    }
                }]
            });
            dialog.show();
        } else {
            fn(args);
        }
        return false;
    });
};

/* Handles applying the appropriate highlighting styles when an item
   is clicked on
   @param id - the DOM of the <li> that is selected
*/
ShootQ.settings.applySelectionStyles = function(item){
    item.addClass('selected');
    
    // Loop through all siblings and change their style */
    var prev = item.prev();
    while(prev){
        prev.removeClass('selected');
        prev = prev.prev();
    }
    var next = item.next();
    while(next){
        next.removeClass('selected');
        next = next.next();
    }
    Ext.select('.removebutton').each(function(el){
       el.dom.disabled = false; 
    });
};

/* Relationship Lookup */
ShootQ.shared.lookupConfig = {
    xtype: 'textfield',
    labelSeparator: '',
    autoCreate: {
        tag: 'p',
        value: '', 
        html: '<img src="/images/search.png" style="float:left;margin:0 5px 0 5px;" /> Lookup',
        qtip: 'Click here to search for an existing relationship.',
        style: 'font-style:normal !important;margin:0 0 10px 10px;padding:3px 12px 3px 3px;overflow:hidden;cursor:pointer !important;position:relative;left:62px;width:70px;',
        cls: 'empty'
    },
    value: ''
};
ShootQ.shared.lookupRelationship = function(uri, callback){
    
    var w = new Ext.Window({
        title: 'Lookup',
        width: 325,
        labelWidth: 100,
        plain: true,
        resizable: false,
        modal: true,
        items: [{
            xtype: 'form',
            style: 'margin: 5px;',
            border: false,
            items: [new Ext.form.ComboBox({
                store: new Ext.data.JsonStore({
                    url: uri,
                    root: 'contacts',
                    id: 'id',
                    fields: [
                        {name:'id', type:'int'}, 
                        'name',
                        'first_name',
                        'last_name',
                        'company_name',
                        'addresses',
                        'phones',
                        'emails', 
                        'birthday',
                        'anniversary',
                        {name:'is_company', type:'auto'}
                    ],
                    baseParams: {
                        'full': true
                    }
                }),
                fieldLabel: 'Search by Name',
                id: 'contact_lookup',
                displayField: 'name',
                valueField: 'id',
                typeAhead: true,
                loadingText: 'Searching...',
                width: 185,
                msgTarget: 'qtip',
                hideTrigger: true
            })]
        }],
        buttons: [{
            text: 'Continue',
            handler: function(){
                var index;
                var field = Ext.getCmp('contact_lookup');
                field.store.each(function(c, i){
                    if(c.get('name') == field.getRawValue())
                        index = i;
                }, this);
                var record = (index == null) ? null : field.store.getAt(index);
                if(!record)
                    return field.markInvalid();
                    
                if(callback && typeof(callback) == 'function')
                    callback(record);
                w.hide();
                w.destroy();
            }
        },{
            text: 'Cancel',
            handler: function() {
                w.hide();
                w.destroy();
            }
        }]
    });
    w.show();
};


/* QuickBooks Warning */
ShootQ.shared.quickbooksWarning = function(callback) {
    var dialog = new Ext.Window({
        modal: true,
        width: 500,
        autoHeight: true,
        shadow: true,
        proxyDrag: true,
        resizable: false,
        title: 'QuickBooks BETA',
        buttons: [{
            text: 'Cancel',
            handler: function(){
                dialog.hide();
                dialog.destroy();
            }
        },{
            text: 'Download',
            handler: function() {
                dialog.hide();
                dialog.destroy();
                callback();
            }
        }]
    });
    
    var contents =''
                 +'<div style="padding: 10px; background: white;">'
                 +' <h1 style="margin: 0 0 0.5em 0; font-size: 1.4em">'
                 +'   QuickBooks&trade; Export &mdash; <i>Beta</i>'
                 +' </h1>'
                 +' <p>'
                 +'   ShootQ is excited to provide QuickBooks&trade; export capabilities'
                 +'   to our users! QuickBooks&trade; is a complex and powerful accounting '
                 +'   system, and we want to make sure that users use this feature '
                 +'   carefully.'
                 +' </p><br/>'
                 +' <p>'
                 +'   Before using this feature, <b>back up your QuickBooks company file</b>, '
                 +'   and be sure to read the following knowledgebase article: '
                 +'   <a href="/genius?redirect=1&task=knowledge&questionID=306" target="window">'
                 +'   How Do I Export Invoices to QuickBooks&trade;</a>.'
                 +' </p><br/>'
                 +' <small style="font-style: italic; margin-top: 1em; display: block;">'
                 +'  ShootQ is not affiliated with QuickBooks&trade; in any '
                 +'  way and QuickBooks&trade; reporting and download features '
                 +'  are provided for your convenience only. Because ShootQ is '
                 +'  unaffiliated with QuickBooks, we are unable to ensure '
                 +'  that our features work with QuickBooks and make no '
                 +'  representation to the contrary. <b><u>These features are '
                 +'  provided “as is” without warranty of any kind, either '
                 +'  expressed or implied, including, but not limited to, the '
                 +'  implied warranties of merchantability or fitness for a '
                 +'  particular purpose. ShootQ shall not be liable for any '
                 +'  damages or costs of any type arising out of or in any way '
                 +'  connected with your use of QuickBooks&trade;, '
                 +'  QuickBooks&trade; is a registered trademark of Intuit '
                 +'  Corporation.</u></b>'
                 +' </small>'
                 +'</div>'
    
    dialog.show();
    dialog.body.dom.innerHTML = contents;
    dialog.center();
    return false;
};


/* Cookie utility functions, adapted from QuirksMode */
ShootQ.shared.cookies.createCookie = function(name, value, days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
};

ShootQ.shared.cookies.readCookie = function(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
};

ShootQ.shared.cookies.eraseCookie = function(name) {
	ShootQ.shared.cookies.createCookie(name,"",-1);
};

/* Role customization */
ShootQ.relationships.roleStore = null;
ShootQ.relationships.initRoleStore = function() {
    ShootQ.relationships.roleStore = new Ext.data.Store({
        proxy: new Ext.data.HttpProxy({
            url: '/account/roles',
            method: 'GET'
        }),
        reader: new Ext.data.JsonReader({
            root: 'results',
            id: 'role',
            totalProperty: 'total'
        }, [
            {name: 'role'},
            {name: 'type', convert: function(v){
                if(v == 'Job')
                    return 'Any';
                return v;
            }},
            {name: 'original', mapping: 'role'},
            {name: 'is_vendor'}
        ]),
        id: 'role'
    });
};

Ext.grid.CheckColumn = function(config){
    Ext.apply(this, config);
    if(!this.id){
        this.id = Ext.id();
    }
    this.renderer = this.renderer.createDelegate(this);
};

Ext.grid.CheckColumn.prototype ={
    init : function(grid){
        this.grid = grid;
        this.grid.on('render', function(){
            var view = this.grid.getView();
            view.mainBody.on('mousedown', this.onMouseDown, this);
        }, this);
    },

    onMouseDown : function(e, t){
        if(t.className && t.className.indexOf('x-grid3-cc-'+this.id) != -1){
            e.stopEvent();
            var index = this.grid.getView().findRowIndex(t);
            var record = this.grid.store.getAt(index);
            record.set(this.dataIndex, !record.data[this.dataIndex]);
        }
    },

    renderer : function(v, p, record){
        p.css += ' x-grid3-check-col-td'; 
        return '<div class="x-grid3-check-col'+(v?'-on':'')+' x-grid3-cc-'+this.id+'">&#160;</div>';
    }
};

ShootQ.relationships.createRoleGrid = function() {
    var Role = Ext.data.Record.create([
        {name: 'role', type: 'string'},
        {name: 'type', type: 'string'},
        {name: 'original', type: 'string'},
        {name: 'is_vendor', type: 'bool'}
    ]);
    
    var checkColumn = new Ext.grid.CheckColumn({
        id: 'is_vendor',
        header: 'Is Vendor?', 
        dataIndex: 'is_vendor',
        sortable: true
    });
    
    var validateRole = function(v) {
        var rows = 0;
        
        /* Don't allow empty strings */
        if(!v.strip().length) return false;
        
        var currentIndex = ShootQ.relationships.roleGrid.getSelectionModel().getSelectedCell()[0];
        ShootQ.relationships.roleStore.each(function(row, i) {
            if (row.data.role == v)
                if (i != currentIndex)
                    rows += 1;
        });
        if (rows == 0) return true;
        return false;
    };
    
    var typesEditor = ShootQ.shared.getShootTypeSelector(null, {
        store: new Ext.data.ArrayStore({
            url: '/account/custom_types/types',
            fields: [{
                name: 'type',
                convert: function(v){
                    if(v == 'Other')
                        return 'Any';
                    return v;
                }
            },{
                name: 'locked', type: 'boolean'
            }],
            autoLoad: true
        }),
        lazyRender: true,
        listClass: 'x-combo-list-small'
    });
    
    ShootQ.relationships.roleGrid = new Ext.grid.EditorGridPanel({
        store: ShootQ.relationships.roleStore,
        border: false,
        width: 585,
        height: 280,
        clicksToEdit: 1,
        plugins: checkColumn,
        columns: [
            {
                id: 'role', 
                header: 'Role', 
                width: 365, 
                dataIndex: 'role', 
                sortable: true,
                invalidText: 'This role already exists.',
                editor: new Ext.form.TextField({
                    validator: validateRole,
                    allowBlank: false
                })
            },
            {
                id: 'type',
                header: 'Shoot Type', 
                dataIndex: 'type', 
                sortable: true,
                editor: typesEditor                
            },
            checkColumn
        ],
        loadMask: true,
        bbar: [{
            text: 'Add Role',
            icon: '/images/add.gif',
            cls: "x-btn-text-icon",
            handler : function() {
                ShootQ.relationships.roleGrid.stopEditing();
                ShootQ.relationships.roleStore.insert(0, new Role({
                    role: 'New Role',
                    type: 'Any',
                    original: '',
                    is_vendor: false
                }));
                ShootQ.relationships.roleGrid.startEditing(0, 0);
            }
        },{
            text: 'Remove Role',
            icon: '/images/delete.gif',
            cls: "x-btn-text-icon",
            disabled: true,
            handler : function() {
                if (ShootQ.relationships.roleGrid.getSelectionModel().getSelectedCell()) {
                    ShootQ.relationships.roleGrid.stopEditing();
                    var rowIndex = ShootQ.relationships.roleGrid.getSelectionModel().getSelectedCell()[0];
                    var row = ShootQ.relationships.roleStore.getAt(rowIndex);
                    ShootQ.relationships.roleStore.remove(row);
                }
            }
        }]
    });
    
    ShootQ.relationships.roleGrid.getSelectionModel().on('selectionchange', function(grid, selection) {
        ShootQ.relationships.roleGrid.getBottomToolbar().items.get(1).setDisabled(selection == null);
    });
};

ShootQ.relationships.customizeRoles = function(cb) {
    if (ShootQ.relationships.roleStore == null) ShootQ.relationships.initRoleStore();
    ShootQ.relationships.createRoleGrid();
    var dialog = new Ext.Window({
        modal: true,
        width: 600,
        height: 350,
        plain: true,
        resizable: false,
        title: 'Customize Relationship Roles',
        items: [ShootQ.relationships.roleGrid],
        buttons: [{
            text: 'Save',
            handler: function() {
                this.disable();
                var data = {'Wedding': [], 'Portrait': [], 'Job': []};
                ShootQ.relationships.roleStore.each(function(row) {
                    if(row.data.type == 'Any') row.data.type = 'Job';
                    if(!data[row.data.type]) data[row.data.type] = [];
                    data[row.data.type].push([
                        row.data.role,
                        row.data.is_vendor,
                        row.data.original
                    ]);
                });
                var saving = Ext.Msg.wait('Saving Roles', 'Your roles are being saved...');
                Ext.Ajax.request({
                    url: '/account/roles',
                    method: 'POST',
                    jsonData: data,
                    success: function() {
                        if (!cb) window.location.reload();
                        else {
                            saving.hide();
                            dialog.hide();
                            cb();
                        }
                    },
                    failure: function() {
                        saving.hide();
                    }
                });
            }
        },{
            text: 'Cancel',
            handler: function() {
                dialog.hide();
                dialog.destroy();
            }
        }]
    });
    dialog.show();
    ShootQ.relationships.roleStore.reload();
};

/* Global Search */
ShootQ.search.window = null;
ShootQ.search.resultQueue = [];
ShootQ.search.show = function() {
    if (!ShootQ.search.window) {
        /* store references to the window, loading indicator, input, etc. */
        ShootQ.search.window = Ext.get('search-window');
        ShootQ.search.loading = Ext.get('search-box').child('img');
        ShootQ.search.input = Ext.get('search-box').child('input');
        ShootQ.search.results = Ext.get('search-results');
        ShootQ.search.results = Ext.get('search-results').hide();
        
        /* define the search function */
        var do_filter = function(force) {
            var value = ShootQ.search.input.getValue();
            if ((value.length > 2 || value.length == 0) || force == true) {
                ShootQ.search.performSearch(value);
            }
        };
        
        /* attach the search event */
        ShootQ.search.task = new Ext.util.DelayedTask(do_filter.createDelegate(this, []));
        ShootQ.search.input.on('keyup', function(e) {
            ShootQ.search.task.delay(333);
        });

        ShootQ.search.input.on('keypress', function(e) {
            if (e.getKey() == e.ENTER) { do_filter.createDelegate(this, [filter, true])(); }
        });

        ShootQ.search.input.on('focus', function() { this.dom.select(); });
        
        /* anchor the search window in place */
        ShootQ.search.window.anchorTo('topnav-container', 'br', [-350, 30]);
    }
    
    if (ShootQ.search.window.isVisible()) {
        ShootQ.search.window.enableDisplayMode().slideOut('t', {duration: .2});
    } else {
        ShootQ.search.loading.hide();
        ShootQ.search.window.enableDisplayMode().slideIn('t', {
            callback: function(){
                ShootQ.search.input.focus();
            },
            duration: .2
        });
    }
};

ShootQ.search.performSearch = function(value) {
    if (value.trim().length <= 1) return;
    
    /* show the loading indicator and reset the search results */
    ShootQ.search.loading.fadeIn();
    Ext.TaskMgr.stopAll();
    ShootQ.search.resultQueue = [];
    ShootQ.search.results.dom.innerHTML = '';
    
    /* queue up search tasks */
    Ext.each(ShootQ.search.actions, function(action) {
        Ext.TaskMgr.start({
            run: action,
            args: [value],
            interval: 0,
            repeat: 0
        });
    });
};

ShootQ.search.actions = [
    function invoices(value) {
        Ext.Ajax.request({
            url: '/business/billing/invoices',
            params: {
                limit: 20,
                filter: value
            },
            failure: function(response) {
                debugger;
            },
            success: function(response) {
                var results = Ext.decode(response.responseText).results;
                if (results.length > 0) {
                    ShootQ.search.results.show();
                    var container = ShootQ.search.results.createChild({
                        tag: 'div',
                        html: '<label>Invoices</label>'
                    });
                    var list = container.createChild({
                        tag: 'ul'
                    });
                    
                    Ext.each(results, function(result) {
                        list.createChild({
                            tag: 'li',
                            html: '<img src="/images/payment_schedule.png" style="margin: -2px 5px 0 0;" align="center" /><a href="/shoots/'+result.uuid+'#billinglegal">'+result.name+'</a>: '+Ext.util.Format.usMoney(result.total)+'<br/><small style="margin-left: 22px">'+result.shoot_name+'</small>'
                        });
                    });
                }
                ShootQ.search.resultQueue.push(results.length);
                ShootQ.search.checkState();
            }
        });

    },
    function events(value) {
        Ext.Ajax.request({
            url: '/shoots/events',
            params: {
                filter: value
            },
            success: function(response) {
                var results = Ext.decode(response.responseText).results;
                if (results.length > 0) {
                    ShootQ.search.results.show();
                    var container = ShootQ.search.results.createChild({
                        tag: 'div',
                        html: '<label>Events</label>'
                    });
                    var list = container.createChild({
                        tag: 'ul'
                    });
                                
                    Ext.each(results, function(result) {
                        list.createChild({
                            tag: 'li',
                            html: '<img src="/images/date.png" style="margin: -2px 5px 0 0;" align="center" /><a href="/shoots/'+result.shoot_uuid+'">'+result.name+'</a><br/><small style="margin-left: 22px">'+result.shoot_name+'</small>'
                        });
                    });
                }
                ShootQ.search.resultQueue.push(results.length);
                ShootQ.search.checkState();
            }
        });
    },
    function proposals(value) {
        Ext.Ajax.request({
            url: '/shoots/shoots',
            params: {
                limit: 20,
                sort: 'name',
                filter: value,
                type: 'bookings',
                classifier: 'proposals'
            },
            success: function(response) {
                var results = Ext.decode(response.responseText).results;
                if (results.length > 0) {
                    ShootQ.search.results.show();
                    var container = ShootQ.search.results.createChild({
                        tag: 'div',
                        html: '<label>Open Proposals</label>'
                    });
                    var list = container.createChild({
                        tag: 'ul'
                    });
                                
                    Ext.each(results, function(result) {
                        list.createChild({
                            tag: 'li',
                            html: '<img src="/images/bookit.png" style="margin-right: 5px;" align="center" /><a href="/shoots/'+result.uuid+'">'+result.name+'</a>'
                        });
                    });
                }
                ShootQ.search.resultQueue.push(results.length);
                ShootQ.search.checkState();
            }
        });
    },
    function shoots(value) {
        /* TODO: dead shoots */        
        Ext.Ajax.request({
            url: '/shoots/shoots',
            params: {
                limit: 20,
                sort: 'name',
                filter: value
            },
            success: function(response) {
                var results = Ext.decode(response.responseText).results;
                if (results.length > 0) {
                    ShootQ.search.results.show();
                    var container = ShootQ.search.results.createChild({
                        tag: 'div',
                        html: '<label>Shoots</label>'
                    });
                    var list = container.createChild({
                        tag: 'ul'
                    });
                                
                    Ext.each(results, function(result) {
                        list.createChild({
                            tag: 'li',
                            html: '<img src="/images/camera.png" style="margin-right: 5px;" align="center" /><a href="/shoots/'+result.uuid+'">'+result.name+'</a>'
                        });
                    });
                }
                ShootQ.search.resultQueue.push(results.length);
                ShootQ.search.checkState();
            }
        });
    },
    function relationships(value) {
        /* TODO: dead relationships */
        Ext.Ajax.request({
            url: '/relationships/relationships',
            params: {
                filter: value
            },
            success: function(response) {
                var results = Ext.decode(response.responseText).results;
                if (results.length > 0) {
                    ShootQ.search.results.show();
                    var container = ShootQ.search.results.createChild({
                        tag: 'div',
                        html: '<label>Relationships</label>'
                    });
                    var list = container.createChild({
                        tag: 'ul'
                    });
                    
                    Ext.each(results, function(result) {
                        var html = '<img src="/images/person.png" style="margin-right: 5px;" align="center" /><a href="/relationships#'+result.id+'">'+result.name+'</a>';
                        if(ShootQ.relationships.loadRelationship)
                            html = '<img src="/images/person.png" style="margin-right: 5px;" align="center" /><a href="#" onclick="ShootQ.relationships.loadRelationship('+result.id+');return false;">'+result.name+'</a>';
                            
                        list.createChild({
                            tag: 'li',
                            html: html
                        });
                    });
                }
                ShootQ.search.resultQueue.push(results.length);
                ShootQ.search.checkState();
            }
        });
    }
];

ShootQ.search.checkState = function() {
    if (ShootQ.search.resultQueue.length == ShootQ.search.actions.length) {
        ShootQ.search.loading.fadeOut();
        if (Ext.max(ShootQ.search.resultQueue) == 0) {
            ShootQ.search.results.show();
            var container = ShootQ.search.results.createChild({
                tag: 'div',
                html: '<label></label>'
            });
            var list = container.createChild({
                tag: 'ul'
            });
            list.createChild({
                tag: 'li',
                html: 'No results were found.'
            });
        }
    }
};

/* Lead Workflow shared functions */
ShootQ.shared.transitionPopup;
ShootQ.shared.transitionLead = function(uuid, milestone, cb) {
    if (ShootQ.shared.transitionPopup) ShootQ.shared.transitionPopup.destroy();

    var url = '/shoots/'+uuid+'/workflow/transition'+(milestone.id ? '/'+milestone.id : '');
    
    Ext.Ajax.request({
        url: url,
        success: function(response) {
            var c = Ext.getBody().createChild({
                tag: 'div',
                style: 'overflow: hidden; padding: 5px 0',
                html: response.responseText
            });

            var spinner = new Ext.ux.form.SpinnerField({
                id: 'milestone-duration-cmp',
                name: 'duration',
                width: 40,
                minValue: 1,
                value: milestone.duration,
                msgTarget: 'qtip'
            });
            spinner.render('milestone-duration');
            
            ShootQ.shared.toggleLeadMilestoneDuration();
            Ext.get('milestone-remind').on('change', ShootQ.shared.toggleLeadMilestoneDuration);

            /* Render a color field if necessary */
            if(Ext.get('milestone-color')){
                ShootQ.shared.milestone_color = new Ext.ux.ColorField({
                    name: 'color',
                    value: milestone.color,
                    msgTarget: 'qtip',
                    allowBlank: false
                });
                ShootQ.shared.milestone_color.render('milestone-color');
            }

            var btn = new Ext.Button({renderTo: 'ok-button', text: 'Continue'});
            btn.on('click', function() {
                /* Lookup the name for new states */
                var name = Ext.get('milestone-name');
                if(name && !name.getValue()) return;                
                
                this.disable();
                this.setText('Saving...');

                var remind = Ext.get('milestone-remind').dom.checked ? 1 : 0;

                var ignored_actions = [];
                Ext.each(Ext.query('input.perform-action', ShootQ.shared.transitionPopup.getEl().dom), function(elem) {
                    if (!elem.checked) ignored_actions.push(parseInt(elem.id.split('-')[1]));
                });
                var duration = spinner.getValue();
                var color = ShootQ.shared.milestone_color ? ShootQ.shared.milestone_color.getValue() : null;

                Ext.Ajax.request({
                    url: url,
                    method: 'POST',
                    params: {
                        name: name ? Ext.util.Format.htmlEncode(name.getValue()) : null,
                        duration: duration,
                        remind: remind,
                        color: color,
                        note: Ext.util.Format.htmlEncode(Ext.get('milestone-notes').dom.value),
                        ignored_actions: Ext.encode(ignored_actions)
                    },
                    success: function() {
                        if(cb){
                            ShootQ.shared.transitionPopup.hide();
                            ShootQ.shared.transitionPopup.destroy();
                            cb(uuid);
                        }else
                            window.location.reload();
                    }
                });
            });
            
            ShootQ.shared.transitionPopup = new Ext.ToolTip({
                target: 'transition-dropdown-'+uuid,
                anchor: 'top',
                autoHide: false,
                contentEl: c,
                width: 225,
                listeners: {
                    'beforehide': function(){
                        if(ShootQ.shared.milestone_color && ShootQ.shared.milestone_color.menu)
                            if(ShootQ.shared.milestone_color.menu.isVisible()) return false;
                    },
                    'hide': function(){
                        this.destroy();
                    }
                }
            });

            ShootQ.shared.transitionPopup.show();            
            
        }
    });
    
};

ShootQ.shared.toggleLeadMilestoneDuration = function(chk){
    var chk = Ext.get('milestone-remind').dom;
    var parent = chk.parentNode.parentNode;
    var columns = Ext.query('td.text', parent);
    var spinner = Ext.getCmp('milestone-duration-cmp');
    if(chk.checked){
        spinner.setDisabled(false);
        Ext.each(columns, function(c){
            Ext.get(c).setStyle('color', '#000 !important;');
        });
    }else{
        spinner.setDisabled(true);
        Ext.each(columns, function(c){
            Ext.get(c).setStyle('color', '#888 !important;');
        });
    }
};

ShootQ.shared.transitionMenu;
ShootQ.shared.showTransitionMenu = function(uuid, currentMilestone, cb) {
    if (ShootQ.shared.transitionPopup) ShootQ.shared.transitionPopup.destroy();
    if (ShootQ.shared.transitionMenu) {
        ShootQ.shared.transitionMenu.destroy();
        ShootQ.shared.transitionMenu = null;
    }
    
    var _load_menu = new Ext.menu.Menu({
        items: [{
            text: '<div style="width:'+Ext.get('transition-dropdown-'+uuid).getWidth()+';min-height:16px;text-align:center;"><img src="/images/loading.gif" width="18" /></div>',
            disabled: true,
            showSeparator: false
        }],
        enableScrolling: false,
        width: Math.max(175, Ext.get('transition-dropdown-'+uuid).getWidth())
    });
    _load_menu.show('transition-dropdown-'+uuid, 'tl-bl?');
    
    Ext.Ajax.request({
        url: '/controlpanels/lead_workflow/milestones',
        success: function(response) {
            var milestones = Ext.decode(response.responseText).milestones;
            
            var options = [];
            Ext.each(milestones, function(m) {
                options.push({
                    text: m.name,
                    disabled: currentMilestone == m.id,
                    iconCls: 'large-rounded" style="background:'+m.color+';"',
                    handler: function(e) {
                        ShootQ.shared.transitionMenu.hide();
                        ShootQ.shared.transitionLead(uuid, m, cb);
                        return false;
                    }
                });
            });
            options.push({
                text: 'Enter Your Own...',
                icon: '/images/new.png',
                handler: function(e) {
                    ShootQ.shared.transitionMenu.hide();                    
                    ShootQ.shared.transitionLead(uuid, {
                        duration: 7,
                        color: '#339922'
                    }, cb);
                    return false;
                }
            });
            
            var noteWidth = Math.max(175, Ext.get('transition-dropdown-'+uuid).getWidth()) - 35;
            Ext.Ajax.request({
               url: '/shoots/'+uuid+'/lead_milestone',
               success: function(response){
                   _load_menu.hide();            
                   _load_menu.destroy();
                   
                   response = Ext.decode(response.responseText);
                   if(!ShootQ.shared.transitionMenu){
                       if(currentMilestone)
                           ShootQ.shared.transitionMenu = new Ext.menu.Menu({items: [{
                                   text: 'Delay...',
                                   icon: '/images/time.png',
                                   handler: function(){
                                       ShootQ.shared.transitionMenu.hide();
                                       Ext.each(milestones, function(m) {
                                           if(currentMilestone == m.id)
                                               ShootQ.shared.transitionLead(uuid, m, cb);
                                       });
                                       return false;
                                   }
                               },{
                                   icon: '/images/refresh.png',
                                   text: 'Change...',
                                   menu: {
                                       xtype: 'menu',
                                       items: options,
                                       enableScrolling: false
                                   }
                               }, response.due_date || response.note ? '-' : '', response.due_date ? {
                                   icon: '/images/date.png',
                                   text: 'By '+response.due_date,
                                   canActivate: false                               
                               } : {hidden: true}, response.note ? {
                                   icon: '/images/note.png',
                                   text: (function(){
                                       return '<div style="width:'+(noteWidth)+'px;max-width:'+(noteWidth)+'px;white-space:pre-wrap;">'+response.note+'</div>'
                                   })(),
                                   canActivate: false
                               } : {hidden: true}],
                               width: Math.max(175, Ext.get('transition-dropdown-'+uuid).getWidth()),
                               enableScrolling: false
                           });
                       else
                           ShootQ.shared.transitionMenu = new Ext.menu.Menu({
                               items: options,
                               enableScrolling: false
                           });
                   }
                   ShootQ.shared.transitionMenu.show('transition-dropdown-'+uuid, 'tl-bl?');
               }
            });
        }
    });
};

/* add tooltip capability to all form fields */
Ext.override(Ext.form.Field, { 
    afterRender : Ext.form.Field.prototype.afterRender.createSequence(function() {
        var qt = this.qtip;
        var qtitle = this.qtitle || '';
        var qwidth = this.qwidth || null;
        if (qt) { 
            Ext.QuickTips.register({
                target: this,
                title: qtitle,
                text: qt,
                width: qwidth,
                enabled: true,
                showDelay: 20
            });
        }
    })
});

/* On ready handler */
Ext.onReady(function() {
    Ext.QuickTips.init();
    ShootQ.shared.initToolTips();
    
    /* register global keyboard shortcut for searching */
    var hash = {
        key: Ext.EventObject.F,
        fn: function(key, e) {
            if (!ShootQ.search.window || !ShootQ.search.window.isVisible()) {
                ShootQ.search.show();
                e.preventDefault();
                return false;
            }
        }
    };
    var modifier = Ext.isWindows || (!Ext.isWindows && Ext.isWebKit) ? 'ctrl' : 'meta';
    hash[modifier] = true;
    
    var map = new Ext.KeyMap(Ext.isWindows ? Ext.getDoc() : Ext.getBody(), hash);
    
    var map = new Ext.KeyMap(Ext.isWindows ? Ext.getDoc() : Ext.getBody(), {
        key: Ext.EventObject.ESC,
        fn: function(e) {
            if (ShootQ.search.window && ShootQ.search.window.isVisible()) 
                ShootQ.search.show();
        }
    });
});

/* 
 * Firefox has this nasty habit of autocompleting form fields, including
 * the state of buttons.
 * 
 * This is annoying, and we almost never want it,
 * so let's turn it off.
 */
Ext.onReady(function(){
    Ext.each(Ext.query('input, button, textarea'), function(n){
        if(!Ext.get(n).hasClass('autocomplete'))
            n.setAttribute('autocomplete', 'off');
    });
});

Ext.form.DateField.prototype.format = 'M j, Y';

Ext.ux.LabelField = Ext.extend(Ext.form.TextField,  {
    defaultAutoCreate : {tag: "p"},
    hideLabel: true,
    
    validate: function() {
        return true;
    },
    
    onRender : function(ct, position){
        cfg = this.getAutoCreate();
        cfg.html = this.html;
        this.autoCreate = cfg;
        Ext.ux.LabelField.superclass.onRender.call(this, ct, position);
    }
});
Ext.reg('labelfield', Ext.ux.LabelField);

/*
 * An Ext-compatible embedded CKEditor
 */ 
Ext.form.CKEditor = function(config){ 
    this.config = config; 
    Ext.form.CKEditor.superclass.constructor.call(this, config); 

    CKEDITOR.on('dialogDefinition', function(ev){
    	var dialogName = ev.data.name;
    	var dialogDefinition = ev.data.definition;

    	if(dialogName == 'link'){
    		dialogDefinition.removeContents('advanced');
    		dialogDefinition.removeContents('target');
    	}

    	if(dialogName == 'image'){
    		dialogDefinition.removeContents('advanced');
    		dialogDefinition.removeContents('Link');
    	}
    });    

}; 

Ext.extend(Ext.form.CKEditor, Ext.form.TextArea,  { 

		buttons : [
			'Bold', 
			'Italic', 
			'Underline', 
			'-',
			'TextColor',
			'BGColor',
			'-',
			'JustifyLeft',
			'JustifyCenter',
			'JustifyRight',
			'-',
			'Link', 
			'Unlink',
			'Image',
			'-', 
			'NumberedList', 
			'BulletedList'
		],

    onRender: function(ct, position){ 
        if(!this.el){ 
            this.defaultAutoCreate = { 
                tag: "textarea", 
                autocomplete: "off" 
            }; 
        } 
        Ext.form.TextArea.superclass.onRender.call(this, ct, position); 
        CKEDITOR.replace(this.id, {
					toolbar: [this.buttons],
					pasteFromWordPromptCleanup: true,
				  pasteFromWordNumberedHeadingToList: true,
				  pasteFromWordRemoveFontStyles: true,
					resize_enabled: false,
					toolbarCanCollapse: false,
					scayt_autoStartup: false,
					removePlugins: 'div',
					enterMode: CKEDITOR.ENTER_BR
				}); 
    }, 

    setValue: function(value){ 
        Ext.form.TextArea.superclass.setValue.apply(this,[value]); 
        CKEDITOR.instances[this.id].setData( value ); 
    }, 

    getValue: function(){ 
        CKEDITOR.instances[this.id].updateElement(); 
        return Ext.form.TextArea.superclass.getValue(this); 
    }, 

    getRawValue: function(){ 
        CKEDITOR.instances[this.id].updateElement();     
        return Ext.form.TextArea.superclass.getRawValue(this); 
    } 
}); 
Ext.reg('ckeditor', Ext.form.CKEditor);
    
/* Automatically strip MS Word content from HTMLEditors */
Ext.ux.StripMSWord = function() {
    
    this.init = function(htmlEditor) {
        this.editor = htmlEditor;
        this.editor.on('push', pushValue, this);
        this.editor.on('beforesync', cleanHTML, this);
    };
    
    function pushValue(editor, html){
        this.editor.getEditorBody().innerHTML = cleanSync(html);
    };
    
    function cleanHTML(editor, html) {
        this.editor.el.dom.value = cleanSync(html);
        this.editor.fireEvent('sync', this.editor, html);
        return false;
    };
    
    function cleanSync(h){
        Ext.each(patterns, function(v) {
                // Remove or replace
                if (v.constructor == RegExp)
                        h = h.replace(v, '');
                else
                        h = h.replace(v[0], v[1]);
        });
        return h;
    };
    
    function cleanMso(a, b){
        return (b = b.replace(/\bMso[\w\:\-]+\b/g, '')) ? ' class="' + b + '"' : '';
    };
    
    function cleanSelector(s){
        return new RegExp(s+":[^\">]+;", "gi");
    };
    
    var patterns = [/^\s*( )+/g,
        /( |<br[^>]*>)+\s*$/g,
        /<!--\[(end|if)([\s\S]*?)-->|<style>[\s\S]*?<\/style>/gi,
        /<\/?(font|meta|link)[^>]*>/gi,
        /<\\?\?xml[^>]*>/gi,
        /<\/?o:[^>]*>/gi,
        [/ class=\"([^\"]+)\"/gi, cleanMso],
        [/ class=([\w\:\-]+)/gi, cleanMso],
        cleanSelector('mso[^:]*'),
        cleanSelector('(font-family|text-indent|height)'),
        /\.0pt;/gi,
        /\sstyle=\"\"/gi,
        [/<br[^>]*>/gi, '<br />'],
        [/<hr[^>]*>/gi, '<hr />']
    ];    
    
}
Ext.form.HtmlEditor.prototype.plugins = [new Ext.ux.StripMSWord()];