function InputSet(){
  this.develWage       = 0;
  this.complexIntTime  = 0;
  this.moderateIntTime = 0;
  this.simpleIntTime   = 0;
  this.srvcComplex     = [0,0,0,0,0];
  this.srvcModerate    = [0,0,0,0,0];
  this.srvcSimple      = [0,0,0,0,0];
  //for ROI:
  this.annualMaint     = [0,0,0,0,0];
  this.hwmwCost        = 0;
  this.consultCost     = 0;
  this.trainCost       = 0;
  this.npv             = 0;
  this.initialized     = false; //values have been entered by user
  
}
// used for making "copies" of javascript objects by value.
// Usage: inData  = new cloneObject(simData);
function cloneObject(obj) {
    for (i in obj) {
        if (typeof obj[i] == 'object') {
            this[i] = new cloneObject(obj[i]);
        }
        else
            this[i] = obj[i];
    }
}

// type must be either 'simple', 'moderate' or 'complex'
// year must be 1,2,3,4 or 5
// isSoa must be true or false (based on if you want the SOA cost)
// inData is the InputSet object to derive values from
// cumalitave must be true or false (for annual vs. to-date)
function getCost(type,year,isSoa,inData,cumalitave){
  var cost = inData.develWage;
  switch(type){
    case 'simple': cost=cost*inData.srvcSimple[year-1]*inData.simpleIntTime; break;
    case 'moderate': cost=cost*inData.srvcModerate[year-1]*inData.moderateIntTime; break;
    case 'complex': cost=cost*inData.srvcComplex[year-1]*inData.complexIntTime; break;
    default: cost=0;
  }
  if(isSoa){
    //hard coded multipliers
    switch(year){
      case 1: cost = cost*1.2;break;
      case 2: cost = cost*0.8;break;
      default: cost = cost*0.6;
    }
  }

  if(year>1 && cumalitave)
    cost += getCost(type,(year-1),isSoa,inData,cumalitave);

  return cost;
}

// code is 1 - 7: s m c sm sc mc smc
// isSoa must be true or false
// cumalitave must be true or false
InputSet.prototype.getDatapointsArray = function(code, isSoa, cumalitave){
  var i;
  var dataPoints = [];
  var costArray = [];
  switch(code){
    case "1":
      costArray = MochiKit.Base.map(getCost,singValArray(5,'simple'),[1,2,3,4,5],singValArray(5,isSoa),singValArray(5,this),singValArray(5,cumalitave));break;
    case "2":
      costArray = MochiKit.Base.map(getCost,singValArray(5,'moderate'),[1,2,3,4,5],singValArray(5,isSoa),singValArray(5,this),singValArray(5,cumalitave));break;
    case "3":
      costArray = MochiKit.Base.map(getCost,singValArray(5,'complex'),[1,2,3,4,5],singValArray(5,isSoa),singValArray(5,this),singValArray(5,cumalitave));break;
    case "4":
      var array1 = MochiKit.Base.map(getCost,singValArray(5,'simple'),[1,2,3,4,5],singValArray(5,isSoa),singValArray(5,this),singValArray(5,cumalitave));
      var array2 = MochiKit.Base.map(getCost,singValArray(5,'moderate'),[1,2,3,4,5],singValArray(5,isSoa),singValArray(5,this),singValArray(5,cumalitave));
      costArray = sumArraysByElement(array1,array2);break;
    case "5":
      var array1 = MochiKit.Base.map(getCost,singValArray(5,'simple'),[1,2,3,4,5],singValArray(5,isSoa),singValArray(5,this),singValArray(5,cumalitave));
      var array2 = MochiKit.Base.map(getCost,singValArray(5,'complex'),[1,2,3,4,5],singValArray(5,isSoa),singValArray(5,this),singValArray(5,cumalitave));
      costArray = sumArraysByElement(array1,array2);break;
    case "6":
      var array1 = MochiKit.Base.map(getCost,singValArray(5,'moderate'),[1,2,3,4,5],singValArray(5,isSoa),singValArray(5,this),singValArray(5,cumalitave));
      var array2 = MochiKit.Base.map(getCost,singValArray(5,'complex'),[1,2,3,4,5],singValArray(5,isSoa),singValArray(5,this),singValArray(5,cumalitave));
      costArray = sumArraysByElement(array1,array2);break;
    case "7":
      var array1 = MochiKit.Base.map(getCost,singValArray(5,'simple'),[1,2,3,4,5],singValArray(5,isSoa),singValArray(5,this),singValArray(5,cumalitave));
      var array2 = MochiKit.Base.map(getCost,singValArray(5,'moderate'),[1,2,3,4,5],singValArray(5,isSoa),singValArray(5,this),singValArray(5,cumalitave));
      var array3 = MochiKit.Base.map(getCost,singValArray(5,'complex'),[1,2,3,4,5],singValArray(5,isSoa),singValArray(5,this),singValArray(5,cumalitave));
      costArray = sumArraysByElement(sumArraysByElement(array1,array2),array3);break;
    default:
      costArray = singValArray(5,0);
      //alert("error: Code "+code+" not matched");
  }
  
  for (i in costArray){
    if(isSoa && cumalitave){
      costArray[i] += parseInt(inData.annualMaint[i])*0.6 + this.getTotalInvestment();
      }
    else if (cumalitave){
      costArray[i] += parseInt(inData.annualMaint[i]);
      }
      
    dataPoints[i] = [(parseInt(i)+1),costArray[i]];
  }

  return dataPoints;
}

// year is the year to show Return (1 thru 5)
function getAnnualReturn(year,inData,code){
  var datapoints = inData.getDatapointsArray(code,false,false);
  var soadatapoints = inData.getDatapointsArray(code,true,false);
  var services = (datapoints[(year-1)])[1] - (soadatapoints[(year-1)])[1];

  var maintenance = parseInt(inData.annualMaint[(year-1)])*0.4;
  //alert("services: "+services+"\nmaintenance: "+maintenance+"\ntotal: "+(services+maintenance));
  //alert(maintenance);
  return services+maintenance;
}

//returns the 5 year roi
InputSet.prototype.getROI = function(){
  return this.npv/this.getTotalInvestment();
}

InputSet.prototype.getROIDatapoints = function(code){
  var dataPoints = [];
  var returnsArray = MochiKit.Base.map(getAnnualReturn,[1,2,3,4,5],singValArray(5,this),singValArray(5,code));
  var npvArray = MochiKit.Base.map(npv,returnsArray,singValArray(5,0.10),[1,2,3,4,5]);
  //sum preceeding years into npv value
  for(var k=npvArray.length-1; k>=0; k--){
    for(var i=k-1; i>=0; i--){
      npvArray[k] += npvArray[i];
    }
  }
  this.npv = npvArray[4];
  var divisor = this.getTotalInvestment();
  if(divisor == 0) divisor = 1;
  var roiArray = MochiKit.Base.map(operator.div,npvArray,singValArray(5,divisor));
  
  for (var i in roiArray){
    dataPoints[i] = [(parseInt(i)+1),MochiKit.Format.twoDigitFloat(roiArray[i])];
  }
  return dataPoints;
}


InputSet.prototype.getTotalInvestment = function(){
  return parseInt(this.hwmwCost) + parseInt(this.consultCost) + parseInt(this.trainCost);
}

// code is 1 - 7: s m c sm sc mc smc
InputSet.prototype.initAnnualMaintenance = function(code){
  switch(code){
    case "1":
      for (var i=0; i<5; i++){
        this.annualMaint[i] = this.srvcSimple[i]*this.simpleIntTime*this.develWage*0.15;
      }break;
    case "2":
      for (var i=0; i<5; i++){
        this.annualMaint[i] = this.srvcModerate[i]*this.moderateIntTime*this.develWage*0.15;
      }break;
    case "3":
      for (var i=0; i<5; i++){
        this.annualMaint[i] = this.srvcComplex[i]*this.complexIntTime*this.develWage*0.15;
      }break;
    case "4":
      for (var i=0; i<5; i++){
        this.annualMaint[i] = (this.srvcSimple[i]*this.simpleIntTime + this.srvcModerate[i]*this.moderateIntTime)*this.develWage*0.15;
      }break;
    case "5":
      for (var i=0; i<5; i++){
        this.annualMaint[i] = (this.srvcSimple[i]*this.simpleIntTime + this.srvcComplex[i]*this.complexIntTime)*this.develWage*0.15;
      }break;
    case "6":
      for (var i=0; i<5; i++){
        this.annualMaint[i] = (this.srvcModerate[i]*this.moderateIntTime + this.srvcComplex[i]*this.complexIntTime)*this.develWage*0.15;
      }break;
    case "7":
      for (var i=0; i<5; i++){
        this.annualMaint[i] = (this.srvcSimple[i]*this.simpleIntTime + this.srvcModerate[i]*this.moderateIntTime + this.srvcComplex[i]*this.complexIntTime)*this.develWage*0.15;
      }break;
    default:
      this.annualMaint = [0,0,0,0,0];
      //alert("error: Code "+code+" not matched");
  }
  var costArray = this.annualMaint;

}
/*********************************************************
  Utility functions for calculations
**********************************************************/
//arrays must be of equal length
function sumArraysByElement(array1,array2){
  return MochiKit.Base.map(operator.add,array1,array2);
}
//creates an array of size length, where every value is the same
function singValArray(length,value){
  var i = 0;
  var myArray = [];
  for(i=0; i<length; i++){
    myArray[i] = value;
  }
  return myArray;
}

//calculates npv for money flow event t
function npv(amount,rate,t){
  return amount/Math.pow((1+rate),t);
}

//takes an array
//returns string of array seperated with stringToken
// not used?
function tokenStringArray(myArray,stringToken){
  var result = "";
  for(var i=0; i<myArray.length; i++){
    if(typeof myArray[i] == 'object')
      return tokenStringArray(MochiKit.Base.flattenArray(myArray),stringToken);
    result += myArray[i] + stringToken;
    if((i+2) == myArray.length) {
      result += myArray[i+1];
      i++;
    }
  }
  return result;
}

//input:
//  year one process count
//  annual growth rate - whole numbers ex: 30 for 30 percent
//returns an array of 5 values at the growth rate.
function genProcCounts(yearOne,growthRate){
  var rate = 1+growthRate/100;
  var two = yearOne*rate;
  var three = two*rate;
  var four = three*rate;
  var five = Math.round(four*rate);
  four = Math.round(four);
  three = Math.round(three);
  two = Math.round(two);

  return [yearOne,two,three,four,five];
}