/**
 *    Copyright (c) 2009-2010, As Is Software, dba Media Lab Inc.
 *    http://www.medialab.com
 */
/*
 * 
 *  Initialization process:
 *  	Init all docent stuff
 *  	As necessry, based on xml:
 *  		New picturebox
 *  		New exhibit sheet
 *  		New view sheet
 *  		New panel sheet
 *  		New bigbox
 *  
 *  	Each picbox and sheet will initially select the current 
 *  	view/exb as passed in.  That way only the jscript for that
 *  	component needs to know about its possibly asynchronous
 *  	initialization requirements.
 *  
 */
var com;
if(!com) { com = {}; } else if(typeof(com) != "object") { throw new Error("can't initialize...com is not an object."); }
if(!com.medialab) { com.medialab = {}; } else if(typeof(com.medialab) != "object") { throw new Error("can't initialize...com.medialab is not an object."); }
if(!com.medialab.sg) { com.medialab.sg = {}; }
if (!com.medialab.sg.gallery1) { com.medialab.sg.gallery1 = {};}


com.medialab.sg.gallery1.docent =
function (xmlPathIn, myNameIn) { 
	if (typeof($ml)=='undefined') { $ml = $; }
	var that=this;
	var myName = myNameIn ? myNameIn : "docent";
	var curExhibit = 0; 
	var prevExhibit = -1;
	var exhibitChange = true;
	var curView = 0;
	var prevView = -1;
	var exhibitCount = 0;
	var thumbsheetCount = 0;
	var galleryXMLpath = xmlPathIn;
	var thumbsheet = null;
	var viewsheet = null;
	var viewsheetOptions = null;
	var exhibitsheetOptions = null;
	var pictureboxOptions = null;
	var bigboxOptions = null;
	var panelOptions = null;
	var bigBox = null;
	var picturebox = null;
	var panel = null;
	var xml = null;
	var thumbsheetDirty = false;
	var viewsheetDirty = false;
	var pictureboxDirty = false;
	var urlViewParamName = "view";
	var urlExhibitParamName = "exb";
	var preload = false;  // preload or not
	var preloads = [];  // array of images to preload
	var preloadMax = 50;
	
	var metaHrefs = null;
	var metaChunks = null;
	var metaDelimOpen = "[[";
	var metaDelimClose = "]]";
	var formMetaData = null;
	
	var useConsole = false;
	var debug = false;
	
 	this.sgalert = function(msg) { if (debug) {	alert(msg);	} };
	function sgalert(msg) { that.sgalert(msg); 	}
	
	this.getCurrentExhibit = function () { return curExhibit; }
	this.getCurrentView = function () { return curView; }
	
	this.getExhibitCount = function () { return exhibitCount; }
	
	this.getName = function () { return myName; }
	
	this.getxml = function() {
		return xml;
	}
	
	this.selectThumb = function (thumbnum, mode, updateThumbsheet) {
		//alert('hi');
		//this.sgalert("Selected thumb (v1)" + thumbnum);
		this.sgconsole("selectthumb. mode: " + mode + " thumbnum: " + thumbnum + ' curexhibit ' + curExhibit);
		if (mode == "exhibit") {
			if (thumbnum != curExhibit) {
				exhibitChange = true;
				prevExhibit = curExhibit;
				curExhibit = thumbnum;
				curView=0;
				prevView=0;
				thumbsheetDirty = updateThumbsheet;
				viewsheetDirty = true;
				pictureboxDirty=true;
				this.sgconsole("About to sync");
				this.sync();
			} else {
				if(panel && panel.goToPanel) {
					panel.goToPanel(thumbnum);
				}
			}
		}
		else {
			if (thumbnum != curView) {
				exhibitChange = false;
				viewsheetDirty=updateThumbsheet;
				pictureboxDirty=true;
				prevView = curView;
				curView = thumbnum;
				this.sync();
			}
		}
//		if(this.getThumbSheetOption(mode,'selectionaction')=='bigbox') {
//			this.openBigbox();
//		}
		return false;
	}
	
//	this.sgalert = function(msg) {	alert("sgalert public"); alert(msg);  	}
	
	this.init = function() {
		var urlExbNum = this.getUrlParam(urlExhibitParamName);
		var urlViewNum = this.getUrlParam(urlViewParamName);
		if(urlExbNum) {
			curExhibit = urlExbNum;
			if(urlViewNum) {
				curView = urlViewNum;
			}
		}

		if(!checkEnvironment()) {
			alert("SiteGrinder gallery missing components!");
			return;
		};
		
		if (!loadGalleryXML()) {
			alert("SiteGrinder gallery can't find XML file!");
			return;
		}
	}
	
	function sync() { that.sgconsole('wrong sync called'); that.sync();}
	
	function checkEnvironment () {
		sgalert("DOCENT: checkEnvironment()");
		// check for any required libs, like jquery
		if (!$ml) { return false; }
		return true;
	}
	

	this.getThumbsheetOption = function (sheetType,optionIn) { // these are dopplegangered just to avoid constant camelcaps typo bugs
		return this.getThumbSheetOption(sheetType,optionIn);
	}
	
	this.getThumbSheetOption = function (sheetType,optionIn) {
		var options = null;
		if(sheetType == "view") { options = viewsheetOptions; }
		else { options = exhibitsheetOptions; }
		return this.getAnOption(options,optionIn);
	}
	
	this.getPictureboxOption = function (optionIn) { 
		return this.getPictureBoxOption(optionIn);
	}
	
	this.getPictureBoxOption = function (optionIn) {
		return this.getAnOption(pictureboxOptions,optionIn);
	}
	
	this.getBigboxOption = function (optionIn) {
		return this.getBigBoxOption(optionIn);
	}
	
	this.getPanelOption = function (modeIn, optionIn) {
		return this.getAnOption(panelOptions,optionIn);
	}
	
	this.getBigboxOption = function (optionIn) {
		return this.getBigBoxOption(optionIn);
	}
	this.getBigBoxOption = function (optionIn) {
		return this.getAnOption(bigboxOptions,optionIn);
	}
	
	this.getAnOption = function (options,option) {
		var type = $ml('option[varname='+option+']', options).attr("type");
		var valMix = $ml('option[varname='+option+']', options).attr("value");
		if (typeof valMix == 'undefined') {
			this.sgconsole('Docent asked for a non existent option: ' + option);
			return "";
		}
	    var valLower = valMix.toLowerCase();
		if (type == 'undefined') {
			this.sgconsole('option type not found in options for option ' + option);
			if (isNaN(valLower)) {
				if (valLower == "true") {
					return true;
				}
				else 
					if (valLower == "false") {
						return false;
					}
					else {
						return valMix;
					}
			}
			else {
				if (valLower.substring(0, 2) == '0x') {
					return valLower;
				} // color
				else {
					return parseFloat(valMix);
				}
			}
		}
		else {
			var typeLower =type.toLowerCase();
			switch (typeLower) {
				case 'boolean' :
					return (valLower == 'true');
					break; 
				case 'number' :
					return parseFloat(valLower);
					break;
				case 'color':
				default:
				    return valMix;
					break;
			}
		}		
	}
	
	this.getCSSFormattedColor = function(col)  {
		if(col.substring(0,1) == '#') { return col; }
		else if (col.substring(0,2) == '0x') { return '#' + col.substring(2,col.length); }
		else { return '#' + col; }
	}
	
	this.getFlashMovie = function(movieName) {
	  // IE and Netscape refer to the movie object differently.
	  // This function returns the appropriate syntax depending on the browser.
	  this.sgconsole("finding movie " + movieName);
	  if (navigator.appName.indexOf ("Microsoft") !=-1) {
	    return window[movieName];
	  } else {
	    return document[movieName];
	  }
	}	
				
	this.flashMovieIsLoaded = function(theMovie) {
	  // First make sure the movie's defined.
	  if (typeof(theMovie) != "undefined") {
	  	this.sgconsole("movie " + theMovie);
	    // If it is, check how much of it is loaded.
	    return theMovie.PercentLoaded() == 100;
	  } else {
	  	  this.sgconsole("movie undefined");
	    // If the movie isn't defined, it's not loaded.
	    return false;
	  }
	}
	
	
	this.processXML = function (fullGalleryXMLIn){
		// **  Called when ajax has successfully loaded our XML  **
		that.sgconsole("about to process xml");
		xml=$ml(fullGalleryXMLIn);
		that.sgconsole("Docent: processXML (xml loaded)");
		that.postXMLInit();
	}
	
	//
	// setUpPreloads()
	//
	function setUpPreloads(){
		if (preload) {
			if (picturebox) { // current picturebox
				var qString = 'exhibits exhibit:eq(' + curExhibit + ') view:eq('+curView+') picturebox url';
				var result = $ml(qString, xml).get();
				if (result) { preloads = preloads.concat(result);	}
			}
			if (thumbsheet) { // current thumbnail
				var qString = 'exhibits exhibit:eq(' + curExhibit + ') view thumbnail url';
				var result = $ml(qString, xml).get();
				if (result) { preloads = preloads.concat(result);	}
			}
			if (viewsheet) { // add current view thumbnails first
				qString = 'exhibits exhibit:eq(' + curExhibit + ') view viewthumb url';
				var result = $ml(qString, xml).get();
				if (result) { preloads = preloads.concat(result);	}
			}
			if(thumbsheet){  // now load all the exhibit thumbs
				for (var curEx = 0; curEx < exhibitCount; curEx++) {
					qString = 'exhibits exhibit:eq('+ curEx +') view:eq(0) thumbnail url';
					var result = $ml(qString, xml).get();
					if (result) { preloads = preloads.concat(result);	}
				}
			}
			for (curEx = 0; curEx < exhibitCount; curEx++) {
				if (curEx != curExhibit) {  // now add the main pictureboxes and viewthumbs in order from zero
					if (picturebox) {
						qString = 'exhibits exhibit:eq('+curEx+') view:eq(0) picturebox url';
						var result = $ml(qString, xml).get();
						if (result) { preloads = preloads.concat(result);	}
					}
					if(viewsheet) {
						qString = 'exhibits exhibit:eq('+curEx+') view viewthumb url';
						var result = $ml(qString, xml).get();
						if (result) { preloads = preloads.concat(result);	}
					}
				}
			}
			that.sgconsole('preload list has ' + preloads.length + 'items');
			if(preloads.length > preloadMax) { preloads.length = preloadMax; }
			preloadNext();
		}
	}
	
	
	preloadErr = function() {
		this.sgconsole('PRELOADING err ' + this.src);
		preloadNext();
	}
	

	function preloadNext(){
		if(preloads.length > 0) {
			var curSrc = $ml.trim($ml(preloads.shift()).text());
			that.sgconsole('PRELOADING next picturebox image '+ curSrc +'('+ preloads.length +' left)');
			var img = new Image();
			img.onerror = preloadErr;
			img.onload = preloadNext;
			img.src = curSrc;
		}
	}
	
	this.postXMLInit = function() {
		// **  Called to init whatever is necessary after XML loaded
		// the options are stored as an optimization so the whole tree isn't parsed each time an option is looked for
		this.sgconsole("Docent: postXMLInit");
		
		this.sgconsole("About to update metadata");
		this.updateMetadata();
		
		this.sgconsole("binding preloader");
		//$ml(window).bind('load', pictureboxPreload);
		
		exhibitCount = $ml('exhibit',xml).length;
		var thumbsheetCount = $ml('thumbsheet',xml).length;
		$ml('options thumbsheet',xml).each(function(n){
			//console.log("docent making thumbsheet");
			var sheetConstructor = $ml('option[varname="constructor"]',this).attr("value");
			if(!sheetConstructor) { sgalert('No thumbsheet contructor provided in xml!') };
			if (!com.medialab.sg.gallery1[sheetConstructor]) {sgalert('Thumbsheet constructor "' + sheetConstructor + '" not available!')};
			var sheetmode = $ml('option[varname="mode"]',this).attr("value");
			that.sgconsole("Found a "+ sheetmode +" sheet with constructor " + sheetConstructor);
			if(sheetmode == 'exhibit') {
				exhibitsheetOptions = this;
				thumbsheet = new com.medialab.sg.gallery1[sheetConstructor](xml,sheetmode,that);
				//thumbsheet = new window[sheetConstructor](xml,sheetmode,that);
			} 
			else {
				viewsheetOptions = this;
				viewsheet = new com.medialab.sg.gallery1[sheetConstructor](xml,sheetmode,that);
	//				viewsheet = new window[sheetConstructor](xml,sheetmode,that);
			}
		});
		var pictureboxCount = $ml('options picturebox',xml).length;
		if (pictureboxCount > 0) {
			var pboxConstructor = $ml('options picturebox option[varname="constructor"]',xml).attr("value");
			that.sgconsole("Found a picturebox with constructor " + pboxConstructor);
			if(!pboxConstructor) { sgalert('No picturebox contructor provided in xml!') };
			if (!window[pboxConstructor]) {sgalert('Picturebox constructor "' + pboxConstructor + '" not available!')};
			pictureboxOptions = $ml('options picturebox',xml);
			picturebox = new com.medialab.sg.gallery1[pboxConstructor](xml, this);
		}
		
	
	
		var bigboxCount = $ml('options bigbox',xml).length;
		if (bigboxCount > 0) {
			var bboxConstructor = $ml('options bigbox option[varname="constructor"]',xml).attr("value");
			that.sgconsole("Found a bigbox with constructor " + bboxConstructor);
			if(!bboxConstructor) { sgalert('No bigbox contructor provided in xml!') };
			if (!window[pboxConstructor]) {sgalert('Bigbox constructor "' + bboxConstructor + '" not available!')};
			bigboxOptions = $ml('options bigbox',xml);
			this.sgconsole("Found a BIGBOX: " + bboxConstructor);
			bigBox = new com.medialab.sg.gallery1[bboxConstructor](xml, this);
		}
	
		var panelCount = $ml('options panel',xml).length;
		if (panelCount > 0) {
			var panelMode = $ml('options panel option[varname="mode"]',this).attr("value");
			if(typeof(panelMode) == 'undefined') { panelMode = 'exhibit'; }
			var panelConstructor = $ml('options panel option[varname="constructor"]',xml).attr("value");
			that.sgconsole("Found a panel with constructor " + panelConstructor);
			if(!panelConstructor) { sgalert('No panel contructor provided in xml!') };
			if (!window[panelConstructor]) {sgalert('panel constructor "' + panelConstructor + '" not available!')};
			panelOptions = $ml('options panel',xml);
			this.sgconsole("Found a panel!!");
			panel = new com.medialab.sg.gallery1[panelConstructor](xml, panelMode, this);
		}
		
		setUpPreloads();

	
		//this.sync(); 
	}

	this.openBigbox = function(mode) {
		if(!mode) { 
			if(!viewsheet || curView == 0)  {mode='exhibit'; }
			else { mode='view';}
		}
		this.sgconsole('js docent opening '+ mode +' mode bigbox with exhibit ' + curExhibit + ', view ' + curView);
		bigBox.openByView(mode, curExhibit, curView);
	}
	
	
	this.num2url = function (exhibitNum, viewNum){
		return $ml('exhibits exhibit:eq('+ exhibitNum +') views view:eq('+ viewNum +') picturebox url',xml).text();
	}	
	
	this.updateMetadata = function () {
		this.sgconsole('NOW IN updateMetadata - ' + $ml($ml('form[class*="'+that.getName()+'"] input[value*="[["]')[0]).attr('value'));
		
		// Create an array to preserve the original metadata hrefs along with their nodes for later replacement
		if(metaHrefs == null) {
			metaHrefs = new Array();
			$ml('a[class*=' + that.getName() + ']').each(function (n) {
				var origHref = $ml(this).attr('href');
				var node = this;
				metaHrefs[n] = { origHref: origHref, node:node };
			});
		}
		
		// Create array to collect metadata nodes in forms along with their metadata terms
		if(formMetaData==null) {
			formMetaData = new Array();
			var searchStr = 'form[class*="'+ that.getName() +'"] input[value*="[["]';
			//this.sgconsole('looking for form nodes with ' + searchStr);
			$ml(searchStr).each(function() { 
				var mdWithDelims = $ml(this).attr('value');
				var mdataName = mdWithDelims.substring(2, mdWithDelims.length-2);
				//that.sgconsole('adding form metadata node: ' + mdataName);
				formMetaData.push({node:this, meta:mdataName}); 
			});
		}
		
		//  first do spans that aren't in panels  
		// (panels are done all at once when they are created)
		$ml('exhibit:eq('+ curExhibit +') view:eq(0) metadata',xml).each(function (n) {
			var metadataName = $ml(this).attr('name');
			var mdContent = $ml.trim($ml(this).text());
			var targetClass = '"' + that.getName() + ' ' + metadataName + '"';  // should be ie 'docent1 description'
			// The two class= below were class*= but were getting false positive between "description" and "description writer"
			if($ml('span.[class="'+targetClass+'"]:not(div[id*=panelsheet] span)').length > 0) {
				$ml('span.[class="'+targetClass+'"]:not(div[id*=panelsheet] span)').html(mdContent);
			}
		});
		
		// Now do hrefs
		// as in 
		// $ml('a[class*=docentname]').attr('href', $ml('a').attr('href').replace('45.00','555.00'))
		for(var curHref = 0; curHref < metaHrefs.length; curHref++) {
			var newHref = metaHrefs[curHref].origHref;
			$ml('exhibit:eq('+ curExhibit +') view:eq(0) metadata',xml).each(function (n) {
				var mdContent = $ml.trim($ml(this).text());
				var metadataChunk = '[[' + $ml(this).attr('name') + ']]';
				newHref = newHref.replace(metadataChunk, escape(mdContent));
			});
			//newHref = escape(newHref);
			//console.log("New href with metadata : " + newHref);
			$ml(metaHrefs[curHref].node).attr('href',newHref);
		}
		
		// now do forms, as in
		//
		// <form class="main foxycart">
		//  <input type="hidden" name="price" value="[[price]]" />	
		for (var curFormFieldNum = 0; curFormFieldNum < formMetaData.length; curFormFieldNum++) {
			var mdContent = $ml.trim($ml('exhibit:eq('+ curExhibit +') view:eq(0) metadata[name="'+ formMetaData[curFormFieldNum].meta +'"]', xml).text());
			//that.sgconsole('replacing form content for: ' + mdContent);
			$ml(formMetaData[curFormFieldNum].node).attr('value',mdContent);
		}
		
		//update foxycart
		if (typeof(fc_CookieFix) == "function") { 
			fc_CookieFix();
		}
		
	}
	
	
	 this.sync = function () {
		this.sgconsole('in sync picturebox ' + picturebox + ' dirty ' + pictureboxDirty);
		if (thumbsheet  && thumbsheetDirty) {
			this.sgconsole('sync thumbsheet');
			thumbsheet.select(curExhibit);
			thumbsheetDirty = false;
		}
		
		if (viewsheet && viewsheetDirty) {
			this.sgconsole('sync viewsheet');
			if (exhibitChange) {
				this.sgconsole('exhibitChange, resetting curView to 0');
				curView = 0;
				viewsheet.updateSheet();
			}
			else {
				viewsheet.select(curView);
			}
			viewsheetDirty = false;

		}
		if (panel && panel.goToPanel) {
			this.sgconsole('sync panelsheet');
			panel.goToPanel(curExhibit);
			//panelsheetDirty = false;		
		}
		this.sgconsole("*Syncing: " + curExhibit + "," + curView);
		this.updateMetadata();
		if (picturebox && pictureboxDirty) {
			this.sgconsole('docent calling picturebox.displaybynum with ' + curExhibit);
			picturebox.displayByNum(curExhibit, curView);
		}
	}  
	
	this.hasViewSheet = function() {
		if(viewsheet) { return true; }
		return false;
	}
	
/* Currently unused	*/
	this.pictureboxReady = function() {
		//picturebox.displayByNum(curExhibit,curView);
	}
	
	this.thumbSheetReady = function() {
		
	}
	function errorXML(xhr,errStr,exceptionObj) {
		sgalert("SiteGrinder's Gallery data could not be loaded.  Error: " + errStr);
		//document.write("DOCENT XML READING ERROR: " + errStr + ".  Please report this to <a href='mailto:help@medialab.com'>help@medialab.com</a>");
	}
	
	function initJQUERYAccessors () {
		this.altThumbQuery = "exhibits > exhibit > views > view > thumbnail > src";
		this.altPictureboxQuery = "exhibits > exhibit > views > view > picturebox > src";
	}
		
	
	function setUpGalleryParts () {
		this.thumbsheet = new com.medialab.sg.gallery1.thumbsheet(this.thumbsheetXML);
	}
	
	function loadGalleryXML () {
		sgalert("DOCENT: loadGalleryXML: " + galleryXMLpath);
		//var ff = this.processXML;
		// load up the xml file into an xml parseable something or other
		$ml.ajax({
			type: "GET",
			url: galleryXMLpath,
			dataType: "xml",
			//dataType: "html",
			success: that.processXML,
			error: errorXML
		});
		return(true);
	}

(function( $ ){
  $.cssRule = function (Selector, Property, Value) {
    // Selector == {}
    if(typeof Selector == "object"){
      $.each(Selector, function(NewSelector, NewProperty){
        $.cssRule(NewSelector, NewProperty);
      });
      return;
    }

    // Selector == "body:background:#F99"
    if((typeof Selector == "string") && (Selector.indexOf(":") > -1)
      && (Property == undefined) && (Value == undefined)){
      Data = Selector.split("{");
      Data[1] = Data[1].replace(/\}/, "");
      $.cssRule($.trim(Data[0]), $.trim(Data[1]));
      return;
    }

    // Check for multi-selector, [ IE don't accept multi-selector on this way, we need to split ]
    if((typeof Selector == "string") && (Selector.indexOf(",") > -1)){
      Multi = Selector.split(",");
      for(x = 0; x < Multi.length; x++){
        Multi[x] = $.trim(Multi[x]);
        if(Multi[x] != "")
          $.cssRule(Multi[x], Property, Value);
      }

      return;
    }

    // Porperty == {} or []
    if(typeof Property == "object"){

      // Is {}
      if(Property.length == undefined){

        // Selector, {}
        $.each(Property, function(NewProperty, NewValue){
          $.cssRule(Selector + " " + NewProperty, NewValue);
        });

      // Is [Prop, Value]
      }else if((Property.length == 2) && (typeof Property[0] == "string") &&
        (typeof Property[1] == "string")){
        $.cssRule(Selector, Property[0], Property[1]);

      // Is array of settings
      }else{
        for(x1 = 0; x1 < Property.length; x1++){
          $.cssRule(Selector, Property[x1], Value);
        }
      }

      return;
    }

    // Parse for property at CSS Style "{property:value}"
    if((typeof Property == "string") && (Property.indexOf("{") > -1)
       && (Property.indexOf("}") > -1)){
      Property = Property.replace(/\{/, "").replace(/\}/, "");
    }

    // Check for multiple properties
    if((typeof Property == "string") && (Property.indexOf(";") > -1)){
      Multi1 = Property.split(";");
      for(x2 = 0; x2 < Multi1.length; x2++){
        $.cssRule(Selector, Multi1[x2], undefined);
      }
      return;
    }

    // Check for property:value
    if((typeof Property == "string") && (Property.indexOf(":") > -1)){
      Multi3 = Property.split(":");
      $.cssRule(Selector, Multi3[0], Multi3[1]);
      return;
    }

    //********************************************
    // Logical CssRule additions
    // Check for multiple logical properties [ "padding,margin,border:0px" ]
    if((typeof Property == "string") && (Property.indexOf(",") > -1)){
      Multi2 = Property.split(",");
      for(x3 = 0; x3 < Multi2.length; x3++){
        $.cssRule(Selector, Multi2[x3], Value);
      }
      return;
    }

    //********************************************
    // Check for Most One Style Sheet
    // jQuery.CssRule need at last one Style Sheet enabled on the page.
    styleSheetsLength = document.styleSheets.length;
    if(styleSheetsLength <= 1){
      // Append for no IE browsers
      if(!document.createStyleSheet){
        var styleSheet = (typeof document.createElementNS != undefined) ?
          document.createElementNS("http://www.w3.org/1999/xhtml", "style") :
          document.createElement("style");
        styleSheet.setAttribute("type", "text/css");
        styleSheet.setAttribute("media", "screen");
        if(styleSheetsLength == 0){
          $($("html")[0]).prepend(styleSheet);
        }
      // Append for IE
      }else{
        BaseStyle = document.getElementsByTagName("style");
        if(BaseStyle.length > 0)
          document.getElementsByTagName("style")[0].disabled = false;
        var styleSheet = document.createElement("style");
        styleSheet.setAttribute("type", "text/css");
        styleSheet.setAttribute("media", "screen");
        styleSheet.disabled = false;
        $($("html")[0]).prepend(styleSheet);
      }
    }

    if((Property == undefined) || (Value == undefined))
      return;

    Selector = $.trim(Selector);
    Property = $.trim(Property);
    Value = $.trim(Value);

    if((Property == "") || (Value == ""))
      return;

    // adjusts on property 
    if($.browser.msie){
      // for IE (@.@)^^^
      switch(Property){
        case "float": Property = "style-float"; break;
      }
    }else{
      // CSS rights
      switch(Property){
        case "float": Property = "css-float"; break;
      }
    }

    CssProperty = (Property || "").replace(/\-(\w)/g, function(m, c){ return (c.toUpperCase()); });

    for(var i = 0; i < document.styleSheets.length; i++){
	  CurrentStyleSheet = document.styleSheets[i];
	  if (typeof(CurrentStyleSheet) != 'undefined' && CurrentStyleSheet != null && typeof(CurrentStyleSheet.href) == 'string' 
	      && CurrentStyleSheet.href.indexOf('foxycart') < 0) 
	  {
  		//console.log('checking ' + CurrentStyleSheet.href);
		try {
			if (typeof(CurrentStyleSheet['cssRules']) != 'undefined') {
				Rules = CurrentStyleSheet['cssRules'];
			}
			if (typeof(CurrentStyleSheet['rules']) != 'undefined') {
				Rules = CurrentStyleSheet['rules'];
			}
		}
		catch(ex) {
			continue;
		}
		//Rules = (CurrentStyleSheet.cssRules || CurrentStyleSheet.rules);
		LowerSelector = Selector.toLowerCase();
		
			for (var i2 = 0, len = Rules.length; i2 < len; i2++) 
			{
				if (Rules[i2].selectorText && (Rules[i2].selectorText.toLowerCase() == LowerSelector)) {
					if (Value != null) {
						Rules[i2].style[CssProperty] = Value;
						return;
					}
					else {
						if (CurrentStyleSheet.deleteRule) {
							CurrentStyleSheet.deleteRule(i2);
						}
						else 
							if (CurrentStyleSheet.removeRule) {
								CurrentStyleSheet.removeRule(i2);
							}
							else {
								Rules[i2].style.cssText = "";
							}
					}
				}
			}
		}
		else {
			//console.log('encountered null stylesheet in cssRule()');
		}
    }

    if(Property && Value){
      for(var i = 0; i < document.styleSheets.length; i++){
	    WorkerStyleSheet = document.styleSheets[i];
	    if(typeof(WorkerStyleSheet) != 'undefined' && WorkerStyleSheet != null && typeof(WorkerStyleSheet.href) == 'string' && WorkerStyleSheet.href.indexOf('foxycart') < 0) {
	        if(WorkerStyleSheet.insertRule){
			  try {
			  	if (typeof(WorkerStyleSheet['cssRules']) != 'undefined') {
			  		Rules = WorkerStyleSheet['cssRules'];
			  	}
			  	if (typeof(WorkerStyleSheet['rules']) != 'undefined') {
			  		Rules = WorkerStyleSheet['rules'];
			  	}
			  }
			  catch(ex) {
			  	continue;
			  }
	          //Rules = (WorkerStyleSheet.cssRules || WorkerStyleSheet.rules);
	          WorkerStyleSheet.insertRule(Selector + "{ " + Property + ":" + Value + "; }", Rules.length);
	        }else if(WorkerStyleSheet.addRule){
	          WorkerStyleSheet.addRule(Selector, Property + ":" + Value + ";", 0);
	        }else{
	          throw new Error("Add/insert not enabled.");
	        }
		}
		else { }
      }
    }
  };
  
  $.tocssRule = function(cssText){
    matchRes = cssText.match(/(.*?)\{(.*?)\}/);
    while(matchRes){
      cssText = cssText.replace(/(.*?)\{(.*?)\}/, "");
      $.cssRule(matchRes[1], matchRes[2]);
      matchRes = cssText.match(/(.*?)\{(.*?)\}/);
    }
  }
})( $ml );

(function( $ ){
           $.fn.toXML = function(){
               var toXML = function(node){
                    var out = '';
                    var attributes = '';
                    var content = '';
                    out += '<' + node.nodeName;
                    if (node.childNodes) {
                        for (var i = 0; i < node.childNodes.length; i++) {
                            switch (node.childNodes[i].nodeType) {
                                case 1: // ELEMENT_NODE
                                    content += toXML(node.childNodes[i]);
                                    break;
                                case 2: // ATTRIBUTE_NODE
                                    attributes += ' ' + node.childNodes[i].nodeName + '="' +
                                    node.childNodes[i].nodeValue +
                                    '"';
                                    break;
                                case 3: // TEXT_NODE
                                case 4: // CDATA_SECTION_NODE
                                case 5: // ENTITY_REFERENCE_NODE
                                case 6: // ENTITY_NODE
                                case 7: // PROCESSING_INSTRUCTION_NODE
                                case 8: // COMMENT_NODE
                                case 9: // DOCUMENT_NODE
                                case 10: // DOCUMENT_TYPE_NODE
                                case 11: // DOCUMENT_FRAGMENT_NODE
                                case 12: // NOTATION_NODE
                                    content += node.childNodes[i].nodeValue;
                                    break;
                            }
                        }
                    }
                    out += attributes;
                    if (content.length > 0) {
                        out += '>' + content;
                        out += '<\/' + node.tagName + '>';
                    }
                    else {
                        out += '/>';
                    }
                    return out;
                }
                var out = '';
                if (this.length > 0) {
                    if (typeof XMLSerializer == 'function' ||
                    typeof XMLSerializer == 'object') {
                        var xs = new XMLSerializer();
                        this.each(function(){
                            out += xs.serializeToString(this);
                        });
                    }
                    else 
                        if (this[0].xml !== undefined) {
                            this.each(function(){
                                out += this.xml;
                            });
                        }
                        else {
                            if (this.length > 0) {
                                this.each(function(){
                                    out += toXML(this);
                                });
                            }
                        }
                } 
                return out;
            }; 
})( $ml );

	this.getUrlParam = function(param) {
	    var regex = '[?&]' + param + '=([^&#]*)';
	    var results = (new RegExp(regex)).exec(window.location.href);
	    if(results) return results[1];
	    return null;
	}
	
	this.sgconsole = function(text) {
		if(useConsole) {
			var msg = "DOCENT : " + text;
			if (window.console && console.log) {
				console.log(msg);
			}
			else 
				if (window.opera && opera.postError) {
					opera.postError(msg);
				}
		}
	}
	
	this.sendMessage = function(where,what) {
		switch (where) {
			case "thumbsheet":
				if(thumbsheet) { return thumbsheet.message(what); }
				else { this.agalert ("There's no thumbsheet to send the message " + what + " to") };
				break;
			case "viewsheet":
				if(viewsheet) { return viewsheet.message(what); }
				else { this.agalert ("There's no viewsheet to send the message " + what + " to") };
				break;
			case "picturebox":
				if(picturebox) { return picturebox.message(what); }
				else { this.agalert ("There's no picturebox to send the message " + what + " to") };
				break;
			case "bigbox":
				if (bigbox) { return bigbox.message(what);	}
				else { this.agalert ("There's no bigbox to send the message " + what + " to") };
				break;
			default:
				this.agalert("Can't send message '"+ what + "' because I don't recognize '"+ where + "' as a message target.");
				break;
		}
		return null;
	}
	
	this.getThumbImage = function(thumbNum, mode) {
		if(typeof mode =='undefined' || mode == 'exhibit') {
			return  $ml('exhibit:eq('+thumbNum+') > views > view:eq(0) > thumbnail > url', xml).text();
		} else {
			return $ml('exhibit:eq(' + curExhibit + ') view > viewthumb > url', xml).eq(thumbNum).text();
		}
	}
	
	this.iterateExhibitThumbImageUrls = function (iterator,data) {
		var iiterator = iterator;
		var idata = data;
		$ml('exhibit', xml).each(function(n){
			iiterator(n, idata, $ml('views > view > thumbnail > url', this).eq(0).text());
		});
	}
	

	// assumes current exhibit unless specified
	this.iterateViewThumbImageUrls = function(iterator, data, exhibitNumIn) {
		var iiterator = iterator;
		var idata = data;
	
		var curExhibit = exhibitNumIn ? exhibitNumIn : this.getCurrentExhibit();
		
//		if ($ml('exhibit:eq(' + curExhibit + ') view', xml).length > 1) {
			$ml('exhibit:eq(' + curExhibit + ') view', xml).each(function(n){
				iiterator(n, idata, $ml('viewthumb > url', this).eq(0).text());
			});
//		}
	}
	
	this.getNumViews = function(exNumIn) {
		var exNum = exNumIn ? exNumIn : curExhibit;
		var numViews = $ml('exhibit:eq(' + curExhibit + ') view', xml).length;
		this.sgconsole("num views for exhibit "+curExhibit+ " : " + numViews);
		return numViews;
	}
	
	this.pictureboxSelectByNum = function(imageNum, updatePbox) {
		this.sgconsole("Picturebox pictureboxSelectByNum exhibit: " + imageNum);
		if (typeof updatePbox == 'undefined') {
			pictureboxDirty = false;
		} else {
			pictureboxDirty = updatePbox;
		}
		if (imageNum != curExhibit) {
			this.sgconsole("image not current so about to sync");
			prevExhibit = curExhibit;
			curExhibit = imageNum;
			thumbsheetDirty=true;
			//thumbsheet.select(curExhibit);
			this.sync();
		}
	}
	
	this.sgconsole("docent initializing");
	this.init();
	
	
	// EVENTS:
	this.thumbHover = function (e) { }
	this.thumbClick = function (e) { } 
    this.alt_thumbHover = function (e) { }
    this.alt_thumbClick = function (e) { }
	
/* 
 * 
 *  Navigation functions:
 * 
 * 	next/previous
 *  nextview/previousview
 *  nextpanelset/previouspanelset
 *  nextthumbset/previousthumbset
 *  nextviewset/previousviewset
 *  
 */	

	// NEXT / PREVIOUS
	this.next = function() {  // advance to next exhibit
		this.nextClick(null);
	}
	this.prev = this.previous = function() {  // go to previous exhibit
		this.previousClick(null);
	}
	
	// NEXTVIEW/PREVIOUSVIEW
	this.nextView = function() {  // advance to next view
		if (curView < this.getNumViews()-1) {
			curView++; 
			pictureboxDirty = true;
			viewsheetDirty = true;
			thumbsheetDirty = false;
			exhibitChange = false;
			this.sync();
		}		
	}
	
	this.prevView = this.previousView = function() {  // go to previous view
		if (curView > 0) {
			curView--; 
			pictureboxDirty = true;
			viewsheetDirty = true;
			thumbsheetDirty = false;
			exhibitChange = false;
			this.sync();
		}				
	}
	
	// NEXTTHUMBSET/PREVIOUSTHUMBSET
	this.nextThumbSet = function() {  // advance to next view
		 this.sgconsole('next Thumb set ')
		 if (thumbsheet && thumbsheet.nextThumbSet) {
		 	thumbsheet.nextThumbSet();
		 }
	}
	
	this.prevThumbSet = this.previousThumbSet = function() {  // go to previous view
		 this.sgconsole('prev Thumb set ')
		 if (thumbsheet && thumbsheet.previousThumbSet) {
		 	thumbsheet.previousThumbSet();
		 }
	}
	
	// NEXTVIEWSET/PREVIOUSVIEWSET   --   ARE THESE SUPPORTED YET?
	this.nextViewSet = function() {  // advance to next view
		 this.sgconsole('next View set ')
		 if (viewsheet && viewsheet.nextThumbSet) {
		 	viewsheet.nextThumbSet();
		 }
	}
	
	this.prevViewSet = this.previousViewSet = function() {  // go to previous view
		 this.sgconsole('prev View set ')
		 if (viewsheet && viewsheet.previousThumbSet) {
		 	viewsheet.previousThumbSet();
		 }
	}
		
	// NEXTPANEL/PREVIOUSPANEL
	this.nextPanel = function () {
		 this.sgconsole('next panel set ' + panel)
		 if (panel && panel.nextPanel) {
		 	panel.nextPanel();
		 }
	}
	
	this.prevPanel = this.previousPanel = function () {
		 this.sgconsole('prev panel set ' + panel)
		 if (panel && panel.previousPanel) {
		 	panel.previousPanel();
		 }
	}
	
	// NEXTPANELSET/PREVIOUSPANELSET
	this.nextPanelSet = function () {
		 this.sgconsole('next panel set ' + panel)
		 if (panel && panel.nextPanelSet) {
		 	panel.nextPanelSet();
		 }
	}
	
	this.prevPanelSet = this.previousPanelSet = function () {
		 this.sgconsole('prev panel set ' + panel)
		 if (panel && panel.previousPanelSet) {
		 	panel.previousPanelSet();
		 }
	}
	
	
	
    this.pictureboxNextClick = function (updatePbox,e) { 
		this.sgconsole("Picturebox Next click received.");
		if (curExhibit < exhibitCount-1) {
			curExhibit++; 
			if (updatePbox) {
				pictureboxDirty = true;
			} else {
				pictureboxDirty = false;
			}
			thumbsheetDirty = true;
			viewsheetDirty = true;
			exhibitChange = true;
			this.sync();
		}
	}
	
   this.pictureboxPreviousClick = function (updatePbox, e) {
		if (curExhibit > 0) {
			curExhibit--; 
			thumbsheetDirty = true;
			viewsheetDirty = true;
			if (updatePbox) {
				pictureboxDirty = true;
			} else {
				pictureboxDirty = false;
			}
			exhibitChange = true;
			this.sync();
		}
	}
	
    this.toCSSColor = function(hexColor) {
		if (hexColor != undefined) {
			if(typeof(hexColor)=='number') { return '#' + hexColor;}
			if (hexColor.substring(0, 1) == '#') {
				return hexColor;
			} // already css style for some reason
			else 
				if (hexColor.substring(0, 2) == '0x') {
					return '#' + hexColor.substring(2);
				}
				else 
					if (!isNaN('0x' + hexColor)) {
						return '#' + hexColor;
					}
		}
		return null;
	}
	
    this.thumbNextClick = function (mode,e) { 
		this.sgconsole("thumb Next click received. mode:" + mode);
		if (curExhibit < exhibitCount-1) {
			curExhibit++; 
			if(mode=='view') { thumbsheetDirty = false; /*viewsheetDirty=false;*/exhibitChange = false;} else {thumbsheetDirty = true; /*viewsheetDirty=true;*/exhibitChange = true;}
			viewsheetDirty = true;
			pictureboxDirty=true;
			this.sync();
		}
	}
	
   this.thumbPreviousClick = function (mode,e) {
		this.sgconsole("thumb prev click received. mode:" + mode);
		if (curExhibit > 0) {
			curExhibit--; 
			if(mode=='view') { thumbsheetDirty = false; /*viewsheetDirty=false;*/exhibitChange = false;} else {thumbsheetDirty = true; /*viewsheetDirty=true;*/exhibitChange = true;}
			viewsheetDirty = true;
			pictureboxDirty = true;
			this.sync();
		}
	}
  	// Next exhibit	
    this.nextClick = function (e) { 
		this.sgconsole("Next click received.");
		if (curExhibit < exhibitCount-1) {
			curExhibit++; 
			thumbsheetDirty = true;
			viewsheetDirty = true;
			pictureboxDirty = true;
			exhibitChange = true;
			this.sync();
		}
	}

    this.previousClick = function(e){
		if (curExhibit > 0) {
			curExhibit--;
			thumbsheetDirty = true;
			viewsheetDirty = true;
			pictureboxDirty = true;
			exhibitChange = true;
			this.sync();
		}
	}
			
    this.nextHover = function (e) { }
	this.previousHover = function (e) { }
    this.pictureboxHover = function (e) { }
	
	this.pictureboxIsFlashBased = function() {
		var flashBased = false;
		if (pictureboxOptions) {
			$ml('option', pictureboxOptions).each(function(n){
				var val  = String($ml(this).attr('value'));
				var lVal = val.toLowerCase();
				if(lVal.substring(lVal.length-4) == '.swf') { flashBased = true; }
			});
		}
		return flashBased;
	}
	
	this.gotoCustomUrl = function(exhibitNum, viewNum, windowName, props) {
		if(typeof(exhibitNum)=='undefined') { exhibitNum = curExhibit ; }
		if(typeof(viewNum)=='undefined') { viewNum = curView; }
		var url = $ml.trim($ml('exhibits exhibit:eq('+ exhibitNum  +') views view:eq('+ viewNum +') link',xml).text());
		this.gotoUrl(url, windowName, props);
	}
	
	this.gotoUrl = function(url, newWindowName, props) {
		if (typeof(url) != 'string') {
			return;
		}
		if(typeof(newWindowName)=='undefined') {
			location=url;
		}
		else {
			window.open(url,newWindowName,props);
		}
	}
	
	this.getJSON = function(url, callback){
//		this.getYQL('select * from rss where url="' + url + '"', callback);
		this.getYQL('select * from feed where url="' + url + '"', callback);
	}
	
	this.getYQL = function(yqlQuery, callback) {
 		var eQuery = escape(yqlQuery);
		eQuery = eQuery.replace(/\//g,'%2F');
		var finalQuery = 'http://query.yahooapis.com/v1/public/yql?q=' + eQuery + '&format=json&callback=?';
		$ml.getJSON(finalQuery,callback);
	}
	
	this.json2GalleryXML = function(jIn, labelsIn) {
		var labels = labelsIn;
		
		var myXML = "<exhibits>";
		$ml.each(data.query.results.item, function(index, item){
			myXML += '<exhibit><views><view><metadataentries>'
			for (var curLabelNum = 0; curLabelNum < labels.length; curLabelNum++) {
				var content = item[labels[curLabelNum]];
				//if (index == 0) {alert(item[labels[curLabelNum]]);}
				if (typeof(content) != 'undefined' && content != "") {
					myXML += '<metadata name="' + labels[curLabelNum] + '">';
					//alert( $ml('p',item.description).text());
					myXML += content;
					//alert(item.description);
					myXML += '</metadata></metadataentries>'
					myXML += '</view></views></exhibit>';
				}
			}
		});
		myXML += '</exhibits>';
		return myXML;
	}
	
	this.getClickUrl = function(mode) {
		if(typeof mode == 'undefined') { mode='exhibit'; }
		if(mode=='exhibit') {
			return $ml.trim($ml('exhibits exhibit:eq('+ curExhibit +') view:eq(0) link',xml).text());;
		}
		else if (mode=='view') { // are separate urls for views supported?
			return $ml.trim($ml('exhibits exhibit:eq('+ curExhibit +') view:eq('+ curView +') link',xml).text());;
		}
		else { return ""; }
	}
	
	this.pictureboxClick = function(updatePbox,clickAction) {
		
		// maybe some code here to assume updatePbox false if a flash pbox?
		if(typeof(updatePbox)=="undefined"  && this.pictureboxIsFlashBased()) { updatePbox=false; }
		
		if (!clickAction) {
			this.sgconsole("docent finding clickaction itself since picturebox did not supply it");
			clickAction = this.getPictureBoxOption('clickaction');
		}
		
		if (typeof(clickAction) == "string") {
			this.sgconsole("docent: picBoxClick: " + clickAction + " updatePbox: " + updatePbox);
			switch (clickAction.toLowerCase()) {
				case 'advance':
					this.pictureboxNextClick(updatePbox, null);
					break;
				case 'url':
					//var url = this.getPictureBoxOption('clickurl');  // Initially this was a DM option but now it's set in the CMS
					var url = this.getClickUrl();
					if(typeof url != 'string' || url=="") { return; }
					if (!this.getPictureBoxOption('newwindow')) {
						this.gotoUrl(url);
					}
					else {
						var newWindowName = this.getPictureBoxOption('newwindowname') || "Untitled";
						var props = "";
						var h = this.getPictureBoxOption('newwindowheight');
						if (h != "" && h != 0) {
							props += "height=" + h;
						}
						
						if (props.length > 0) {	props += ","; }
						var w = this.getPictureBoxOption('newwindowwidth');
						if (w != "" && w != 0) {
							props += "width=" + w;
						}
						
						if (props.length > 0) { props += ","; }
						if (w == "" || h == "" || w == 0 || h == 0) {
							props += "resizable=yes";
						}
						else {
							props += "resizable=no";
						};
						this.gotoUrl(url, newWindowName, props);
					}
					break;
				case 'bigbox':
					this.sgconsole("about to call openBigBox");
					this.openBigbox();
					break;
				default:
					this.sgconsole("unknown picturebox clickaction: " + clickAction);
					break;
			}
		}
		else {
			this.sgconsole("picturebox clicked, but clickaction is null or undefined ");
		}
	}
}

if(!com.medialab.parseUri) { com.medialab.parseUri = {}; }
com.medialab.parseUri.options = {
	strictMode: false,
	key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
	q:   {
		name:   "queryKey",
		parser: /(?:^|&)([^&=]*)=?([^&]*)/g
	},
	parser: {
		strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
		loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
	}
};
com.medialab.parseUri.parse = function(str) {
	var	o   = com.medialab.parseUri.options,
		m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
		uri = {},
		i   = 14;

	while (i--) uri[o.key[i]] = m[i] || "";

	uri[o.q.name] = {};
	uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
		if ($1) uri[o.q.name][$1] = $2;
	});

	return uri;
};

