var clientVersion = '1.664';
var clientAgent = 'PUBLIC';
var clientBuild = "$Revision: 1213 $";

clientBuild = clientBuild.substring(11, clientBuild.length - 2);

// This function returns the name of a given function. It does this by
// converting the function to a string, then using a regular expression
// to extract the function name from the resulting code.
function funcname(f) {
    var s = f.toString().match(/function (\w*)/)[1];
    if ((s == null) || (s.length == 0)) return "anonymous";
    return s;
}

// This function returns a string that contains a "stack trace."
function stacktrace() {
    var s = "";  // This is the string we'll return.
    // Loop through the stack of functions, using the caller property of
    // one arguments object to refer to the next arguments object on the
    // stack.
    for(var a = arguments.caller; a != null; a = a.caller) {
        // Add the name of the current function to the return value.
        s += funcname(a.callee) + "\n";

        // Because of a bug in Navigator 4.0, we need this line to break.
        // a.caller will equal a rather than null when we reach the end
        // of the stack. The following line works around this.
        if (a.caller == a) break;
    }
    return s;
}

/**
 *  Extends the YAHOO.ext.state.CookieProvider to check
 *  the cookies for changes at a specified interval of time.
 *  Useful for maintaining sync'd state information across distributed
 *  locations (within the same browser, but different loaded pages)
 */
var PollingCookieProvider = function(config) {

	this.previousCookie = document.cookie.toString();

	PollingCookieProvider.superclass.constructor.call(this, config);

	var interval = 1000; //default polling interval

	if (config && config.interval)
	{
		interval = +config.interval;

		if (!(interval > 0))
		{
			interval = 1000;
		}
	}

	setInterval(this.poll.createDelegate(this), interval);
}

YAHOO.extendX(PollingCookieProvider, YAHOO.ext.state.CookieProvider, {
	/**
	 * had to override this function to fix a bug
	 */
    encodeValue: function(v){
        var enc;
        if(typeof v == 'number'){
            enc = 'n:' + v;
        }else if(typeof v == 'boolean'){
            enc = 'b:' + (v ? '1' : '0');
        }else if(v instanceof Date){
            enc = 'd:' + v.toGMTString();
        }else if(v instanceof Array){
            var flat = '';
            for(var i = 0, len = v.length; i < len; i++){
                flat += this.encodeValue(v[i]);
                if(i != len-1) flat += '^';
            }
            enc = 'a:' + flat;
        }else if(typeof v == 'object'){
            var flat = '';
            for(var key in v){
                if(typeof v[key] != 'function' && typeof v[key] != 'undefined'){
                    flat += key + '=' + this.encodeValue(v[key]) + '^';
                }
            }

			  if (flat.length > 0)
			  {
				  flat = flat.substring(0, flat.length - 1);
			  }

            enc = 'o:' + flat;
        }else{
            enc = 's:' + v;
        }

        return escape(enc);
    },

	/**
	 *  Stores the new cookie value after calling the superclass set method
	 *
	 *  @param string name
	 *  @param string value
	 */
	set: function(name, value) {
		PollingCookieProvider.superclass.set.call(this, name, value);

		this.previousCookie = document.cookie.toString();
	},

	/**
	 *  Checks whether the current cookie is different than the cached
	 *  "previous" value.  If it has changed then fire the statechange
	 *  event for all registered listeners per property.
	 */
	poll: function() {
		var newCookie = document.cookie.toString();

		if (this.previousCookie != newCookie)
		{
			this.previousCookie = newCookie;

			this.state = this.readCookies();

			for (var property in this.state)
			{
				this.fireEvent('statechange', this, property, this.state[property]);
			}
		}
	}
});

var PollingServletProvider = function(config) {
	this.reportFailure = true;
	this.failureCount = 0;
	this.failureCountLimit = 1;
	this.timestamp = 0;

	PollingServletProvider.superclass.constructor.call(this, config);

	//setup our custom serverfailure event
	this.events.serverfailure = new YAHOO.util.CustomEvent('serverfailure');

	var interval = 1000; //default polling interval

	if (config)
	{
		if (config.interval)
		{
			interval = +config.interval;

			if (!(interval > 0))
			{
				interval = 1000;
			}
		}

		if (config.url)
		{
			this.url = config.url;
		}

		if (config.failureCountLimit)
		{
			this.failureCountLimit = +config.failureCountLimit;
		}
	}

	this._pollDelegate = this._poll.createDelegate(this);
	this._noServerDelegate = this._noServer.createDelegate(this);

	this.pollingCookieProvider = new PollingCookieProvider({ interval: interval });
	this.pollingCookieProvider.on('statechange', this.poll.createDelegate(this));

	//run an initial poll
	this.poll();
};

YAHOO.extendX(PollingServletProvider, YAHOO.ext.state.Provider, {
	/**
	 * had to override this function to fix a bug
	 */
    encodeValue: function(v){
        var enc;
        if(typeof v == 'number'){
            enc = 'n:' + v;
        }else if(typeof v == 'boolean'){
            enc = 'b:' + (v ? '1' : '0');
        }else if(v instanceof Date){
            enc = 'd:' + v.toGMTString();
        }else if(v instanceof Array){
            var flat = '';
            for(var i = 0, len = v.length; i < len; i++){
                flat += this.encodeValue(v[i]);
                if(i != len-1) flat += '^';
            }
            enc = 'a:' + flat;
        }else if(typeof v == 'object'){
            var flat = '';
            for(var key in v){
                if(typeof v[key] != 'function' && typeof v[key] != 'undefined'){
                    flat += key + '=' + this.encodeValue(v[key]) + '^';
                }
            }

			  if (flat.length > 0)
			  {
				  flat = flat.substring(0, flat.length - 1);
			  }

            enc = 'o:' + flat;
        }else{
			v = v.replace(/[(\r*\n*)]/g, '##nl');
			v = v.replace(/##nl##nl/g, '##nl');
            enc = 's:' + v;
        }

        return escape(enc);
    },

	decodeValue: function(cookie) {
		var re=/^(a|n|d|b|s|o)\:(.*)$/;var matches=re.exec(unescape(cookie));
		if(!matches||!matches[1])
			return;

		var type=matches[1];
		var v=matches[2];
		switch(type) {
			case'n':
				return parseFloat(v);
			case'd':
				return new Date(Date.parse(v));
			case'b':
				return(v=='1');
			case'a':
				var all=[];
				var values=v.split('^');
				for(var i=0,len=values.length;i<len;i++) {
					all.push(this.decodeValue(values[i]))
				}
				return all;
			case'o':
				var all={};
				var values = v.split('^');
				for(var i=0,len=values.length;i<len;i++) {
					var kv = values[i].split('=');
					all[kv[0]] = this.decodeValue(kv[1]);
				}
				return all;
			default:
				return v.replace(/##nl/g, '\r\n');
		}
	},


	get: function(name, defaultValue) {
		return typeof this.state[name] == 'undefined' ? defaultValue : this.decodeValue(this.state[name]);
	},

	/**
	 *  Stores the new cookie value after calling the superclass set method
	 *
	 *  @param string name
	 *  @param string value
	 */
	set: function(name, value) {
		value = this.encodeValue(value);

		if (typeof this.state[name] == 'undefined' || this.state[name] != value)
		{
			var params = 'timestamp=' + this.timestamp + '&name=' + encodeURIComponent(name) + '&value=' + encodeURIComponent(value);

			YAHOO.util.Connect.asyncRequest('POST', this.url, { success: this._pollDelegate, failure: this._noServerDelegate }, params);
		}
	},

	/**
	 *  Checks whether the current cookie is different than the cached
	 *  "previous" value.  If it has changed then fire the statechange
	 *  event for all registered listeners per property.
	 */
	poll: function(cookieProvider, name) {
		if (typeof cookieProvider == 'undefined' || (name == 'timestamp' && cookieProvider.state['timestamp'] > 0 && this.timestamp < cookieProvider.state['timestamp']))
		{
			var params = 'timestamp=' + this.timestamp;

			YAHOO.util.Connect.asyncRequest('GET', this.url + '?' + params, { success: this._pollDelegate, failure: this._noServerDelegate });
		}
	},

	_poll: function(response) {
		this.failureCount = 0;

		var json = response.responseText;

		try {
			var state = eval('('+json+')');

			var timestamp = 0;
			var statechange = false;

			for (var name in state)
			{
				if (name != 'timestamp')
				{
					statechange = true;

					var value = this.decodeValue(state[name]);
					this.state[name] = state[name];

					try
					{
						this.fireEvent('statechange', this, name, value);
					}
					catch (e) {}
				}
				else if (state[name])
				{
					timestamp = state[name];
				}
			}

			if (timestamp)
			{
				this.timestamp = timestamp;
			}

			if (statechange)
			{
				this.pollingCookieProvider.set('timestamp', this.timestamp);
			}
		}
		catch(e)
		{
			if (window.confirm('An error has occurred that requires this page be refreshed'))
			{
				window.location.reload();
			}
			else
			{
				alert(e);
			}
		}
	},

	_noServer: function(response) {
		this.failureCount++;

		if (this.failureCount >= this.failureCountLimit)
		{
			this.failureCount = 0;

			if (this.reportFailure)
			{
				top.PartExplorer.serverFailure(this);
			}
		}
	},

	setReportFailure: function(reportFailure) {
		this.reportFailure = reportFailure;
	}
});

/**
 * Templated view for the part detail pane
 */
var PartView = function(element, include_add_to_cart, include_pricing) {

	var add_to_cart_form_start = '', add_to_cart_input = '', add_to_cart_form_end = '', pricing_spans = '', dnet_pricing_button = '';

	if (include_add_to_cart)
	{
		add_to_cart_form_start = '<form action="javascript: void(0)">';
		add_to_cart_input = 	' x <input type="text" size="2" maxlength="6" name="qty" value="{standard_qty}" onfocus="this.select()"/><input type="text" maxlength="36" name="comment" value="Comment..." onfocus="this.select()"/><input class="button" type="button" onclick="PartExplorer.addPart({parts_app_node_id}, this.form.qty.value, this.form.comment.value); this.form.comment.value = \\\'Comment...\\\'; return Button.disableForPeriod(this, 1000, \\\'Adding...\\\')" value="Add to Order" onmouseover="Button.hoverButton(this)" onmouseout="Button.unhoverButton(this)" onmousedown="Button.downButton(this)" onmouseup="Button.upButton(this)"/>';
		add_to_cart_form_end = '</form>';
	}

	if (include_pricing)
	{
		pricing_spans = '<span class="price">${list_price}</span><span class="dnet_price"> (${dnet_price})</span>';
		dnet_pricing_button = '<input class="button" type="button" onclick="PartExplorer.showDNET(this.parentNode)" value="Show DNET" onmouseover="Button.hoverButton(this)" onmouseout="Button.unhoverButton(this)" onmousedown="Button.downButton(this)" onmouseup="Button.upButton(this)"/>';
	}

	var optionalColumn = add_to_cart_form_start + pricing_spans + add_to_cart_input + dnet_pricing_button + add_to_cart_form_end;

    var template = new YAHOO.ext.Template(
    	'<table cell-spacing="0" cell-padding="0" class="part-detail-heading-container">' +
    		'<tr>' +
				'<td ' + (optionalColumn.length > 0 ? 'width="220px"' : '') + '><h1>{product_name}</h1></td>' +
    			(optionalColumn.length > 0 ? '<td>' + optionalColumn + '</td>' : '') +
			'</tr>' +
    	'</table>' +
    	'<table cell-spacing="0" cell-padding="0" class="part-detail-container">' +
    		'<tr>{image_section}' +
    			'<td>' +
			    	'<table cell-spacing="0" cell-padding="0">' +
			    		'<tr class="ytoolbar">' +
			    			'<th width="25%">Part Detail</th>' +
			    			'<th>Description</th>' +
			    		'</tr>' +
			    		'<tr><td>UPC: {upc}</td><td rowspan="4">{parsed_description}</td></tr>' +
			    		'<tr><td>SI Number: {si_number}</td></tr>' +
			   			'<tr><td>Standard Pack: {standard_qty}</td></tr>' +
			   			'<tr><td>Weight: {gross_weight}</td></tr>' +
			   		'</table>' +
					'{properties_table}' +
					'{alternate_parts}' +
			    '</td>' +
			'</tr>' +
	    '</table>'
    );

    PartView.superclass.constructor.call(this, element, template, {fitToFrame: true});
};

YAHOO.extendX(PartView, YAHOO.ext.JsonView, {
	/**
	 * Preprocessor hook for the data before its given to the
	 * templating code of the JsonView class
	 */
	prepareData : function(data, index) {
		if (data.image)
		{
			data.image_section = '<td width="220px" align="center">' + '<img src="' + PartExplorer.makeJSDataURLPrefix(data.image) + '.jpg' + '"/></td>';
		}

		if (data.description)
		{
			data.parsed_description = data.description.replace(/\r\n|\r|\n/g, '<br/>');
		}

		if (data.replacement_parts && data.replacement_parts.length)
		{
			data.alternate_parts =
			   		'<table cell-spacing="0" cell-padding="0">' +
						'<tr class="ytoolbar"><th width="25%">Alt. Part #</th><th>Brand</th></tr>';

			for (var i = 0; i < data.replacement_parts.length; i++)
			{
				var alternate_part = data.replacement_parts[i];
				data.alternate_parts += '<tr><td><a href="javascript: void()" onclick="return PartExplorer.loadPartDetail(\''+alternate_part['parts_app_node_id']+'\', \''+alternate_part['sku']+'\');">'+alternate_part['sku']+'</a></td><td>'+alternate_part['make']+'</td></tr>';
			}

			data.alternate_parts += '</table>';
		}

		if (data.properties)
		{
			data.properties_table =
					'<table cell-spacing="0" cell-padding="0">' +
			    		'<tr class="ytoolbar">' +
			    			'<th>Properties</th>' +
			    		'</tr>' +
			    		'<tr>' +
			    			'<td><div>'+data.properties.replace(/;/g, '<br/>')+'</div></td>' +
			    		'</tr>' +
			    	'</table>';
		}

		return data;
	}
});

/**
 * Overall controller for the part listing grid and the part detail pane.
 */
var PartWidget = function(layoutEl, filterEl, gridEl, detailEl, detailViewEl, data, pageSize) {
	if (!data)
	{
		data = [];
	}

	if (!pageSize)
	{
		pageSize = 20;
	}

	this.pageSize = pageSize;

	this.delayedTask = new YAHOO.ext.util.DelayedTask(this.filter, this);

	this.dataModel = new CITDataModel(data, this.pageSize);

	this.colModel = new YAHOO.ext.grid.DefaultColumnModel([
		{header: "Part #", width: 115},
		{header: "Part Name", width: 120},
		{header: "Description", width: 180},
		{header: "Properties", width: 180},
		{header: "Std. Pkg.", width: 55, sortFormat: "Numeric"}
	]);

	this.colModel.defaultSortable = true;

	this.selModel = new YAHOO.ext.grid.SingleSelectionModel();

	this.grid = new YAHOO.ext.grid.Grid(gridEl, {
		 //animate: true,
		 //autoHeight: true,
		 //autoSizeColumns: true,
		 monitorWindowResize: false,
		 dataModel: this.dataModel,
		 colModel: this.colModel,
		 selModel: this.selModel,
		 stripeRows: false,
		 trackMouseOver: true
	});

	this.grid.on('keydown', this.handleGridKeyDown, this, true);
	this.dataModel.on('load', this.handleDataModelLoad, this, true);

	this.selModel.on('selectionchange', this.handleSelection, this, true);
	this.dataModel.removeListener('rowsdeleted', this.deleteRows, this);

	this.handleDataUpdate(this.dataModel);

    // create the main layout
    this.layout = new YAHOO.ext.BorderLayout(layoutEl, {
        center: {
        	titlebar: false,
        	//title: 'Filter: <input id="' + filterEl.toString() + '" type="text" />',
        	split: true,
			fitToFrame: true
        },
        south: {
        	split: true,
        	titlebar: true,
        	title: 'Detail',
        	fitToFrame: true,
        	collapsible: true,
        	initialSize: 250,
			collapsed: false
        }
    });

    this.partDetail = new PartView(detailViewEl, false, false);

    // tell the layout not to perform layouts until we're done adding everything
    this.layout.beginUpdate();
    this.grid.render();

    this.layout.add('center', new YAHOO.ext.GridPanel(this.grid), {fitToFrame: true});

    this.southPanelReference = new YAHOO.ext.ContentPanel(detailEl , {fitToFrame: true});
    this.layout.add('south', this.southPanelReference);
    this.southReference = this.layout.getRegion("south");

    this.layout.restoreState();
    this.layout.endUpdate();

	this.ignoreSelect = false;
	this.expandPartDetail();
	
	this.southReference.on('collapsed', function() {
		var lastRow = this.grid.getView().lastFocusedRow;
		if (lastRow) 
			this.grid.getView().focusRow(lastRow); 
		}, 
		this, true);

    //this.filterEl = filterEl;
    //YAHOO.ext.EventManager.on(filterEl, 'keyup', this.handleFilterType, this, true);
};

PartWidget.prototype = {
	/**
	 * Used to create a maximum length value of 30 characters
	 */
	trim: function(value) {
		if (value.length > 30)
		{
			return value.substr(0, 27) + "...";
		}

		return value;
	},

	/**
	 *
	 */
	loadDoc: function(url, callback, params) {
        var cb = {
            success: this.handleResponse,
            failure: this.handleFailure,
            scope: this,
     		argument: {callback: callback}
        };

		this.dataModel.fireEvent("beforeload", this.dataModel);
		YAHOO.util.Connect.asyncRequest("GET", url, cb, params);
		this.clearDetail();
	},

	/**
	 * Load the part detail based on the parts app node id
	 */
	loadPartDetail: function(parts_app_node_id, sku) {
		if (sku)
		{
    		this.southReference.titleTextEl.innerHTML = 'Detail <b>[Part Number: ' + sku + ']</b>';
		}
		else
		{
			this.southReference.titleTextEl.innerHTML = 'Detail';
		}

		this.partDetail.load({url: PartExplorer.makeJSDataURLPrefix(parts_app_node_id) + ".js"});

		this.expandPartDetail();
	},

	/**
	 * ensure that the part detail tray is in an expanded state
	 */
	expandPartDetail: function() {
		this.southReference.expand(null, true);
	},

	/**
	 * ensure that the part detail tray is in a collapsed state
	 */
	collapsePartDetail: function() {
		this.southReference.collapse(true);
	},

	/**
	 * clear the part grid data model and the part detail data model
	 */
	clear: function() {
		this.clearList();
		this.clearDetail();
	},

	/**
	 * clear the part list grid
	 */
	clearList: function() {
		this.dataModel.resetData([], this.pageSize);
		this.dataModel.loadPage(1);
	},

	/**
	 * Clear the part detail view
	 */
	clearDetail: function() {
		this.southReference.titleTextEl.innerHTML = 'Detail';

    	this.partDetail.jsonData = [];
    	this.partDetail.refresh();
	},

	/**
	 * call back function for data requests
	 */
    handleResponse: function(response){
        var json = response.responseText;

        try {
            var o = eval('('+json+')');

            this.dataModel.setOriginalJSON(json);
            this.dataModel.resetData(o, this.pageSize);
            this.dataModel.loadPage(1);


			if (this.filterEl) {
				getEl(this.filterEl).value = '';
			}

	        if(typeof response.argument.callback == 'function'){
                response.argument.callback(response);
            }
        }catch(e){
            this.handleFailure(response);
        }

		this.grid.view.updateHeaderSortState();
    },

	/**
	 * callback used during data request failure
	 */
    handleFailure: function(response){
        if(typeof response.argument.callback == 'function'){
            response.argument.callback(response);
        }
    },

	/**
	 * part detail data grid selection event handler. loads
	 * the part detail view with data
	 */
    handleSelection: function(sm, rows, ids) {
    	if (!this.ignoreSelect && ids.length)
    	{
			this.loadPartDetail(ids);

    		var rowIndex = this.grid.getSelectedRowIndex()
    		var sku = this.dataModel.getValueAt(rowIndex, 0);

    		this.southReference.titleTextEl.innerHTML = 'Detail <b>[Part Number: ' + sku + ']</b>';
    	}
    },

	/**
	 * data update event handler (called from grid data model)
	 */
    handleDataUpdate: function(dataModel) {
		if (this.grid.view)
		{
			this.grid.reset({ dataModel: this.dataModel });
			this.dataModel.pageData(1);
			this.grid.render();
			this.grid.view.updateHeaderSortState();
		}
	},

	handleGridKeyDown: function(e) {
		if(e.browserEvent.keyCode == e.LEFT){
			this.dataModel.loadPreviousPage();
			e.preventDefault();
		}else if(e.browserEvent.keyCode == e.RIGHT){
			this.dataModel.loadNextPage();
			e.preventDefault();
		}
    },

	handleDataModelLoad: function(e) {

		if (this.southReference.collapsed)
		{
			this.ignoreSelect = true;
		}

		this.clearDetail();
		this.selModel.selectFirstRow();

		this.ignoreSelect = false;
	},

	/**
	 * filter (no longer used) even handler
	 */
    handleFilterType: function(e) {
    	var target = e.getTarget();

    	if (target)
    	{
	    	var query = target.value;

	    	if (query)
	    	{
		    	this.delayedTask.delay(1000, this.filter, this, [query])
	    	}
    	}
    },

	/**
	 * match each sku in the parts grid against a regex filter
	 */
    filter: function(query) {
    	query = query.replace('^', '\^');
    	query = query.replace('$', '\$');
    	query = query.replace('[', '\[');
    	query = query.replace(']', '\]');
    	query = query.replace('.', '\.');
    	query = query.replace('*', '.*');
    	query = '^' + query;

    	regex = new RegExp(query, 'i');
    	this.dataModel.filter({1: regex});
    	this.dataModel.pageData(1);
    }
};

/**
 * Custom tree node loader
 */
var CITTreeLoader = function(config){

	CITTreeLoader.superclass.constructor.call(this, config);

    this.baseParams = {};
    this.requestMethod = 'GET';
};

YAHOO.extendX(CITTreeLoader, YAHOO.ext.tree.TreeLoader, {
	/**
	 * handles retrieving of child node data based on an existing node
	 */
	load: function(node, callback){
        if(node.attributes.children){ // preloaded json children
            var cs = node.attributes.children;
            for(var i = 0, len = cs.length; i < len; i++){
                node.appendChild(this.createNode(cs[i]));
            }
            if(typeof callback == 'function'){
                callback();
            }
        }else if(this.dataUrl){
            this.requestData(node, callback);
        }
	},

	/**
	 * data retrieval handler
	 */
    requestData : function(node, callback){
        if(this.fireEvent('beforeload', this, node, callback) !== false){
            var params = this.getParams(node);
            var cb = {
                success: this.handleResponse,
                failure: this.handleFailure,
                scope: this,
         		 argument: {callback: callback, node: node}
            };

			if (node.attributes.dataUrl)
			{
				this.transId = YAHOO.util.Connect.asyncRequest(this.requestMethod, node.attributes.dataUrl, cb, params);
			}
			else
			{
				this.transId = YAHOO.util.Connect.asyncRequest(this.requestMethod, this.dataUrl, cb, params);
			}
        }else{
            // if the load is cancelled, make sure we notify
            // the node that we are done
            if(typeof callback == 'function'){
                callback();
            }
        }
    },

	/**
	 * Node creation handler. Used for custom processing of JSON data for te node
	 */
    createNode : function(attr){
        if(this.applyLoader !== false){
            attr.loader = this;
        }

		attr.text = attr.name;
		attr.dataUrl = PartExplorer.makeJSDataURLPrefix(attr.parts_app_node_id) + ".js";
		attr.leaf = !attr.children;
		attr.children = false;

        return(attr.leaf ?
                        new YAHOO.ext.tree.TreeNode(attr) :
                        new YAHOO.ext.tree.AsyncTreeNode(attr));
    },

	/**
	 * request data callback (close enough)
	 */
    processResponse : function(response, node, callback){
        var json = response.responseText;
        try {
            var o = eval('('+json+')');

	        for(var i = 0, len = o.length; i < len; i++){
	            node.appendChild(this.createNode(o[i]));
	        }

	        if(typeof callback == 'function'){
                callback(response);
            }
        }catch(e){
            this.handleFailure(response);
        }
    },

	/**
	 * request data failure callback
	 */
    handleFailure : function(response){
        this.transId = false;
        var a = response.argument;
        this.fireEvent('loadexception', this, a.node, response);
        if(typeof a.callback == 'function'){
            a.callback(response);
        }
    }
});

/**
 * Customized grid data model for the part list grid. Used
 * to paginate large json results sets for faster viewing.
 */
CITDataModel = function(data, pageSize) {
	CITDataModel.superclass.constructor.call(this, data);

	this.pageSize = pageSize;
	this.loadedPage = 1;
	this.originalJSON = '';

	this.delayedTask = new YAHOO.ext.util.DelayedTask();

 	this.onLoad = new YAHOO.util.CustomEvent("load");
 	this.onLoadException = new YAHOO.util.CustomEvent("loadException");
	this.events["load"] = this.onLoad;
	this.events["beforeload"] = new YAHOO.util.CustomEvent("beforeload");
	this.events["loadexception"] = this.onLoadException;
};

YAHOO.extendX(CITDataModel, YAHOO.ext.grid.DefaultDataModel, {
	resetData: function(data, pageSize) {
		this.data = data;
		this.pageSize = pageSize;
		this.loadedPage = 1;

		this.sortColumn = 50; //apply sortColumn to some impossible number so sorting is taken away
	},

	setOriginalJSON: function(json) {
		this.originalJSON = json;
	},

	isPaged: function() {
		return true;
	},

	getTotalPages: function() {
		if (this.pageSize)
		{
			return Math.ceil(this.data.length / this.pageSize);
		}

		return 1;
	},

	getPageSize: function() {
		return this.pageSize;
	},

	getRowCount: function() {
		try
		{
			return (Math.min(this.pageSize, this.data.length - this.pageOffset||0));
		}
		catch (e)
		{
			return 0;
		}
	},

	getRow: function(rowIndex) {
		return this.data[rowIndex + this.pageOffset];
	},

	getRowId: function(rowIndex) {
		return this.data[rowIndex + this.pageOffset][0];
	},

	getValueAt: function(rowIndex, colIndex) {
		return this.data[rowIndex + this.pageOffset][colIndex + 1];
	},

	// Overridden to not fireRowsDeleted after each data splice so
	// that we can edit the data and then refresh the grid view when
	// finished.
	removeRows: function(startIndex, endIndex){
	    endIndex = endIndex || startIndex;
	    this.data.splice(startIndex, endIndex-startIndex+1);
	},

	removeRow: function(index){
	    this.data.splice(index, 1);
	},

    sort: function(sortInfo, columnIndex, direction, suppressEvent){
        // store these so we can maintain sorting when we load new data
        this.sortInfo = sortInfo;
        this.sortColumn = columnIndex;
        this.sortDir = direction;

		columnIndex++;

        var dsc = (direction && direction.toUpperCase() == 'DESC');
        var sortType = null;
		var sortFormat = "Default";
        if(sortInfo != null){
            if(typeof sortInfo == 'function'){
                sortType = sortInfo;
            }else if(typeof sortInfo == 'object'){
				// getSortType uses a zero-based indexing scheme
                sortType = sortInfo.getSortType(columnIndex-1);

				if (sortInfo.config[columnIndex-1].sortFormat)
				{
					sortFormat = sortInfo.config[columnIndex-1].sortFormat;
				}
            }
        }
        var fn = function(cells, cells2){
            var v1 = sortType ? sortType(cells[columnIndex], cells) : cells[columnIndex];
            var v2 = sortType ? sortType(cells2[columnIndex], cells2) : cells2[columnIndex];
            if(v1 < v2)
    			return dsc ? +1 : -1;
    		if(v1 > v2)
    			return dsc ? -1 : +1;
    	    return 0;
        };

        var fnNumeric = function(cells, cells2){
            var v1 = sortType ? sortType(cells[columnIndex], cells) : cells[columnIndex];
            var v2 = sortType ? sortType(cells2[columnIndex], cells2) : cells2[columnIndex];

			v1 = (v1.replace(/\D/, "")) * 1.0;
			v2 = (v2.replace(/\D/, "")) * 1.0;

            if(v1 < v2)
    			return dsc ? +1 : -1;
    		if(v1 > v2)
    			return dsc ? -1 : +1;
    	    return 0;
        };

		if (sortFormat == "Numeric")
		{
			this.data.sort(fnNumeric);
		} else {
	        this.data.sort(fn);
		}

        if(!suppressEvent){
           this.fireRowsSorted(columnIndex - 1, direction);
        }
    },

	loadPage: function(pageNum, callback, keepExisting) {
		this.fireEvent("beforeload", this);

		this.delayedTask.delay(50, this.pageData, this, [pageNum, callback]);
	},

	loadPreviousPage: function() {
		if (this.loadedPage && this.loadedPage > 1)
		{
			this.loadPage(this.loadedPage - 1);
		}
	},

	loadNextPage: function() {
		if (this.loadedPage && this.loadedPage < this.getTotalPages())
		{
			this.loadPage(this.loadedPage + 1);
		}
	},

	pageData: function(pageNum, callback) {
		this.loadedPage = pageNum;
		this.pageOffset = this.pageSize * (this.loadedPage - 1);

		this.fireTableDataChanged();
		this.fireEvent("load", this.loadedPage, this.getTotalPages());

		if (typeof callback == "function")
		{
			callback(this, true);
		}
	},

	filter: function(query) {
		var o = eval('('+this.originalJSON+')');
		this.resetData(o, this.pageSize);
		this.pageData(1);

		return CITDataModel.superclass.filter.call(this, query);
	}
});

/**
 * Customized data model for the order form item grid. Hooks
 * into a PollingCookieProvider
 */
OrderFormDataModel = function(stateProvider) {
	this.state = stateProvider;

	this.updating = false;

	var data = this.state.get('order');
	if (!data)
	{
		data = [];
	}

	OrderFormDataModel.superclass.constructor.call(this, data);

	this.on('cellupdated', this.persist, this, true);
	this.on('rowsinserted', this.persist, this, true);
	this.on('rowsupdated', this.persist, this, true);
	this.on('rowsdeleted', this.persist, this, true);

	this.state.on('statechange', this.refresh, this, true);
}

YAHOO.extendX(OrderFormDataModel, YAHOO.ext.grid.DefaultDataModel, {
	startUpdate: function() {
		 this.updating = true;
	},

	endUpdate: function() {
		this.updating = false;

		this.persist();
	},

	getValueAt: function(row, column) {
		if (column == 0)
		{
			return row + 1;
		}

		return OrderFormDataModel.superclass.getValueAt.call(this, row, column);
	},

	persist: function() {
		if (!this.updating)
		{
			if (this.data != null && this.data instanceof Array && this.data.length)
			{
				this.state.set('order', this.data);
			}
			else
			{
				this.state.set('order', '');
			}
		}
	},

	refresh: function(state, key, value) {
		if (key == 'order' || typeof key == 'undefined')
		{
			var data = this.state.get('order');

			if (!data || typeof data != 'object' )
			{
				data = [];
			}

			this.data = data;
			this.fireTableDataChanged();
		}
	}
});

/**
 * Controlling widget for the order form (items and user data)
 */
var OrderForm = function(gridEl) {
	this.state = YAHOO.ext.state.Manager.getProvider();

	this.dataModel = new OrderFormDataModel(this.state);

	this.colModel = new YAHOO.ext.grid.DefaultColumnModel([
		{header: "LN.", width: 25, renderer: this.alignFieldCenter},
		{header: "PART NUMBER", width: 100},
		{header: "QTY", width: 35, editor: new YAHOO.ext.grid.NumberEditor({allowNegative: false, allowDecimals: false, allowBlank: false, minValue: 1, maxValue: 999999}), renderer: this.alignFieldCenter},
		{header: "DESCRIPTION", width: 200},
		{header: "DNET PRICE", width: 70, renderer: this.formatMoney},
		{header: "TOTAL NET", width: 70, renderer: this.formatMoney},
		{header: "COMMENTS", width: 170, editor: new YAHOO.ext.grid.TextEditor({allowBlank: true, maxLength: 36})}
	]);

	this.colModel.defaultSortable = false;

	this.selModel = new YAHOO.ext.grid.EditorAndSelectionModel();

	this.grid = new YAHOO.ext.grid.EditorGrid(gridEl, {
		 autoHeight: true,
		 monitorWindowResize: false,
		 dataModel: this.dataModel,
		 colModel: this.colModel,
		 selModel: this.selModel,
		 stripeRows: true,
		 trackMouseOver: true
	});

	this.rerenderTask = new YAHOO.ext.util.DelayedTask(this.rerender, this);

	this.dataModel.on('cellupdated', this.handleOrderGridCellUpdate, this, true);
	this.dataModel.on('datachanged', this.handleOrderGridUpdate, this, true);

	this.handleOrderGridUpdate(this.dataModel);
	this.grid.render();

	this.grid.on('afteredit', this.afterEdit, true, true);
	this.grid.on('beforeedit', this.beforeEdit, true, true);

	//set up listener
	this.state.on('statechange', this.handleOrderFormUpdate, this, true);

	this.setDelayedTask = new YAHOO.ext.util.DelayedTask();
};

OrderForm.prototype = {
	setOrderTotal: function(value) {
		value -= 0;
		value = (Math.round(value*100))/100;
		value = (value == Math.floor(value)) ? value + '.00' : ( (value*10 == Math.floor(value*10)) ? value + '0' : value);

		var order_total = getEl('order_total');

		if (order_total)
		{
			order_total.dom.innerHTML = value;
		}
	},

	formatMoney: function(value) {
		value = Number(value);

		//value = (Math.round(value*100))/100;
		//value = (value == Math.floor(value)) ? value + '.00' : ( (value*10 == Math.floor(value*10)) ? value + '0' : value);

		return '<div style="text-align: right">' + "$" + value.toFixed(2) + '</div>';
	},

	alignFieldCenter: function(value) {
		return '<div style="text-align: center">' + value + '</div>';
	},

	alignFieldRight: function(value) {
		return '<div style="text-align: right">' + value + '</div>';
	},

	setFormValue: function(key, value) {
		if (!this.formValues)
		{
			this.formValues = {
				account_no: '',
				location_code: '',
				po_no: '',
				special_instructions: '',
				sold_to_name: '',
				sold_to_address_1: '',
				sold_to_address_2: '',
				sold_to_city: '',
				sold_to_state: '',
				sold_to_zip: '',
				sold_to_country: 'USA',
				ship_to_name: '',
				ship_to_address_1: '',
				ship_to_address_2: '',
				ship_to_city: '',
				ship_to_state: '',
				ship_to_zip: '',
				ship_to_country: 'USA',
				ship_via: '',
				order_class: '',
				promotion_code: '',
				out_of_stock_action: 'other_warehouse',
				ship_direct_to_customer: 'false',
				phone: ''
			};
		}

		if (this.formValues[key] != value)
		{
			this.formValues[key] = value;

			//during rapid setting we can get bugs
			this.setDelayedTask.delay(50, this.state.set, this.state, ['formValues', this.formValues]);
			//this.state.set('formValues', this.formValues);
		}
	},

	getFormValue: function(key) {
		return this.formValues[key];
	},

	handleOrderGridCellUpdate: function(dataModel, row, column) {
		if (column == 2)
		{
			//make sure net is correct
			var price = dataModel.getValueAt(row, 4);
			var qty = dataModel.getValueAt(row, 2);

			this.handleOrderGridUpdate(dataModel);

			dataModel.setValueAt(price * qty, row, 5);
		}

		return true;
	},

	handleOrderGridUpdate: function(dataModel) {
		//update totals
		var total = 0;

		for (var row = dataModel.getRowCount() - 1; row >= 0; row--)
		{
			total += dataModel.getValueAt(row, 5)
		}

		this.setOrderTotal(total);

		this.rerenderTask.delay(10);
	},

	handleOrderFormUpdate: function(state, key, value) {
		if (key == 'formValues' || typeof key == 'undefined')
		{
			this.formValues = this.state.get('formValues');
			var userid = this.state.get('userid');

			if (!this.formValues)
			{
				this.formValues = {
					account_no: '',
					location_code: '',
					po_no: '',
					special_instructions: '',
					sold_to_name: '',
					sold_to_address_1: '',
					sold_to_address_2: '',
					sold_to_city: '',
					sold_to_state: '',
					sold_to_zip: '',
					sold_to_country: 'USA',
					ship_to_name: '',
					ship_to_address_1: '',
					ship_to_address_2: '',
					ship_to_city: '',
					ship_to_state: '',
					ship_to_zip: '',
					ship_to_country: 'USA',
					ship_via: '',
					order_class: '',
					promotion_code: '',
					out_of_stock_action: 'other_warehouse',
					ship_direct_to_customer: 'false',
					phone: ''
				};
			}

			if (userid)
			{
				//also make the order form uneditable
				var account_element = getEl('account_no');

				if (account_element)
				{
					account_element.dom.readOnly = true;
					account_element.dom.disabled = true;
				}

				if (this.formValues['account_no'] != userid)
				{
					this.setFormValue('account_no', userid);

					//set it to keep from a double post race condition
					this.formValues['account_no'] = userid;
					return;
				}
			}

			for (element_name in this.formValues) {
				var current_element = getEl(element_name);

				// Don't update the contents of this element if it is currently in focus
				if (current_element && (element_name != this.element_in_focus))
				{
					if (!this.formValues[element_name])
					{
						this.formValues[element_name] = '';
					}

					current_element.dom.value = this.formValues[element_name];

					// Checkbox fix
					if (current_element.dom.type == 'checkbox')
					{
						if (current_element.dom.value == 'true')
						{
							current_element.dom.checked = true;
						}
						else
						{
							current_element.dom.checked = false;
						}
					}
				}
			}

			this.handleShipToCustomer();

			this.handleOrderGridUpdate(this.dataModel);
		}

		if (key == 'userid')
		{
			var userid = this.state.get('userid');

			if (userid && this.formValues['account_no'] != userid)
			{
				this.setFormValue('account_no', userid);
			}
		}
	},

	handleShipToCustomer: function() {
		var ship_to_box = getEl('ship_direct_to_customer');

		if (ship_to_box)
		{
			for (element_name in this.formValues)
			{
				var current_element = getEl(element_name);

				if (current_element && element_name.indexOf('ship_to') > -1)
				{
					if (ship_to_box.dom.checked)
					{
						ship_to_box.dom.value = 'true';
						current_element.dom.disabled = false;
						current_element.dom.style.backgroundColor = 'white';

						if (element_name == 'ship_to_country' && this.formValues['ship_to_country'] == '')
						{
							this.setFormValue('ship_to_country', 'USA');
						}
					}
					else
					{
						ship_to_box.dom.value = 'false';

						this.setFormValue(element_name, '');

						current_element.dom.disabled = true;
						current_element.dom.style.backgroundColor = 'gray';
					}
				}
			}
		}
	},

	deleteAll: function(skipConfirm) {
		if (skipConfirm || window.confirm("Are You Sure?"))
		{
			if (this.grid.view)
			{
				this.grid.view.unplugDataModel(this.dataModel);
			}

			this.dataModel.removeAll();

			if (this.grid.view)
			{
				this.grid.setDataModel(this.dataModel, false);
			}

			this.rerenderTask.delay(10);
		}
	},

	deleteSelected: function() {
		var rows = this.grid.getSelectedRowIndexes();

		if (this.grid.view)
		{
			this.grid.view.unplugDataModel(this.dataModel);
		}

		this.dataModel.startUpdate();

		for (var row = rows.length - 1; row >= 0; row --)
		{
			this.dataModel.removeRow(rows[row]);
		}

		this.dataModel.endUpdate();

		if (this.grid.view)
		{
			this.grid.setDataModel(this.dataModel, false);
		}

		this.rerenderTask.delay(1);
	},

	rerender: function() {
		if (this.grid.view)
		{
			this.grid.view.renderRows(this.dataModel);
			this.grid.view.adjustForScroll();
	        this.grid.view.updateWrapHeight();
			this.grid.view.adjustForScroll();

			if (this.dataModel.getRowCount())
			{
				this.grid.view.updateCell(this.dataModel, 0, 0);
			}
		}
	},

	_getValues: function(procName) {
		var submittable_values = {
			'ProcName':			procName,

			'H-User-id': 		this.formValues['account_no'] != null ? this.formValues['account_no'] : '',
			'tLocCode':			this.formValues['location_code'] != null ? this.formValues['location_code'] : '',

			'tnRvCustPO': 		this.formValues['po_no'] != null ? this.formValues['po_no'] : '',
			'tnRvOrdClass': 	this.formValues['order_class'] != null ? this.formValues['order_class'] : '',

			'rbBOyes': 			this.formValues['out_of_stock_action'] == 'backorder' ? 'true' : 'false',
			'rbBOno': 			this.formValues['out_of_stock_action'] == 'cancel' ? 'true' : 'false',
			'rbBOother': 		this.formValues['out_of_stock_action'] == 'other_warehouse' ? 'true' : 'false',

			'cbshipvia': 		this.formValues['ship_via'] != null ? this.formValues['ship_via'] : '',

			'tcompany':			this.formValues['ship_to_name'] != null ? this.formValues['ship_to_name'] : '',
			'taddr1':			this.formValues['ship_to_address_1'] != null ? this.formValues['ship_to_address_1'] : '',
			'taddr2':			this.formValues['ship_to_address_2'] != null ? this.formValues['ship_to_address_2'] : '',
			'tcity':			this.formValues['ship_to_city'] != null ? this.formValues['ship_to_city'] : '',
			'tzip':				this.formValues['ship_to_zip'] != null ? this.formValues['ship_to_zip'] : '',
			'tstate':			this.formValues['ship_to_state'] != null ? this.formValues['ship_to_state'] : '',

			'tPhone':			this.formValues['phone'] != null ? this.formValues['phone'] : '',

			'tInstructions':	this.formValues['special_instructions'] != null ? this.formValues['special_instructions'] : '',

			'tpromotioncode':	this.formValues['promotion_code'] != null ? this.formValues['promotion_code'] : '',

			'H-Source': clientAgent,
			'H-Version': clientVersion,

			'ol[0]': '["part","qty","price","com"]'
		};


		var order_items = this.dataModel.data;
		var count = 0;

		for (var order_item in order_items)
		{
			count++;

			var part = order_items[order_item][1].toString().replace(/(\\|")/g,'\\$1');
			var qty = order_items[order_item][2].toString().replace(/(\\|")/g,'\\$1');
			var price = order_items[order_item][4].toString().replace(/(\\|")/g,'\\$1');
			var comments = order_items[order_item][6].toString().replace(/(\\|")/g,'\\$1');

			submittable_values['ol[' + count + ']'] = '["' + part + '","' + qty + '","' + price + '","' + comments + '"]';
		}

		return submittable_values;
	},

	checkAvailability: function() {
		var submittable_values = this._getValues('checkAvail');

		var password = this.state.get("password");

		if (password)
		{
			submittable_values['H-Password'] = password;
		}

		var params = '';

		for (var field in submittable_values)
		{
			params += encodeURIComponent(field) + '=' + encodeURIComponent(submittable_values[field]) + '&';
		}

		params = params.substr(0, params.length - 1);

		YAHOO.util.Connect.asyncRequest('POST', '/proxy', { scope: this, success: this._submitSuccess, failure: this._submitFailure }, params);
		return false;
	},

	submit: function() {
		var submittable_values = this._getValues('submitOrd');

		var converted_html = '';

		for (var submittable_value in submittable_values)
		{
			converted_html += '<input type="hidden" name="' + submittable_value + '" value="' + submittable_values[submittable_value].replace(/\"/g, '&quot;') + '" />';
		}

		var win = window.open('', 'orderSubmittal', 'scrollbars=yes, resizeable=yes, menubar=no, location=no, width=600, height=480, left=' + ((screen.availWidth - 600) / 2) + ', top=' + ((screen.availHeight - 480) / 2));

		if (!win)
		{
			alert('Please enable pop-ups');
		}
		else
		{
			var password = this.state.get("password");
			var password_string = '';
			var onload_string = 'document.getElementById(\'password\').focus()';
			var title_string = 'Please Enter Your Password';
			var warning = '<tr><td><b>Your order will now be sent to Tisco and automatically processed.  There will not be another opportunity to review your order unless errors are found.  If you would like to make any further changes to your order first, click Cancel now.  Otherwise, click Continue to transmit and finalize your order</b><br/><br/></td></tr>';

			if (password)
			{
				password_string = password.replace(/&/g,'&amp;').replace(/>/g,'&gt;').replace(/</g,'&lt;').replace(/"/g,'&quot;');
				onload_string = '';
				title_string = 'Please Confirm Your Submission...';
			}

			win.document.open('text/html');

			win.document.write(
				'<html>' +
					'<head>' +
						'<title>' + title_string + '</title>' +
						'<link rel="stylesheet" type="text/css" href="css/PartExplorer.css"/>' +
						'<link rel="stylesheet" type="text/css" href="css/OrderForm.css"/>' +
					'</head>' +
					'<body style="width: 300px; margin: 150px" onload="' + onload_string + '">' +
						 '<form id="passwordForm" action="javascript: void" onsubmit="window.opener.orderWidget.submitToTisco(this); this[\'H-Password\'].disabled = true; this[\'submitButton\'].value = \'Please Wait...\'; this[\'submitButton\'].disabled = true; return false">'+
							converted_html +
							'<table class="orderGridForm">' +
								 warning +
								'<tr><td>Password:</td></tr>' +
								'<tr><td class="outlined"><div><input id="password" type="password" name="H-Password" value="' + password_string + '"/></div></td></tr>' +
								'<tr><td><div id="orderGridControls" class="orderGridControls"><input type="button" value="Cancel" onclick="window.close();" />&nbsp;<input type="submit" name="submitButton" value="Continue"/></div></td></tr>' +
							'</table>' +
						'</form>' +
					'</body>' +
				'</html>'
			);
			win.document.close();

			win.focus();

			try
			{
				win.document.getElementById('password').focus();
			}
			catch (e)
			{}
		}
	},

	submitToTisco: function(frm) {
		YAHOO.util.Connect.setForm(frm);
		YAHOO.util.Connect.asyncRequest('POST', '/proxy', { scope: this, success: this._submitSuccess, failure: this._submitFailure });
		return false;
	},

	_submitSuccess: function(response) {
		if (response.responseText)
		{
			var status_window = window.open('', 'orderSubmittal', 'scrollbars=yes, resizeable=yes, menubar=no, location=no, width=600, height=480, left=' + ((screen.availWidth - 600) / 2) + ', top=' + ((screen.availHeight - 480) / 2));

			status_window.document.open('text/html');
			status_window.document.write(response.responseText);
			status_window.document.close();
		}
	},

	_submitFailure: function(response) {
		switch(response.status) {
			case 406:
				if (response.responseText)
				{
					var status_window = window.open('', 'orderSubmittal', 'scrollbars=yes, resizeable=yes, menubar=no, location=no, width=600, height=480, left=' + ((screen.availWidth - 600) / 2) + ', top=' + ((screen.availHeight - 480) / 2));

					status_window.document.open('text/html');
					status_window.document.write(response.responseText);
					status_window.document.close();
				}
				break;

			case 0:
			case 500:
				alert("There was a problem while trying to submit your order to TISCO, this could be the result of not having an active connection to the internet or TISCO\'s servers being down for maintenance.\n\nPlease try again later.");
				break;

			default:
				alert("An unexpected error has occured while trying to submit your order:\n\n" + "status: " + response.status + "\nerror: " + response.statusText + "\n\nPlease try again later.");
		}
	},

	conditionalClearSuccessfulOrder: function()
	{
		if (confirm('Order was successful! Clear your Order Form? Click cancel to leave your order items intact.'))
		{
			this.clearSuccessfulOrder();
		}
	},

	clearSuccessfulOrder: function()
	{
		this.deleteAll(true);

		//also delete po #, special instructions, and clear ship direct
		this.setFormValue('po_no', '');
		this.setFormValue('special_instructions', '');

		var ship_to_box = getEl('ship_direct_to_customer');
		ship_to_box.dom.checked = false;
		ship_to_box.dom.onclick();

		this.handleShipToCustomer();
	},

	formOnFocus: function(input) {
		// Disable updating this field
		this.element_in_focus = input.id;

		var td = getEl(input.parentNode.parentNode);

		if (td)
		{
			td.addClass('red');
		}
	},

	formOnBlur: function(input) {
		// Re-enable updating this field
		this.element_in_focus = '';

		var td = getEl(input.parentNode.parentNode);

		if (td)
		{
			td.removeClass('red');
		}
	},

	beforeEdit: function(grid, row, column) {
		previous_cell_value = grid.dataModel.data[row][column];
	},

	afterEdit: function(grid, row, column) {
		if (column !== 2) {
			return;
		}

		var quantity = grid.dataModel.data[row][2];
		var standard_qty = 1;

		if (grid.dataModel.data[row][7])
		{
			standard_qty = grid.dataModel.data[row][7];
		}

		if (quantity % standard_qty == 0)
		{
			return;
		}

		alert('Quanity must be a multiple of ' + standard_qty);

		grid.dataModel.setValueAt(previous_cell_value, row, column);
	},

	previous_cell_value: 1,

	element_in_focus: '',

	submittal_window: null
};

/**
 * Because of problems with printing the grid in its javascripty form, had
 * to create a simpler table based templated view that's only displayed during
 * a print operation
 */
var OrderView  =  function(element) {

   var template = new YAHOO.ext.Template(
		'<tr class="{stripe}">' +
			'<td class="center line first">{line}</td>'	 +
			'<td class="part_number">{part_number}</td>' +
			'<td class="center quantity">{quantity}</td>' +
			'<td class="description">{description}</td>' +
			'<td class="right dnet_price">{dnet_price}</td>' +
			'<td class="right total_net">{total_net}</td>' +
			'<td class="comments">{comments}</td>' +
		'</tr>'
    );

	this.outerTemplate = new YAHOO.ext.Template(
		'<table class="orderFormTable" cellpadding="0" cellspacing="0">' +
			'<thead>' +
				'<tr>' +
					'<th class="line center first">LN.</th>' +
					'<th class="part_number">PART NUMBER</th>' +
					'<th class="quantity center">QTY</th>' +
					'<th class="description">DESCRIPTION</th>' +
					'<th class="dnet_price">DNET PRICE</th>' +
					'<th class="total_net">TOTAL NET</th>' +
					'<th class="comments">COMMENTS</th>' +
				'</tr>' +
			'</thead>' +
			'<tbody>{table_body}</tbody>' +
		'</table>'
	);

	var dataModel = new OrderFormDataModel(YAHOO.ext.state.Manager.getProvider());

    OrderView.superclass.constructor.call(this, element, template, dataModel);
};

YAHOO.extendX(OrderView, YAHOO.ext.View, {
    renderEach : function(data, index){
        this.html[this.html.length] = this.tpl.applyTemplate(this.prepareData(data, index));
    },

	refresh : function(){
        this.clearSelections();
        this.el.update('');
        this.html = [];
        if(this.renderUpdates || this.jsonRoot){
            var o = this.jsonData;
            if(o){
                for(var i = 0, len = o.length; i < len; i++) {
                	this.renderEach(o[i]);
                }
            }
        }else{
           this.dataModel.each(this.renderEach, this);
        }
        var strHtml;
        if(this.html.length > 0){
            strHtml = this.html.join('');
        }else{
            strHtml = this.emptyText;
        }

		strHtml = this.outerTemplate.applyTemplate({ table_body: strHtml });

        this.el.update(strHtml);
        this.html = null;
        this.nodes = this.el.dom.childNodes;
        this.updateIndexes(0);
    },

	prepareData: function(data, index) {

		data = {
			line: index + 1,
			part_number: data[1],
			quantity: data[2],
			description: data[3],
			dnet_price: this.formatMoney(data[4]),
			total_net: this.formatMoney(data[5]),
			comments: data[6]
		};

		if (index % 2 > 0)
		{
			data.stripe = 'altRow';
		}
		else
		{
			data.stripe = '';
		}

		return data;
	},

	formatMoney: function(value) {
		value -= 0;
		value = (Math.round(value*100))/100;
		value = (value == Math.floor(value)) ? value + '.00' : ( (value*10 == Math.floor(value*10)) ? value + '0' : value);
		return '<div style="text-align: right">' + "$" + value + '</div>';
	},

	alignFieldCenter: function(value) {
		return '<div style="text-align: center">' + value + '</div>';
	},

	alignFieldRight: function(value) {
		return '<div style="text-align: right">' + value + '</div>';
	}
});

YAHOO.ext.grid.CellEditor.prototype.initEvents = function(){
	var stopOnEnter = function(e){
		if(e.browserEvent.keyCode == e.RETURN){
			this.stopEditing(true);
		}else if(e.browserEvent.keyCode == e.ESC){
			this.setValue(this.originalValue);
			this.stopEditing(true);
		}
	};

	this.element.mon('keydown', stopOnEnter, this, true);
	this.element.on('blur', this.stopEditing, this, true);

	var maxLength = this.maxLength;

    var keyPress = function(e){
        var c = e.getCharCode();
		var element = e.getTarget();

        if(c != e.BACKSPACE && c != e.DELETE && c != e.LEFT && c != e.RIGHT && element.value.length >= maxLength){
            e.stopEvent();
        }
    };
    this.element.mon('keypress', keyPress, this, true);
};

YAHOO.ext.grid.NumberEditor.prototype.initEvents = function(){
    var stopOnEnter = function(e){
        if(e.browserEvent.keyCode == e.RETURN){
            this.stopEditing(true);
        }else if(e.browserEvent.keyCode == e.ESC){
            this.setValue(this.originalValue);
            this.stopEditing(true);
        }
    };

    var allowed = "0123456789";
    if(this.allowDecimals){
        allowed += this.decimalSeparator;
    }
    if(this.allowNegative){
        allowed += '-';
    }

	var maxValue = this.maxValue;

    var keyPress = function(e){
        var c = e.getCharCode();
		var element = e.getTarget();

        if(c != e.BACKSPACE && c != e.DELETE && c != e.LEFT && c != e.RIGHT && (element.value >= maxValue || allowed.indexOf(String.fromCharCode(c)) === -1)){
            e.stopEvent();
        }
    };
    this.element.mon('keydown', stopOnEnter, this, true);
    var vtask = new YAHOO.ext.util.DelayedTask(this.validate, this);
    this.element.mon('keyup', vtask.delay.createDelegate(vtask, [this.validationDelay]));
    this.element.mon('keypress', keyPress, this, true);
    this.element.on('blur', this.stopEditing, this, true);
};

/**
 * Simple utility functions for handling the css class switching of
 * buttons used in the interface
 */
var Button = {
	hoverButton: function(element) {
		getEl(element).addClass('buttonhover');
	},

	unhoverButton: function(element) {
		getEl(element).removeClass('buttonhover');
	},

	downButton: function(element) {
		getEl(element).addClass('buttondown');
	},

	upButton: function(element) {
		getEl(element).removeClass('buttondown');
	},

	disableForPeriod: function(element, period, message) {
		element = getEl(element);

		element.dom.disabled = true;
		element.addClass('buttondisabled');
		element.removeClass('buttondown');
		element.removeClass('buttonhover');

		var previous_text = element.dom.value;

		if (message)
		{
			element.dom.value = message;
		}

		if (!period)
		{
			period = 2000;
		}

		Button._enable.defer(period, this, [element, previous_text]);

		return false;
	},

	_enable: function(element, message) {
		if (message)
		{
			element.dom.value = message;
		}

		element.removeClass('buttondisabled');
		element.dom.disabled = false;
	}
};

if (YAHOO.widget.Menu)
{
	/**
	 * Got this from yui-ext forums as a work around for yui menu
	 * inside a border layout not displaying properly overtop of
	 * the center pane
	 */
	BorderLayoutMenu = function(obj, config) {
		BorderLayoutMenu.superclass.constructor.call(
			this,
			obj,
			config
		);
	};

	YAHOO.extend(BorderLayoutMenu, YAHOO.widget.Menu, {
	init: function(obj, config) {
		if(!this.ITEM_TYPE) {
			this.ITEM_TYPE = BorderLayoutMenuItem;
		}

		BorderLayoutMenu.superclass.init.call(this, obj);

		var currentConfig = this.cfg;

		if(config) {
			currentConfig.applyConfig(config, true);
		}

		currentConfig.fireQueue();
	},

	render: function(appendToNode, moduleElement) {

		BorderLayoutMenu.superclass.render.call(this, appendToNode, moduleElement);

		if(this.element.parentNode != document.body){
			document.body.insertBefore(this.element, document.body.firstChild);
		}
	}

	}); // end extend


	BorderLayoutMenuItem = function(p_oObject, p_oConfig) {

		BorderLayoutMenuItem.superclass.constructor.call(
			this,
			p_oObject,
			p_oConfig
		);

	};

	YAHOO.extend(BorderLayoutMenuItem, YAHOO.widget.MenuItem, {

	init: function(p_oObject, p_oConfig) {

		if(!this.SUBMENU_TYPE) {
			this.SUBMENU_TYPE = BorderLayoutMenu;
		}

		/*
			Call the init of the superclass (YAHOO.widget.MenuItem)
			Note: We don't pass the user config in here yet
			because we only want it executed once, at the lowest
			subclass level.
		*/
		BorderLayoutMenuItem.superclass.init.call(this, p_oObject);

		var oConfig = this.cfg;

		if(p_oConfig) {
			oConfig.applyConfig(p_oConfig, true);
		}

		oConfig.fireQueue();
	},

	// Public methods

	/**
	* @method toString
	* @description Returns a string representing the menu bar item.
	* @return {String}
	*/
	toString: function() {
		return ("BorderLayoutMenuItem: " + this.cfg.getProperty("text"));
	}

	}); // END YAHOO.extend

	BorderLayoutMenuBar = function(obj, config) {
		BorderLayoutMenuBar.superclass.constructor.call(
			this,
			obj,
			config
		);
	};

	YAHOO.extend(BorderLayoutMenuBar, YAHOO.widget.MenuBar, {

	init: function(obj, config) {
		if(!this.ITEM_TYPE) {
			this.ITEM_TYPE = BorderLayoutMenuBarItem;
		}

		BorderLayoutMenuBar.superclass.init.call(this, obj);

		var currentConfig = this.cfg;

		if(config) {
			currentConfig.applyConfig(config, true);
		}

		currentConfig.fireQueue();
	}

	}); // end extend

	BorderLayoutMenuBarItem = function(obj, config) {
		BorderLayoutMenuBarItem.superclass.constructor.call(
			this,
			obj,
			config
		);
	};

	YAHOO.extend(BorderLayoutMenuBarItem, YAHOO.widget.MenuBarItem, {

	init: function(obj, config) {
		if(!this.SUBMENU_TYPE) {
			this.SUBMENU_TYPE = BorderLayoutMenu;
		}

		BorderLayoutMenuBarItem.superclass.init.call(this, obj);

		var currentConfig = this.cfg;

		if(config) {
			currentConfig.applyConfig(config, true);
		}

		currentConfig.fireQueue();
	}

	}); // end extend

}

var QuickBrowseWidget = function(form, parent_id, suffix, element_class, submit_unchangeable) {
	this.parent_id = parent_id;
	this.enabled = true;

	if (!this.parent_id)
	{
		this.parent_id = 0;
	}

	this.suffix = suffix;

	if (!this.suffix)
	{
		this.suffix = '';
	}

	this.element_class = element_class;

	if (!this.element_class)
	{
		this.element_class = '';
	}

	this.submit_unchangeable = submit_unchangeable ? true : false;

	this.form = getEl(form);

	this.events = {
        'selectionchange': new YAHOO.util.CustomEvent('selectionchange'),
		'deadend': new YAHOO.util.CustomEvent('deadend')
    };

	this.loadCallbackDelegate = this.loadCallback.createDelegate(this);
	this.init();
};

YAHOO.extendX(QuickBrowseWidget, YAHOO.ext.util.Observable, {
	init: function() {
		this.views = new Array();
		this.levels = new Array();

		//find our select inputs within this form element
		//modify their onchange behavior to set up listeners
		for (var i = 0; i < this.form.dom.elements.length; i++)
		{
			if (this.form.dom.elements[i].type && this.form.dom.elements[i].type.indexOf('select') == 0)
			{
				if (this.element_class.length == 0 || this.form.dom.elements[i].className == this.element_class)
				{
					this.levels.push(this.form.dom.elements[i]);
					this.form.dom.elements[i].onchange = this.selectionChangeHandler.createDelegate(this, [this.levels.length - 1], true);
				}
			}

			if (this.form.dom.elements[i].type && this.form.dom.elements[i].type == 'submit')
			{
				this.submit_button = getEl(this.form.dom.elements[i]);
			}
		}

		//create QuickBrowseViews for each select
		for (var j = 0; j < this.levels.length;  j++)
		{
			this.views.push(new QuickBrowseView(this.levels[j]));
		}

		//load parent file as first select's values
		if (this.levels[0] && !this.submit_unchangeable)
		{
			this.views[0].load(PartExplorer.makeJSDataURLPrefix(this.parent_id) + this.suffix + '.js', '', this.loadCallbackDelegate);
			this.levels[0].disabled = false;
		}
	},

	disable: function() {
		this.enabled = false;

		if (this.levels)
		{
			for (var i = 0; i < this.levels.length; i++)
			{
				this.levels[i].selectedIndex = 0;
				this.levels[i].disabled = true;
			}
		}
	},

	enable: function() {
		this.enabled = true;

		if (this.levels[0])
		{
			this.levels[0].disabled = false;
		}
	},

	reset: function(parent_id, suffix) {
		if (parent_id)
		{
			this.parent_id = parent_id;
		}

		if (suffix)
		{
			this.suffix = suffix;
		}

		for (var i = 0; i < this.levels.length; i++)
		{
			this.levels[i].selectedIndex = 0;
			this.levels[i].disabled = true;
		}

		if (parent_id || suffix)
		{
			if (this.levels[0])
			{
				this.enable();
				this.views[0].load(PartExplorer.makeJSDataURLPrefix(this.parent_id) + this.suffix + '.js', '', this.loadCallbackDelegate);
			}
		}
		else
		{
			this.levels[0].disabled = !this.enabled;
			this.levels[0].onchange(null);
		}
	},

	loadIdAtLevel: function(id, level) {
		if (this.levels[level] && !this.levels[level].disabled)
		{
			var found = false;

			for (var i = 0; i < this.levels[level].options.length; i++)
			{
				if (this.levels[level].options[i].getAttribute("id") == id)
				{
					this.levels[level].selectedIndex = i;
					found = true;
					break;
				}
			}

			if (found)
			{
				this.selectionChangeHandler(null, level);
			}
		}
	},

	selectionChangeHandler: function(e) {
		level = arguments[arguments.length - 1];

		if (!level)
		{
			level = 0;
		}

		if (!this.submit_unchangeable && level == 0)
		{
			this.submit_button.dom.disabled = true;
		}

		for (var i = level + 1; i < this.levels.length; i++)
		{
			this.levels[i].selectedIndex = 0;
			this.levels[i].disabled = true;
		}

		var selectedIndex = this.levels[level].selectedIndex;
		var selectedId = this.levels[level].options[selectedIndex].getAttribute("id");

		if (selectedId && selectedId.substr(0, 5) == 'elgen')
		{
			selectedId = false;
		}

		try
		{
			this.fireEvent('selectionchange', this, this.form, level, selectedId);
		}
		catch (e) {}

		if (!this.submit_unchangeable && level == 0 && selectedId)
		{
			this.submit_button.dom.disabled = false;
		}

		if (selectedId && this.views[level + 1])
		{
			this.views[level + 1].load(PartExplorer.makeJSDataURLPrefix(selectedId) + this.suffix + ".js", '', this.loadCallbackDelegate);
		}
		else if (!this.submit_button.dom.disabled && selectedIndex > 0)
		{
			try
			{
				this.fireEvent('deadend', this);
			}
			catch (e)
			{}

			//auto submit
			//PartExplorer.search(this.form.dom);
		}
	},

	loadCallback: function(element, success) {
		if (element.dom.childNodes.length > 2)
		{
			element.dom.disabled = false;

			//check for Tractor item
			for (var i = 0; i < element.dom.options.length; i++)
			{
				if (element.dom.options[i].text == 'Tractor')
				{
					//element.dom.options[i].selected = true;
					element.dom.selectedIndex = i;
					element.dom.onchange(null);
					break;
				}
			}
		}
		else if (element.dom.childNodes.length == 2)
		{
			element.dom.disabled = !this.enabled;

			//auto select
			//element.dom.options[1].selected = true;
			element.dom.selectedIndex = 1;

			if (this.enabled)
			{
				element.dom.onchange(null);
			}
		}
		else if (!this.submit_button.dom.disabled)
		{
			try
			{
				this.fireEvent('deadend', this);
			}
			catch (e)
			{}

			//auto submit
			//PartExplorer.search(element.dom.form);
		}
	}
});

var QuickBrowseView = function(el, forcenew) {
	QuickBrowseView.superclass.constructor.call(this, el, forcenew);
	this.showLoadIndicator = false;
	this.setRenderer(new QuickBrowseRenderer());
};

YAHOO.extendX(QuickBrowseView, YAHOO.ext.UpdateManager, {
	load: function(url, params, callback, discardUrl) {
		this.update(url, params, callback, discardUrl);
	}
});

var QuickBrowseRenderer = function() {
    QuickBrowseRenderer.superclass.constructor.call();
};

YAHOO.extendX(QuickBrowseRenderer, YAHOO.ext.UpdateManager.BasicRenderer, {
	render: function(el, response, updateManager, callback) {
		try
		{
			if (response.responseText)
			{
				response = eval(response.responseText);
			}

			el.dom.options.length = 1;

			for (var i = 0; i < response.length; i++)
			{
				var child = document.createElement('option');
				child.setAttribute('id', response[i].id);
				child.appendChild(document.createTextNode(response[i].name));

				if (response[i].name == 'Tractor' || response.length == 1)
				{
					child.setAttribute('selected', 'selected');
				}

				el.dom.appendChild(child);
			}
		}
		catch (e)
		{}
	}
});

