if( typeof( svpply_api ) == 'undefined' ) {

// source: http://msdn.microsoft.com/en-us/library/ms537509(v=vs.85).aspx
function getInternetExplorerVersion()
// Returns the version of Internet Explorer or a -1
// (indicating the use of another browser).
{
  var rv = false; // Return value assumes failure.
  if (navigator.appName == 'Microsoft Internet Explorer')
  {
    var ua = navigator.userAgent;
    var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
    if (re.exec(ua) != null)
      rv = parseFloat( RegExp.$1 );
  }
  return rv;
}

function addEvent( obj, evt, fn ) {
	if ( typeof obj.attachEvent != 'undefined' )  {
		obj.attachEvent( "on" + evt, fn );
	}
	else if ( typeof obj.addEventListener != 'undefined' ) {
		obj.addEventListener( evt, fn, false );
	}
};

function addElementAfter( node, tag_type, html ) {
	var new_element = document.createElement( tag_type );
	if(html) new_element.innerHTML = html;
	node.parentNode.insertBefore( new_element, node.nextSibling );
};

function getElementsByClassName(cl) {
	var retnode = [];
	var myclass = new RegExp('\\b'+cl+'\\b');
	var elem = document.getElementsByTagName('*');
	for (var i = 0; i < elem.length; i++) {
		var classes = elem[i].className;
		if (myclass.test(classes)) retnode.push(elem[i]);
	}
	return retnode;
};

var jsonp = {
    callbackCounter: 0,
    fetch: function(url, callback) {
        var fn = 'JSONPCallback_' + this.callbackCounter++;
        window[fn] = this.evalJSONP(callback);
        url = url.replace('=JSONPCallback', '=' + fn);
        var scriptTag = document.createElement('SCRIPT');
        scriptTag.src = url;
        document.getElementsByTagName('HEAD')[0].appendChild(scriptTag);
    },
    evalJSONP: function(callback) {
        return function(data) {
            var validJSON = false;
	        if (typeof data == "string") {
	            try {validJSON = JSON.parse(data);} catch (e) {
	                /*invalid JSON*/
	            }
	        } else {
	            validJSON = JSON.parse(JSON.stringify(data));
	                window.console && console.warn(
	                'response data was not a JSON string');
            }
            if (validJSON) {
                callback(validJSON);
            } else {
                throw("JSONP call returned invalid or empty JSON");
            }
        }
    }
}
function product_button( placeholder, button_index ) {
	/* 
		sample parameter string:
		<sv:product-button type="boxed|micro|text" button-style="font-weight:bold;" ></sv:product-button>
		note: stylesheet grid isn't really set up for more than small
	*/
	var self = this;
	self.placeholder = placeholder;
	self.button_index = button_index;
	self.button_type = '';
	self.button_style = '';
	self.min_side = 190;
	self.grab_image_url = '';
	self.active_trigger = '';

	self.construct = function() {

		// if IE & < v8, do nothing
		msie = getInternetExplorerVersion();
		if(msie && msie < '8') return false;

		// initialize message listener
		if( window.addEventListener )
			window.addEventListener( "message", self.receive_message, false );
		else window.attachEvent("onmessage", self.receive_message);
		
		// place CSS
			var css = document.createElement("link");
			css.setAttribute("href", "http://svpply.com/assets/min/g=product_button_css&amp;1308683727");
			css.setAttribute("rel", "stylesheet");
			css.setAttribute("type", "text/css");
			document.getElementsByTagName("body")[0].appendChild(css);					  

		// get button class
			self.button_type = self.placeholder.getAttribute('type');
		// custom styling?
			self.button_style = ( self.button_type == 'text' ) 
				? self.placeholder.getAttribute('button-style')
				: '';

		// build it
			var button = '<div class="svpply_button ' + self.button_type + '" id="svpply_button_' + self.button_index + '" style="' + self.button_style + '" >Add to Svpply</div>';
			addElementAfter( self.placeholder, 'div', button );
			addEvent( 
				document.getElementById('svpply_button_' + self.button_index), 
				'click', 
				function() {
					self.initiate(this);
				}
			);
		
	};

	
	self.receive_message = function(e) {
		switch( e.data ) {
			case 'svpply.destruct' : self.destruct(); break;
			case 'svpply.scan_for_products' : self.scan_for_products(); break;
			case 'svpply.show_iframe' : self.show_iframe(); break;
			case 'svpply.refresh_iframe' : self.refresh_iframe(); break;
			case 'svpply.show_success_message' : self.show_success_message(); break;
		}
	};


	self.initiate = function( trigger ) {
		self.active_trigger = trigger;
		self.active_trigger.innerHTML = 'Adding&hellip;';
		self.active_trigger.className += ' active';
		self.generate_iframe();
	};

	
	self.generate_iframe = function() {
		/* load onionskin */
			var onionskin = document.createElement('div');
			onionskin.id = 'svpply_onionskin';
			document.getElementsByTagName("body")[0].appendChild(onionskin);
			addEvent( document.getElementById('svpply_onionskin'), 'click', self.destruct );
		/* load iFrame */
			var the_frame = document.createElement('iframe');
			the_frame.id = 'svpply_iframe';
			the_frame.name = 'svpply_iframe';
			the_frame.setAttribute('allowtransparency',true);
			the_frame.setAttribute('scrolling','no');
			the_frame.setAttribute('frameborder',0);
			the_frame.setAttribute('marginwidth',0);
			the_frame.setAttribute('marginheight',0);
			document.getElementsByTagName("body")[0].appendChild(the_frame);
			document.getElementById('svpply_iframe').src = 'http://svpply.com/svpply_button/index/' + Math.floor( Math.random() * 101 );
		/* grab frames container */
			var container = document.createElement("div");
			container.id = "svpply_frames";
			var theParent = document.getElementsByTagName('body')[0];
			var theChildren = theParent.children;
			theParent.insertBefore( container, theChildren[0] );
		/* from this point on, instructions come from the iFrame to self.receive_message() */
	};

	
	self.hide_iframe = function() {
		document.getElementById('svpply_onionskin').style.display = 'none';
		document.getElementById('svpply_iframe').style.display = 'none';
	};
	
	
	self.show_iframe = function() {
		document.getElementById('svpply_onionskin').style.display = 'block';
		document.getElementById('svpply_iframe').style.display = 'block';
	};
	
	
	self.refresh_iframe = function() {
		document.getElementById('svpply_iframe').refresh();
	};
	
	
	self.scan_for_products = function() {
		var hProduct = self.scan_for_hproduct();
		if( !hProduct ) {
			self.place_grab_frames();
		}
	};
	
	
	self.scan_for_hproduct = function() {
		// not implemented yet
		return false;
	};
	
	
	self.show_success_message = function() {
		var frame = document.createElement("div");
		frame.id = "svpply_msg_up_and_running";
		frame.innerHTML = '<h1>Success! Your Svpply is up and running.</h1><p>Now we need some information about this product before we can add it.</p>';
		frame.style.display = "block";
		document.getElementsByTagName("body")[0].appendChild(frame);
	};
	
	
	self.place_grab_frames = function() {
		self.hide_iframe();
		
		var frames = new Array();
		var images = document.getElementsByTagName("img");
		var j = 0;
		for( var i = 0; i < images.length; i++ ) {
			if( images[i].offsetWidth >= self.min_side && images[i].offsetHeight >= self.min_side ) {
				frames[j] = images[i];
				j++;
			}
		}
		for( var i = 0; i < frames.length; i++ ) {
			self.put_frame_around( frames[i], i, true );
		}
	};
	
	
	self.put_frame_around = function( image, i, msg_click ) {
		var position_of_image = self.position_of_image(image);
		var left = position_of_image[0] - 10; // subtract stroke of border
		var top = position_of_image[1]  - 10;
		var frame = document.createElement("div");
		frame.id = "svpply_frame_" + i;
		frame.setAttribute("class", "svpply_frame");
		frame.style.display = "block";
		frame.style.width  = ( image.offsetWidth - 20 ) + 'px';
		frame.style.height = ( image.offsetHeight - 20 ) + 'px';
		frame.style.left = left + "px";
		frame.style.top  = top  + "px";
		if( msg_click ) {
			frame.innerHTML = "<div>Click to select this product image</div>";
			addEvent( frame, 'click', function() {
				self.select_image( i, image );
			} );
		}
		document.getElementById("svpply_frames").appendChild(frame);
	};
	
	
	self.select_image = function(i, image) {
		self.grab_image_url = image.src;
		var url = 'http://svpply.com/svpply_button/grab' + 
				'?page_url='   + encodeURIComponent( document.location ) + 
				'&image_url='  + encodeURIComponent( self.grab_image_url ) +
				'&page_title=' + encodeURIComponent( document.title );
		document.getElementById('svpply_iframe').src = url;
	};
	
	
	self.destruct = function() {
		self.active_trigger.innerHTML = 'Added!';
		self.active_trigger.className = self.active_trigger.className.replace( / active/, '' );
		document.getElementsByTagName("body")[0].removeChild( document.getElementById('svpply_onionskin') );
		document.getElementsByTagName("body")[0].removeChild( document.getElementById('svpply_iframe') );
		document.getElementsByTagName("body")[0].removeChild( document.getElementById('svpply_frames') );
		if( (document) && (document.getElementById('svpply_msg_up_and_running')) ) document.getElementsByTagName("body")[0].removeChild( document.getElementById('svpply_msg_up_and_running') );
	};
		
	
	/* general functionality */
		
		self.position_of_image = function(elem) { 
			var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement,
			clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
			top  = box.top  + (self.pageYOffset || body.scrollTop ) - clientTop,
			left = box.left + (self.pageXOffset || body.scrollLeft) - clientLeft;
			return [left, top];
		};

	self.construct();

}
function feed_widget( params, i ) {

	// default and calculated properties
	var self = this;
		self.ie_legacy = false;
		self.counter = i;
		self.view; /* widget in the DOM */
		self.padding = 20;
		self.product_size = 'smaller'; /* image size from S3 store */
		self.thumbnail_max  = 120; /* thumbnail render size */
		self.limit = 9;
		self.activated_filter = 'all';
		self.msie = false;
	
	// required attributes
		self.source = params.getAttribute('source');
	
	// optional attributes
		self.link = 'My Svpply Favorites';
		self.background = 'white';
		self.width = 420;
		self.columns;
		self.rows;
	
	// private/undocumented attributes
		self.partner = false;
		self.show_curators = false;
		self.feed_filters = false;
		self.headline;
	
	
	self.construct = function() {
		// MSIE check
			self.msie = getInternetExplorerVersion();
			/* We check for both IE < 8 and "quirks mode" (which is triggered automatically
			 * by IE 8 for pages that are lacking a perfect doctype.
			 * Quirks mode issues are also fixed by ie_legacy.
			 * http://msdn.microsoft.com/en-us/library/cc288325(VS.85).aspx
			*/
			if(self.msie && (self.msie < '8' || document.documentMode == 5)) self.ie_legacy = true;
		// set parameters from embed code
			var parameters = new Array('link','background','partner','product_size','width','limit','rows','columns','partner','show_curators','feed_filters','headline');
			for( var i=0; i<parameters.length; i++ ){
				var parameter = parameters[i];
				if(params.getAttribute(parameter)) {
					value = isNaN(params.getAttribute(parameter))
						? params.getAttribute(parameter) 
						: parseInt(params.getAttribute(parameter), 10);
					self[parameter] = value;
				}
			}
		// calculate thumbnail size
			self.set_thumbnails_parameters();
			if(self.columns != null && self.rows != null) {
				self.reset_grid(new Array(self.columns,self.rows));
			}
		// insert CSS
			var css = document.createElement("link");
			css.setAttribute("href", "http://svpply.com/assets/min/g=feed_widget_css&amp;1308683727");
			css.setAttribute("rel", "stylesheet");
			css.setAttribute("type", "text/css");
			document.getElementsByTagName("body")[0].appendChild(css);
			if(self.ie_legacy) {
				var css = document.createElement("link");
				css.setAttribute("href", "http://svpply.com/assets/min/g=feed_widget_css_ie7&amp;1308683727");
				css.setAttribute("rel", "stylesheet");
				css.setAttribute("type", "text/css");
				document.getElementsByTagName("body")[0].appendChild(css);
			}
		// draw widget
			self.view = document.createElement('div');
			if(!self.ie_legacy) {
				self.view.setAttribute('class', 'feed_widget');
			} else {
				self.view.setAttribute('className', 'feed_widget');
			}
			if( self.partner ) {
				self.view.appendChild( self.build_tag( 'p', '', 'svpply_powered_by', 'Powered by <a href="http://svpply.com" target="_blank" >Svpply.com</a>' ) );
				self.view.appendChild( self.build_tag( 'div', '', 'svpply_hr', '' ) );
				if( self.headline ) {
					self.view.appendChild( self.build_tag( 'p', '', 'basic', self.headline ) );
				}
				self.svpply_curators = self.build_tag( 'ul', 'svpply_curators', 'svpply_curators', '' );
				self.view.appendChild( self.svpply_curators );
				self.view.appendChild( self.build_tag( 'div', '', 'svpply_hr', '' ) );
				if( self.feed_filters != null ) {
					self.filter_buttons = self.build_tag( 'ul', '', 'svpply_filter_buttons', '' );
					self.view.appendChild( self.filter_buttons );
				}
			}
			self.products = self.build_tag( 'ul', 'svpply_items', 'svpply_items', '' );
			self.view.appendChild( self.products );
			if( !self.partner ) {
				self.view.appendChild( self.build_tag( 'p', 'svpply_show_all', 'svpply_show_all', '<a href="' + self.source + '" target="_blank" >' + self.link + '</a>' ) );
			} else {
				self.view.appendChild( self.build_tag( 'p', 'svpply_show_all', 'svpply_show_all partner', '<a href="' + self.source + '" target="_blank" >' + self.link + '</a>' ) );
			}
			params.parentNode.insertBefore( self.view, params );
		// get JSON
			jsonp.fetch( self.source + ".json?callback=svpply_api.feed_widgets[" + self.counter + "].input_json&item_limit=" + self.limit + "&curators=" + self.show_curators + "&size=" + self.product_size, function(data) {});
			if( self.feed_filters ) self.output_filters();
		// trigger "loaded" event
			if(typeof jQuery != 'undefined'){
				jQuery(function(){
					jQuery(document).trigger('svpply_widget_loaded');
				});
			}
	};
	
	
	self.reset_grid = function(grid) {
		// set number of columns and rows; assign limit for json query
		self.columns = parseInt(grid[0], 10);
		self.rows = parseInt(grid[1], 10);
		self.limit = self.rows * self.columns;
		if(self.columns != '') {
			self.width = (self.columns*self.thumbnail_max) + (self.padding*(self.columns+1));
		}
	};
	
	
	self.set_thumbnails_parameters = function() {
		// get image size for S3 requests
		switch(self.product_size) {
			case 'small':
				self.thumbnail_max = 195;
				break;
			case 'smaller':
				self.thumbnail_max = 120;
				self.product_size = 'small';
				break;
			case 'medium':
				self.thumbnail_max = 450;
				break;
			case 'large':
				self.thumbnail_max = 625;
				break;
		}
		// create maximum image dimension
		if( self.width != '' && self.columns != '' ) {
			// resample thumbnail size to fit columns
			var padding = self.padding * ( self.columns + 1 );
			var calculated_width = self.width - padding;
			self.thumbnail_max = Math.floor( calculated_width / self.columns );
			if( self.thumbnail_max <= 195 ) self.product_size = 'small';
			else if( self.thumbnail_max <= 450 ) self.product_size = 'medium';
			else self.product_size = 'large';
		}
	};
	
	
	self.get_thumbnail_dimensions = function( x, y, ratio ) {
		// calculate individual thumbnail dimension
		var output = {};
		if( x < self.thumbnail_max && y < self.thumbnail_max ) {
			output.width  = x;
			output.height = y;
		}
		else {
			output.width = ( x >= y )
				? self.thumbnail_max 
				: Math.floor( self.thumbnail_max / ratio );
			output.height = ( y >= x )
				? self.thumbnail_max
				: Math.floor( self.thumbnail_max * ratio );
		}
		return output;
	};
	
	
	
	// JSONP callback
	self.input_json = function(r) {
		if( self.show_curators > 0 && typeof r.curators != 'undefined' ) {
			self.output_curators( r.curators );
		}
		self.output_products( r.items );
	};
	
	
	self.output_products = function( products ) {	
		self.view.setAttribute('style','background:'+self.background+'; width:'+self.width+'px;');
		if(self.ie_legacy) self.view.style.cssText = 'background:'+self.background+'; width:'+self.width+'px;';
		// empty ul.svpply_items (in case of filter action)
			if(self.products.hasChildNodes()) {
			    while(self.products.childNodes.length >= 1) {
			        self.products.removeChild(self.products.firstChild);
			    } 
			}
		var limit = (products.length<self.limit) ? products.length : self.limit;
		for( var i=0; i<limit; i++ ) {
			var item = products[i],
				dimensions = self.get_thumbnail_dimensions(item.width,item.height,item.ratio),
				img = document.createElement('img');
				img.src = item.sv_img_url;
				img.alt = item.page_title;
				img.width = dimensions.width;
				img.height = dimensions.height;
				img.setAttribute('style','width:'+dimensions.width+'px; height:'+dimensions.height+'px;');
			var wrapper = document.createElement('li');
				wrapper.setAttribute('style','width:'+self.thumbnail_max+'px; height:'+self.thumbnail_max+'px;');
				if(self.ie_legacy) wrapper.style.cssText = 'width:'+(self.thumbnail_max+self.padding)+'px; height:'+(self.thumbnail_max+self.padding)+'px;';
			var link = document.createElement('a');
				link.setAttribute('href','http://svpply.com'+item.link);
				link.setAttribute('target','_blank');
				link.appendChild(img);
			wrapper.appendChild(link);
			self.products.appendChild(wrapper);
		}
	};
		
	
	self.output_curators = function(curators) {
		for( var i=0; i<curators.length; i++ ) {
			var output = document.createElement('li'),
				curator = curators[i];
			if( typeof curator.full_name == 'undefined' ) curator.full_name = curator.username;
			output.innerHTML = "<a href='http://svpply.com/"+curator.username+"' target='_blank' class='username avatar'><img src='"+curator.avatar+"' width='48' height='48' /></a><br><a href='http://svpply.com/"+curator.username+"' target='_blank' class='username' >"+curator.full_name+"</a>";
			self.svpply_curators.appendChild(output);
		}
	};
	

	self.output_filters = function() {
		self.filter_buttons.appendChild(self.build_tag('li','','direction','Show:'));
		var feed_filters = self.feed_filters.split(',');
		for( var i=0; i<feed_filters.length; i++ ){
			filter_class = ( i == 0 ) ? 'checked' : '';
			var filter_tag = self.build_tag('li','',filter_class,feed_filters[i]);
			filter_tag.setAttribute('data-filter',feed_filters[i]);
			if( self.ie_legacy || self.msie != false && self.msie < 9 ) {
				filter_tag.attachEvent('onclick', self.run_filter);
			} else {
				filter_tag.addEventListener('click', self.run_filter, false);
			}
			self.filter_buttons.appendChild( filter_tag );
		}
	};
	
	
	self.run_filter = function(e){
		var target = (e.target) ? e.target : e.srcElement;
		self.activated_filter = target.getAttribute('data-filter');
		if( self.activated_filter == 'women' ) self.activated_filter = 'female';
		else if( self.activated_filter == 'men' ) self.activated_filter = 'male';
		// "uncheck" all
			for( var j = 1; j < target.parentNode.childNodes.length; j++ ) {
				target.parentNode.childNodes[j].className = '';
			}
		// "check" this
			target.className = 'checked';
		// apply filter
			var url = self.source+".json?callback=svpply_api.feed_widgets["+self.counter+"].input_json"+"&size="+self.product_size;
			url += (self.activated_filter != 'all') ? '&filter='+self.activated_filter : '';
			jsonp.fetch( url );
	};
	
	
	/* general functionality */

		self.build_tag = function( tag_type, tag_id, tag_class, tag_content ) {
			var tag = document.createElement( tag_type );
			tag.setAttribute( 'id', tag_id );
			if(self.ie_legacy) {
				tag.setAttribute( 'className', tag_class );
			} else {
				tag.setAttribute( 'class', tag_class );
			}
			tag.innerHTML = tag_content;
			return tag;
		};

	self.construct();

};

	
	/* API loader */

	var svpply_api = {

		feed_widgets : new Array(),
		product_buttons : new Array(),
		construct : function() {
			
			// scan document for instances of sv:feed-widget
			var tags = document.getElementsByTagName( 'sv:feed-widget' );
			for(var i=0; i<tags.length; i++){
				this.feed_widgets[i] = new feed_widget(tags[i], i);
			}
			// delete placeholders (must be done after loop, otherwise count is off)
			for(var i=0; i<tags.length; i++){
				tags[i].parentNode.removeChild(tags[i]);
			}
			
			// scan document for instances of sv:product-button
			var tags = document.getElementsByTagName( 'sv:product-button' );
			for(var i=0; i<tags.length; i++){
				this.product_buttons[i] = new product_button(tags[i], i);
			}
			// delete placeholders (must be done after loop, otherwise count is off)
			for(var i=0; i<tags.length; i++){
				tags[i].parentNode.removeChild(tags[i]);
			}
		
		}
	};
	
	//We are initializing manually in application.js
	/*
addEvent( window, 'load', function() {
		svpply_api.construct();
	} );
*/

}

