function Project(projectData) {
//deserialize the data we get from the database for easier access
  this.id = projectData['Project']['id'];
  this.name = projectData['Project']['name'];
  this.description = projectData['Project']['description'];
  this.diy = projectData['Project']['diy'];
  this.url = projectData['Project']['url'];
  this.impacts = typeof projectData['Impacts'] != 'undefined' ? projectData['Impacts'] : new Array();
  //not all projects will have resources
  this.resources = typeof projectData['Resources'] != 'undefined' ? projectData['Resources'] : new Array();
  this.water = projectData['Project']['water'];
  this.energy = projectData['Project']['energy'];
  this.waste = projectData['Project']['waste'];
  this.co2 = projectData['Project']['co2'];
  this.completed = projectData['Project']['completed'];
  this.category_id = projectData['Project']['category_id'];
  this.category = projectData['Project']['category'];
  this.category_type = projectData['Project']['category_type'];
  this.lili = Math.round((this.impacts.LILI)*10)/10;
  
  //get the required projects, if any
  this.projectPrereqs = new Array();
  for (var i=0; i<projectData['ProjectPrereq'].length; i++) {
    this.projectPrereqs.push(projectData['ProjectPrereq'][i]['project_prereq_id']);
	updateDependecyList(this.id, projectData['ProjectPrereq'][i]['project_prereq_id']);
  }

  //get the mutually exclusive projects, if any
  this.projectMutuallyExclusives = new Array();
  for (var i=0; i<projectData['ProjectMutuallyExclusive'].length; i++) {
    this.projectMutuallyExclusives.push(projectData['ProjectMutuallyExclusive'][i]['dependent_project']);
//	updateDependecyList(this.id, projectData['ProjectPrereq'][i]['project_prereq_id']);
  }
  
  //get the required userdata inputs, if any
  this.userDataPrereqs = new Array();
  for (var i=0; i<projectData['ProjectUserdataPrereq'].length; i++) {
    var preReq = new Object();
    preReq.userDataKey = projectData['ProjectUserdataPrereq'][i]['userdata_prereq_key'];
    preReq.userDataValue = projectData['ProjectUserdataPrereq'][i]['userdata_prereq_value']
    this.userDataPrereqs.push(preReq);
  }
}; 
  
  
  Project.prototype.getCo2 = function(){
  	return this.impacts["CO2"];
  }
  
  Project.prototype.getEunits = function(){
  	return this.impacts["E_Units"];
  }
  
  
  /**
   * Checks all prerequisites (both other projects and user data entries) of this
   * project and returns true if they are all met, false otherwise.
   * @param {UserData} userData The object representing the answers the user has provided to survey questions
   * @param {Array} selectedProjects An array of projects the user has already selected
   * @return true if all prerequisites are met, false otherwise
   * @see UserData
   */
  Project.prototype.prereqsAreMet = function (userData, selectedProjects) {
    for (var i=0; i<this.projectPrereqs.length; i++) {
    //note the use of indexOf - we'll need Prototype for this to work in IE, I think
      if (selectedProjects.indexOf(this.projectPrereqs[i].id) == -1) return false;
    }
    for (var i=0; i<this.userDataPrereqs.length; i++) {
      var req = this.userDataPrereqs[i];
      if (userData.getValue(req.userDataKey) != req.userDataValue) return false;
    }
    return true;
  };
  
  /**
   * Simple test function to pretty-print the data in the project
   */
   Project.prototype.toHTMLNoah = function () {
     result = "<tr><td>" +
     this.id + "</td><td>" +
     this.name + "</td><td>";
	  result += "-1" + "</td><td>";
     if ("Cost" in this.impacts) { 
       result += this.impacts.Cost + "</td><td>"; 
     } else {
       result += "Cost goes here </td><td>";
     }
     if ("Savings" in this.impacts) { 
       result += this.impacts.Savings + "</td><td>"; 
     } else {
       result += "Savings goes here</td><td>";
     }
    
     result += this.water + "</td><td>" +
     this.co2 + "</td><td>" +
     this.waste + "</td><td>" +
     this.energy + "</td><td>" +
     this.renderResources() + "</td></tr>";
     return result;
   };
   
      
   /**
    * Called when setCompleted is called on any project.  
    * Counts lili values of projects marked as completed.
    */    
   Project.countCompletedProjectsLili = function(projectList) {
   	
		var lili_reduction = 0;
		var checkProjectCompletion = function(el, index) {
			if (el != undefined) {
				if (el.completed == true) {
					// Modified by JWP on 1-25-08 to calculate true LILI reduction
					// lili_reduction = lili_reduction + 1;
			        lili_reduction = lili_reduction + Math.round(el.impacts['LILI']);
				}		
			}	
		}
		projectList.each(checkProjectCompletion);
		return lili_reduction;
   };
   
   
         
   /**
    * Called when setCompleted is called on any project.  
    * Counts impacts of specified category on projects marked as completed.
    */    
   Project.countCompletedProjectsImpact = function(projectList, impact) {
   	
		var impact_subtotal = 0;
		var checkProjectImpact = function(el, index) {
			if (el != undefined) {
				if (el.completed == true) {
					if (el.impacts[impact] != undefined) {
						impact_subtotal = impact_subtotal + el.impacts[impact];
					}
				}
			}	
		}
		projectList.each(checkProjectImpact);
		return impact_subtotal;
   };
   
   
   /**
    * Another test function; given an element and a list of projects
    * prints all of the projects into the doc after the element.
    * (The element is probably a table header row.)
    */    
   Project.renderProjects = function(element, projectList) {
   	
		var renderProject = function(el, index) {
			if (el != undefined) {
				element.appendChild( el.toHTML() );
			}
		}
		projectList.each(renderProject);
		
		var len = (dependencies.length/2)
	    for (var i=0; i<len; i++) {
			new Insertion.After($('p'+dependencies[i][0]), $('p'+dependencies[i][1]));
	    }
	   
   };
   
   
   /**
    * moves project elements into new order
    */    
   Project.moveProjects = function(element, projectList) {
   		// get first element from current list
		var lastEl = element.childNodes[0];
		//iterate through new list, and move each element after a preceeding element.
		var moveProjects = function(obj, index) {
			if (obj != undefined) {
				var el = $('p' + obj['id']);
				if (index == 0) {
					if (el != lastEl) {
						new Insertion.Before(lastEl, el);
					}
				}
				else {
					if (el != lastEl) {
						new Insertion.After(lastEl, el);
					}
					
				}
				lastEl = el;
			}
		}
		projectList.each(moveProjects);
		
		var len = (dependencies.length/2)
	    for (var i=0; i<len; i++) {
			new Insertion.After($('p'+dependencies[i][0]), $('p'+dependencies[i][1]));
	    }
		
   };
   
    var lastSortOrder = "";
    Project.reorderProjects = function(element, projectList, orderBy, reverse){
	
		var sortedProjectList = projectList.sortBy(function(project) {
			if (project != undefined) {
				if (orderBy == 'cost') {
					return parseInt(project.impacts.Cost);
				} else if (orderBy == 'save') {
						return parseInt(project.impacts.Savings);
				}else if (orderBy == 'lili') {
						return project.lili;
						
				} else {
						return project[orderBy];
				}
			}
		});
	
		if (reverse == true) {
			sortedProjectList.reverse();
		} 
		
		this.moveProjects(element, sortedProjectList);
		
		//return sortedProjectList;
	}
	
	 Project.clearProjects = function(element){
	 
	 	var els = element.getElementsByClassName('project');
		var clearProject = function (el, index) {
			
			el.remove();
		}
		els.each(clearProject);
	 
	 
	 }
	
       
   Project.updateProjects = function(element, projectList, fb, len) {
   		//fb is filterObject
		var totalParams = len;
		var update = function(el, index) {
			if (el != undefined) {
				var display = 0;
				fb.each(function(param){
					if (param.key == 'budget') {
						if (Math.round(el.impacts.Cost) <= parseInt(param.value)) {
							display = display + 1;
						}
					}
					else 
						if (param.key == 'savings') {
							if (Math.round(el.impacts.Savings) <= parseInt(param.value)) {
								display = display + 1;
							}
							
						}
					else 
						if (param.key == 'PBP') {
						
							if (Math.round(el.impacts.PBP) <= parseInt(param.value)) {
								display = display + 1;
							}
							
						}
					else {
						if (el[param.key] == param.value) {
							display = display + 1;
						}
					}
					
				});
				if (display >= totalParams) {
					el.displayOn();
				}
				else {
					el.displayOff();
				}
			}
		}
		projectList.each(update);
   };
   
   
   
    Project.prototype.displayOff = function(){
		$('p' + this.id).hide();
	}
   
   
   
    Project.prototype.displayOn = function(){
		$('p' + this.id).show();
	}
   
   
    Project.prototype.setCompleted = function(completed){
		this.completed = completed;
		var params = {};
	    params['project_id'] = this.id;
		if (completed == true) { 
		
			ajaxAddCompleted(this.id, this.impacts['CO2'], this.impacts['E_Units'], this.impacts['HotWater'], this.projectPrereqs[0], this.projectMutuallyExclusives );
			
		} else {
			
			ajaxRemoveCompleted(this.id, this.impacts['CO2'], this.impacts['E_Units'], this.impacts['HotWater'], this.projectPrereqs[0], this.projectMutuallyExclusives );
			
		}
	}
	
    Project.prototype.updateCheckbox = function(completed){
		var el = $('checkbox' + this.id);
		if (completed == false) {
			el.value = 0;
			el.replace( new Element('input', {id:'checkbox' + this.id, 'class':'checkbox', 'type':'checkbox', value:'0'})   );
			this.completed = false;
		}
		else {
			el.value = 1;
			el.replace( new Element('input', {id:'checkbox' + this.id, 'class':'checkbox', 'type':'checkbox', 'checked':'checked', 'defaultChecked':'checked', value:  1})   );
			this.completed = true;
		}
		this.updateCompletedTag($('projectCheckboxBlock'+this.id), completed);
		this.updateBar(completed);
	}

// Added by JWP on 2-28-09

    Project.prototype.grayoutCheckbox = function(grayout){
		var el = $('checkbox' + this.id);
		if (grayout == false) {
      el.value = 0;
			this.grayout = false;

      var d_checkbox = $('checkbox' + this.id);
      d_checkbox.show();

      var d_lili = $('projectRowLili' + this.id);
      var d = $('p' + this.id);
			d.removeClassName('projectExcluded');

		}
		else {
      el.value = 1;
      var d_checkbox = $('checkbox' + this.id);
      d_checkbox.hide();
			this.grayout = true;

      var d_lili = $('projectRowLili' + this.id);
      var d = $('p' + this.id);
			d.addClassName('projectExcluded');

		}
	}
// End of JWP Add
	
    Project.prototype.updateBar = function(completed){
		var d_lili = $('projectRowLili' + this.id);
		var d = $('p' + this.id);
		if (completed == false) {
			d_lili.addClassName('projectRowLili');
			d_lili.removeClassName('projectRowLiliCompleted');
			d.removeClassName('projectSelected');
		}
		else {
			d_lili.removeClassName('projectRowLili');
			d_lili.addClassName('projectRowLiliCompleted');
			d.addClassName('projectSelected');
		}
	}	
   
    Project.prototype.updateCompletedTag = function(container, completed){

	
	}
	
	Project.prototype.updateImpacts = function(projectData){
		
  		this.impacts = projectData['Impacts'];
		this.lili = Math.round((this.impacts.LILI)*10)/10;
		this.water = projectData['Project']['water'];
		this.energy = projectData['Project']['energy'];
		this.waste = projectData['Project']['waste'];
		this.co2 = projectData['Project']['co2'];
		
		var container = $('p' + this.id );
		if ($('p' + this.id + '_description') != undefined) {
			$('p' + this.id + '_description').remove();
			$('p' + this.id + '_breakdown').remove();
			$('p' + this.id + '_toggle').update('more info');
			this.renderMoreInfo();
		}
		
		$('p_cost' + this.id ).update( '$' + Math.round(this.impacts.Cost) );
		$('p_save' + this.id ).update( '$' + Math.round(this.impacts.Savings) );
		$('projectRowLili' + this.id ).update( this.lili );

	}
   
    /**
   * Simple test function to pretty-print the data in the project
   */
   Project.prototype.toHTML = function () {
  // alert('toHtml');
   	var index = this.id;
	var d = new Element('div', {'class':'project', id:'p' + index});
		
		var d_sp1 = new Element('div', {'class':'spacer'}).update('&nbsp;');
		
		var d_checkbox = new Element('div', {'id':'projectCheckboxBlock'+this.id, 'class':'projectCheckbox'});
		var d_checkbox_wrapper = new Element('div', {'class':'projectCheckboxWrapper'});
		
		if (this.completed == true) {
			d.addClassName('projectSelected');
			var d_checkbox1 = d_checkbox_wrapper.appendChild( new Element('input', {id:'checkbox' + this.id, 'class':'checkbox', 'type':'checkbox', 'checked':'checked', 'defaultChecked':'checked', value:  1})   );
			d_checkbox.appendChild(d_checkbox_wrapper);
			
		} else {
			var d_checkbox1 = d_checkbox_wrapper.appendChild( new Element('input', {id:'checkbox' + this.id, 'class':'checkbox', 'type':'checkbox', value:'0'})   );
			d_checkbox.appendChild(d_checkbox_wrapper);
		}
		if (isNaN(this.impacts.LILI)) { this.impacts.LILI = 0; }
		var d_lili = new Element('div', {'class':'projectRowLili', 'id':'projectRowLili' + this.id}).update(this.lili);
		if (this.completed == true) {
			d_lili.removeClassName('projectRowLili');
			d_lili.addClassName('projectRowLiliCompleted');
		}
// Added by JWP on 2-29-09
    else {
      if (this.grayout == true) {
        d_checkbox1.hide();
        d.addClassName('projectExcluded');
      }
    }
		
		var d_info = new Element('div', {'class':'projectInfo'});

			var d_toggle = new Element('div', {'class':'projectToggle'});//.update("<img src='/images_calculator/more_info_arrow.gif'/>");
				var p_toggle_a = new Element('a', {'id':'p' + this.id + '_toggle', 'class':'toggleInfo'}).update('Project Description');
				d_toggle.appendChild(p_toggle_a);
			
			var detail_container = new Element('div', {'class':'projectDetails', id:'p' + index + '_details'});
			
					detail_container.setStyle({ 
						height: '1px'
						}
					); 
			var projectData = [ new Element('div', {'class':'projectTitle'}).update( this.name), 
				new Element('div', {'id':'p_cost' + this.id , 'class':'projectMoney'}).update( '$' + Math.round(this.impacts.Cost)),
				new Element('div', {'id':'p_save' + this.id , 'class':'projectMoney'}).update( '$' + Math.round(this.impacts.Savings)),

				detail_container,
				d_toggle];
			
			var addToParent = function(el, index) {
				d_info.appendChild(el);
			}
			projectData.each(addToParent);
	
		var d_imp = new Element('div', {'class':'projectImpact'}).update(this.renderEnergy() + this.renderWater() + this.renderCo2() +  this.renderWaste() + "&nbsp;" );
		var d_res = new Element('div', {'class':'projectResources'}).update(this.renderResources());
		var d_sp2 = new Element('div', {'class':'spacer'}).update('&nbsp;');
		
		d.appendChild(d_sp1);
		d.appendChild(d_checkbox);
		d.appendChild(d_lili);
		d.appendChild(d_info);
		d.appendChild(d_imp);
		d.appendChild(d_res);
		d.appendChild(d_sp2);
		
		// observer for More Info button
		var me = this;
		
		
		p_toggle_a.observe('click',  
			  function(event){ 
				me.renderMoreInfo();
			  } 
		);
		
		p_toggle_a.observe('mouseover',  
			  function(event){ 
				event.target.addClassName('over');
			  } 
		);
		p_toggle_a.observe('mouseout',  
			  function(event){ 
				event.target.removeClassName('over');
			  } 
		);
		

	
		d_checkbox1.observe('click',  
			  function(event){ 
			  	if (event.target.checked == true) {
					me.setCompleted(true);
					me.updateBar(true);
					me.updateCompletedTag(d_checkbox1, true);
				} else {
					me.setCompleted(false);
					me.updateBar(false);
					me.updateCompletedTag(d_checkbox1, false);

				}
				
			  } 
			  
			  
		);
	
     return d;
   };
   
      
   
   Project.prototype.renderMoreInfo = function () { 
   		var enUnit = this.impacts["E_Units"];
		if(enUnit == 0 || enUnit == "0"){
			enUnit = "";
		}
   		if ($('p' + this.id + '_description') == undefined) {
			$('p' + this.id + '_details').appendChild(new Element('div', {
				id: 'p' + this.id + '_description',
				'class': 'projectDescription'
			}).update(this.description));
			$('p' + this.id + '_details').appendChild(new Element('div', {
				id: 'p' + this.id + '_breakdown',
				'class': 'projectBreakdown'	
			}).update('<ul><li><label>Energy Savings</label><br/>' + Math.round(this.impacts["Energy"]) + ' ' + enUnit + '</li><li><label>Water Savings</label><br/>' + Math.round(this.impacts["FreshWater"]) + ' gallons</li><li><label>Waste Savings</label><br/>' + Math.round(this.impacts["Waste"]) + ' lbs</li><li><label>CO2 Savings</label><br/>' + Math.round(this.impacts["CO2"]) + ' lbs</li><li><label>Runoff Savings</label><br/>' + Math.round(this.impacts["Runoff"]) + ' gallons</li><li><label>Payback Period</label><br/>' + Math.round(this.impacts["PBP"]*10)/10 + ' years</li></ul>'));		
			$('p' + this.id + '_toggle').update('Close');
			$('p' + this.id + '_details').setStyle({height: 'auto'}); 
			
		} else {
			$('p' + this.id + '_description').remove();
			$('p' + this.id + '_breakdown').remove();
			$('p' + this.id + '_toggle').update('Project Description');
			$('p' + this.id + '_details').setStyle({height: '1px'}); 
		}
   }
   
   
   
       /**
   * Simple test function to pretty-print the data in the project
   */
   Project.prototype.renderEnergy = function(){
		if (this.energy == 1) {
			return '<img src="/images_calculator/tag_energy.png"><br/>';
		} else {
			return '';
		}
   }
   Project.prototype.renderWater = function(){
		if (this.water == 1) {
			return '<img src="/images_calculator/tag_water.png"><br/>';
		} else {
			return '';
		}
   }
   Project.prototype.renderCo2 = function(){
		if (this.co2 == 1) {
			return '<img src="/images_calculator/tag_c02.png"><br/>';
		} else {
			return '';
		}
   }
   Project.prototype.renderWaste = function(){
		if (this.waste == 1) {
			return '<img src="/images_calculator/tag_trash.png"><br/>';
		} else {
			return '';
		}
   }

   
   /**
    * Helper function for use with renderProjects and toHTML
    */
    Project.prototype.renderResources = function () {
      result = "";
      for (var i=0; i<this.resources.length; i++) {
        if (i > 0) { result += ""; }
        if (typeof(this.resources[i].url) == 'undefined') { this.resources[i].url = ""; }

		if (this.resources[i].url == "") {
			result += "<p>" + this.resources[i].name + "</p>";
		}
		else {
		
			if (this.resources[i].url.substring(0, 7) == "http://") {
				protocol = "";
			}
			else 
				if (this.resources[i].url.charAt(0) != '/') {
					protocol = "http://";
				}
				else {
					protocol = "";
				}
//  Added by JWP on 3-25 to incorporate image rollover
        var tipmsg = "(\'<img src=" + this.resources[i].image + ">\', WIDTH, 135, BGCOLOR, \'#FFFFFF\',ABOVE,true)";
        if (this.resources[i].image == "/images_products/prod/") {
          result += "<p><a href=\"" + protocol + this.resources[i].url + "\" class='resource'>" +
          this.resources[i].name + "</a></p>";
        }
        else {
          result += "<p><a href=\"" + protocol + this.resources[i].url + "\" class='resource' onmouseover=\"Tip" + tipmsg + "\" onmouseout=\"UnTip()\" >" +
                 this.resources[i].name + "</a></p>";
//			result += "<p><a href=\"" + protocol + this.resources[i].url + "\" class='resource'>" +
//			this.resources[i].name + "</a></p>";
        }
		}
      }
	  if (result == "") {
	  	var link = "";
	    if (this.category_type == "PRODUCT") {
			link = "<a href=" + this.url + " class='help'>More Resources</a>";
		} else {
			link =  "<a href='/providers/" + this.category + "/" + this.category_id + "' class='help'>Find Resources</a>";
		}
	  	return link;
	  }
	  else {
	  	var link = "";
	    if (this.category_type == "PRODUCT") {
			link = "<a href=" + this.url + " class='help'>More Resources</a>";
		} else {
			link =  "<a href='/providers/" + this.category + "/" + this.category_id + "' class='help'>More Resources</a>";
		}
	  	return result+=link;
	  }
    };
