function maraWeekObj(targDist, sched, wkCde)
{ 
	var wInd = wkCde.match(/\d+/); 
	wInd = wInd*1.0; 
	if(wkCde.indexOf('t3') != -1)
		{ return new mraceWeek(targDist, sched, wInd); } 
	if(wkCde.indexOf('t') != -1) 
		{ return new mtaprWeek(targDist, sched, wInd); } 
	if(wkCde.indexOf('n') != -1) 
		{ return new normlWeek(targDist, sched, wInd); } 
	if(wkCde.indexOf('r') != -1)
		{ return new rcovrWeek(Math.ceil(targDist * .75), sched); } 
	
	return null; 
} 

normlWeek.prototype = new genWeek(); 
rcovrWeek.prototype = new genWeek(); 
mtaprWeek.prototype = new genWeek(); 
mraceWeek.prototype = new genWeek(); 
lprepWeek.prototype = new genWeek(); 

function rcovrWeek(tDist, sched)
{     
	genWeekApply(this, tDist); 
	this.setRegRuns(sched); 
	this.dispData = "RECOVERY"; 
} 

/** 
 * Week object representing the final week of the program which includes the 
 * marathon race week. 
 */ 
function mraceWeek(tDist, sched, wInd)
{     
	var sMPW = prParams["mpwe"]*1.0; 
	var x = sMPW <= 20 ? 2 : (sMPW <= 40 ? 3 : 4); 
	
	genWeekApply(this, 40); 
	this.dispData = "RACE WEEK"; 
	
	for(var i = 1; i < 7; i++)
	{ 
		if(i == 2 || i == 5) 
		{ 
			this.days[i] = new regRun(); 
			this.days[i].dst = x; 
		} 
	} 
	
	// Marathon Race Day.
	this.days[0] = new raceDay();
	this.days[0].getDispData = maraDispData;
} 

/**
 * Sets the special run to be the one from the very first training week. 
 */ 
mraceWeek.prototype.setFromPrevWeeks = function(prevWeeks, sched)
{ 
	this.days[4] = mClone(prevWeeks[0].getSpecRun());  
	this.days[4].paceWeek = 0; 
} 

mraceWeek.prototype.allocateDist = function() { } 

function normlWeek(tDist, sched, wInd)
{ 
	genWeekApply(this, tDist); 
	
	this.dispData = "Marathon Training"; 
	
	// First set the EZ runs. 
	this.setRegRuns(sched); 
	
	var sMPW = prParams["mpwe"];
	
	// Now set the long run. Little bit unpleasant because we have to cross cut back 
	// to the starting miles per week data. 
	{ 
		var lro = new longRun(); 
				
		var dInd; 
		if(sMPW <= 15) { dInd = 0; } 
		else if(sMPW <= 20) { dInd = 2; } 
		else if(sMPW <= 30) { dInd = 4; } 
		else if(sMPW <= 40) { dInd = 5; } 
		else { dInd = 6; } 				
		
		var maraDistAr = new Array(6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 16, 20, 16, 20, 16, 20, 16, 20, 16, 20, 16, 20);
		
		// This is a hard coded scheme to make sure the 11-15 moderate program 
		// is really MODERATE and not HARD. 
		if(sMPW < 15 && prParams["diff"] == "mod") 
			{ maraDistAr = new Array( 6,7,8,9,10,11,12,13,14,15,16, 17, 18); } 
		
		lro.dst = maraDistAr[dInd + wInd-1];
		
		// If we reached the 20-mile mark, then the last training week must be 20 miles. 
		wcStr = mWeekCodes(sched.getProgLength()).join(","); 
		if(dInd + wInd-1 > 9 && wcStr.indexOf("n" + wInd) != -1 && wcStr.indexOf("n" + (wInd+1)) == -1)
			{ lro.dst = 20; } 
		
		this.days[sched.longRunDay()] = lro;
	} 
	
	// Now set the special run 
	{ 
		var pro; 
		var srDists = new Array(5, 5, 6, 5, 6, 6, 5, 6, 7, 5, 5); 
		var mApprox = Math.floor((wInd-1)/3); 
		
		if((wInd-1) % 3 == 1)
		{ 
			pro = new repeatSixteen(tDist, mApprox);  
		} 
		else
		{ 
			var trDst; 
			if(sMPW < 31) 
				{ trDst = new Array(3, 3, 4, 4, 5, 5, 3, 6); } 
			else
				{ trDst = new Array(4, 5, 6, 7, 8, 7, 6, 7); } 	
			var secondPR = (wInd-1) % 3 == 2 ? 1 : 0; 
			pro = new tempoRun(trDst[mApprox*2 + secondPR]); 
		} 
		this.days[sched.pacedRunDay()] = pro; 
	} 
}

normlWeek.prototype.addDist = function()
{ return true; } 

function mtaprWeek(tDist, sched, wInd)
{ 
	var mDist; 
	if(wInd == 1)
		{ mDist = Math.ceil(tDist * .75); } 
	if(wInd == 2)
		{ mDist = Math.ceil(tDist * .5); } 
	genWeekApply(this, mDist); 
	
	this.wInd = wInd; 
	this.setRegRuns(sched); 
	this.dispData = "Marathon-Tapering " + wInd; 
	
	var lro = new longRun(); 
	lro.dst = wInd == 1 ? 12 : 8; 
	this.days[sched.longRunDay()] = lro;     
} 

/** 
 * The marathon taper weeks have special runs that are taken from the previous weeks. 
 * See "Taper Week" section in specs doc. 
 */ 
mtaprWeek.prototype.setFromPrevWeeks = function(prevWeeks, sched)
{ 
	if(this.wInd == 1) 
	{
		// Last previous Repeat 1600 workout. Almost always is from N10
		for(var i = 0; i < prevWeeks.length && prevWeeks[i] != this; i++)
		{ 
			var sr = prevWeeks[i].getSpecRun(); 
			if(sr != null && sr.cde == "y160")
			{ 
				this.days[sched.pacedRunDay()] = mClone(sr);
				this.days[sched.pacedRunDay()].paceWeek = i; 
			} 
		}  
	} 
	else
	{ 
		this.days[sched.pacedRunDay()] = mClone(prevWeeks[2].getSpecRun());
		this.days[sched.pacedRunDay()].paceWeek = 2; 
	}
} 

// xxmGetPaceMod
function mGetPaceMod(met, paceData)
{ 
	var p = new Object(); 
	p.easy = "" + timeConvert(paceData.easy, met); 
	p.temp = "" + timeConvert(paceData.maxm, met); 
	p.maxm = "" + timeConvert(paceData.maxm, met); 
	p.sped = "" + timeConvert(paceData.sped, met); 
	p.lgrn = "" + timeConvert(paceData.lgrn, met); 
	if(paceData.spec)
		{ p.spec = "" + timeConvert(paceData.spec, met); } 
	return p; 
} 

// xxmWeekProg
// tw = total weeks in program
function mWeekCodes(tw)
{ 
	var wstr = mWeekCodeSub(tw); 
	return wstr.split(","); 	
} 

function mWeekCodeSub(tw)
{ 
	if(tw == 16) 
		{ return "n1, n2, n3, r1, n4, n5, n6, r2, n7, n8, n9, r3, n10, t1, t2, t3"; } 
	if(tw == 15)
		{ return "n1, n2, n3, n4, r1, n5, n6, n7, r2, n8, n9, n10, t1, t2, t3"; } 
	if(tw == 14)
		{ return "n1, n2, n3, r1, n4, n5, n6, r2, n7, n8, n9, t1, t2, t3"; } 
	if(tw == 13)
		{ return "n1, n2, n3, r1, n4, n5, n6, r2, n7, n8, n9, t2, t3"; } 
	if(tw == 12)
		{ return "n1, n2, n3, n4, n5, r1, n6, n7, n8, n9, t2, t3"; } 
	if(tw == 11)
		{ return "n1, n2, n3, n4, r1, n5, n6, n7, n8, t2, t3"; } 
	if(tw == 10)
		{ return "n1, n2, n3, n4, r1, n5, n6, n7, t2, t3"; } 
	if(tw == 9)
		{ return "n1, n2, n3, r1, n4, n5, n6, t2, t3"; } 
	if(tw == 8)
		{ return "n1, n2, n3, r1, n4, n5, t2, t3"; } 
	if(tw == 7)
		{ return "n1, n2, n3, r1, n4, n5, t3"; } 
	if(tw == 6)
		{ return "n1, n2, n3, n4, n5, t3"; } 
	if(tw == 5)
		{ return "n1, n2, n3, n4, t3"; } 
	if(tw == 4)
		{ return "n1, n2, n3, t3"; } 
	if(tw == 3)
		{ return "n1, n2, t3"; } 
	
	logErr("Foutmelding: U dient tenminste een 3 weken lang trainingsprogramma te volgen"); 
	return null; 
} 

/** 
 * These are weeks for a preparatory training program. 
 */ 
function lprepWeek(wkNum, sched, dc)
{     	 
	if(wkNum == 0)      { dists = dc > 1 ? [2, 2, 2] : [2, 2, 2]; } 
	if(wkNum == 1)      { dists = dc > 1 ? [2, 3, 3] : [2, 2, 3]; } 
	if(wkNum == 2)      { dists = dc > 1 ? [3, 3, 4] : [2, 3, 4]; } 
	if(wkNum == 3)      { dists = dc > 1 ? [3, 4, 5] : [2, 3, 5]; } 
	
	var td = 0; 
	for(var i = 0; i < 3; i++) { td += dists[i]; } 
	
	genWeekApply(this, td); 
	this.dispData = "Voorbereiding"; 
	
	var tds = [2, 4, 0]; 
	for(var i = 0; i < tds.length; i++)
	{ 
		var rrd = new regRun(); 
		rrd.dst = dists[i];
		this.days[(tds[i] + sched.longRunDay()) % 7] = rrd; 
	}
} 






