EnVisageOnline/Main/Source/EnVisage/Code/RaceMatrix.cs

918 lines
38 KiB
C#

using EnVisage.Code.BLL;
using EnVisage.Controllers;
using EnVisage.Models;
using Iniphi.Calculations;
using NLog;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Validation;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EnVisage.Code
{
public class RaceMatrix
{
protected static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private List<MixProjectModel> MixProjects { get; set; }
private DateTime RaceStartDate { get; set; }
private DateTime RaceEndDate { get; set; }
private Race CalcModule { get; set; }
private int Threshold { get; set; }
private Guid TeamID { get; set; }
private int RaceDuration { get; set; }
public MatrixProject[] Projects { get; set; }
public Dictionary<int, Dictionary<Guid, DateRange>> _mixInfo { get; set; }
public List<AvailableCapacityMatrix> AvailableCapacityMatrixs {get;set;}
private Dictionary<Guid, decimal[]> pinnedActuals = new Dictionary<Guid, decimal[]>();
private List<ProjectObj> Race2CalcProjectObj = new List<ProjectObj>();
public RaceMatrix(int threshold, Race calcModule, bool TeamLevel,MixSaveModel model, int version)
{
var raceStartDate = Utils.ConvertFromUnixDate(model.Filter.Selection.StartDate);
var raceEndDate = Utils.ConvertFromUnixDate(model.Filter.Selection.EndDate);
TeamID = Guid.Parse(model.Calendar.Teams.FirstOrDefault().Id);
var weekEndings = FiscalCalendarManager.GetWeekendingsByRange(raceStartDate, raceEndDate, new EnVisageEntities());
RaceStartDate = weekEndings[0];
RaceEndDate = weekEndings.Last();
Threshold = threshold;
MixProjects = model.Calendar.Projects.Values.ToList();
CalcModule = calcModule;
CalcModule.SCORE2MAX = 100m;
LoadMatrixData(model, TeamLevel);
ReconCapacity();
if (version > 1)
{
Projects = Projects.OrderByDescending(x => x.Score2).ToArray();
}
}
private void ReconRace2Capacity(MatrixProject p, int Ord)
{
var RollingIterationActuals = new Dictionary<Guid, decimal[]>();
if (pinnedActuals.Count > 0)
{
foreach (var k in pinnedActuals.Keys)
{
RollingIterationActuals.Add(k, pinnedActuals[k]);
}
}
p.Race2Pinned = true;
var cap = p.SetBestIterationDataRace2( Ord, this.RaceStartDate, this.RaceEndDate, this.RaceDuration);
calcIterationActuals(cap, ref RollingIterationActuals);
pinnedActuals = RollingIterationActuals;
Race2CalcProjectObj.Add(p.getRaceProject(Ord, 1));
}
private void ReconCapacity()
{
var RollingIterationActuals = new Dictionary<Guid, decimal[]>();
foreach (var p in Projects)
{
if (p.isPinned && Projects.Count() > 0)
{
var cap = p.DoIterationCalc(p.CalculateOrdinalFromDate(p.StartDate, this.RaceStartDate), this.RaceStartDate, this.RaceEndDate, this.RaceDuration);
calcIterationActuals(cap, ref RollingIterationActuals);
}
else if (p.isPinned)
p.isPinned = false;
}
var cleanPs = Projects.Where(x => x.isPinned == false).ToArray();
Projects = cleanPs;
pinnedActuals = RollingIterationActuals;
}
private void SetRaceToCapacity()
{
var RollingIterationActuals = new Dictionary<Guid, decimal[]>();
foreach (var p in Projects)
{
if (p.Race2Pinned)
{
var cap = p.DoIterationCalc(p.CalculateOrdinalFromDate(p.StartDate, this.RaceStartDate), this.RaceStartDate, this.RaceEndDate, this.RaceDuration);
calcIterationActuals(cap, ref RollingIterationActuals);
}
}
pinnedActuals = RollingIterationActuals;
}
public void resetRaceModule()
{
CalcModule.resetCalcModule();
}
public int GetTotalWeekEndingForIteration()
{
return RaceDuration;
}
public void SetRace2ScorePerProject(int pIdx, decimal totalScore)
{
var p = this.Projects[pIdx];
p.Race2TotalScore = totalScore;
}
public List<MatrixProjectModel> GetMixDataForRace2()
{
var cntx = new EnVisageEntities();
var results = new List<MatrixProjectModel>();
for (int pIdx = 0; pIdx < Projects.Length; pIdx++)
{
var proj = Projects[pIdx];
var StartDateWeekEnding = FiscalCalendarManager.GetWeekendingsByRange(proj.StartDate, null, cntx);
var weekEndings = FiscalCalendarManager.GetWeekendingsByRange(this.RaceStartDate, this.RaceEndDate, cntx);
var newStartWeek = StartDateWeekEnding[0];
if (!proj.isPinned && proj.Race2BestCycle > 0)
newStartWeek = weekEndings[proj.Race2BestCycle - 1];
var pr = new MatrixProjectModel()
{
Id = proj.Id,
OriginalStartWeek = Utils.ConvertToUnixDate(StartDateWeekEnding[0]),
NewStartWeek = Utils.ConvertToUnixDate(newStartWeek),
Name =proj.Name,
RaceOrder = pIdx,
Score2 = proj.Score2,
TotalScore =Math.Round(proj.Race2TotalScore)
};
results.Add(pr);
}
return results;
}
public List<MatrixProjectModel> GetMixDataForIteration(int[] cycles)
{
var results = new List<MatrixProjectModel>();
for (int pIdx = 0; pIdx < Projects.Length; pIdx++)
{
int cycle = cycles[pIdx];
var proj = Projects[pIdx];
var cntx = new EnVisageEntities();
var StartDateWeekEnding= FiscalCalendarManager.GetWeekendingsByRange(proj.StartDate, null, cntx);
var weekEndings = FiscalCalendarManager.GetWeekendingsByRange(this.RaceStartDate, this.RaceEndDate, cntx);
var newStartWeek = weekEndings[cycle - 1];
if (proj.isPinned)
newStartWeek = StartDateWeekEnding[0];
var pr = new MatrixProjectModel()
{
Id = proj.Id,
OriginalStartWeek = Utils.ConvertToUnixDate(StartDateWeekEnding[0]),
NewStartWeek = Utils.ConvertToUnixDate(newStartWeek),
RaceOrder = proj.RaceOrder,
Score2 = proj.Score2,
Name = proj.Name,
TotalScore =proj.Race2TotalScore
};
results.Add(pr);
}
return results;
}
public void BuildProjectIterationRace2Scores(int projectIndex)
{
var proj = Projects[projectIndex];
if (proj.isPinned)
{
return;
}
else
{
for (int cycle = 1; cycle <= this.RaceDuration; cycle++)
{
var RollingIterationActuals = new Dictionary<Guid, decimal[]>();
if (pinnedActuals.Count > 0)
{
foreach (var k in pinnedActuals.Keys)
{
RollingIterationActuals.Add(k, pinnedActuals[k]);
}
}
var workingProjObjList = Race2CalcProjectObj.Clone();
var iterationActuals = proj.DoIterationCalc( cycle, this.RaceStartDate, this.RaceEndDate, this.RaceDuration);
calcIterationActuals(iterationActuals, ref RollingIterationActuals);
var calcdataList = RollingIterationActuals.Select(x => x.Value).ToList();
workingProjObjList.Add(proj.getRaceProject(cycle, 1));
if (calcdataList.Count > 0)
AddIterationToModule(calcdataList, cycle, workingProjObjList);
}
var TotalScore = this.CalcModule.GetBestMix();
proj.Race2TotalScore = TotalScore.TotalScore;
proj.SetBestIterationDataRace2(TotalScore.MixIteration, this.RaceStartDate, this.RaceEndDate, this.RaceDuration);
ReconRace2Capacity(proj, TotalScore.MixIteration);
}
}
private void calcIterationActuals(Dictionary<Guid, decimal[]> iterationActuals, ref Dictionary<Guid, decimal[]> RollingIterationActuals)
{
try
{
foreach (var prId in iterationActuals.Keys)
{
var rollingActuals= RollingIterationActuals.Where(x => x.Key == prId).Select(x=>x.Value).FirstOrDefault();
var AvailPerResource = this.AvailableCapacityMatrixs.Where(x => x.PeopleResourceId == prId).FirstOrDefault();
if (AvailPerResource == null)
{
var initDurationArray = new decimal[this.RaceDuration];
Array.Clear(initDurationArray, 0, this.RaceDuration);
AvailPerResource = new AvailableCapacityMatrix()
{
PeopleResourceId = prId,
AvailableCapacity = initDurationArray,
IsRealResource = true
};
AvailableCapacityMatrixs.Add(AvailPerResource);
}
var iterationActual = iterationActuals[prId];
if (rollingActuals != null)
{
var allocations= rollingActuals.Zip(iterationActual, (first, second) => first - second).ToArray();
RollingIterationActuals[prId] = allocations;
}
else {
var allocations = AvailPerResource.AvailableCapacity.Zip(iterationActual, (first, second) => first - second).ToArray();
var rollingIterationActual = RollingIterationActuals.Where(x => x.Key == prId).FirstOrDefault();
if (rollingIterationActual.Value == null)
RollingIterationActuals.Add(prId, allocations);
else
{
RollingIterationActuals[prId] = allocations;
}
}
}
}
catch (Exception dd)
{
RaceMatrix.LogException(dd);
}
}
public void BuildProjectIterationScores(int Iteration, int[] Cycles)
{
var calcProjectObj = new List<ProjectObj>();
var RollingIterationActuals = new Dictionary<Guid, decimal[]>();
if (pinnedActuals.Count > 0)
{
foreach (var k in pinnedActuals.Keys)
{
RollingIterationActuals.Add(k, pinnedActuals[k]);
}
}
for (int pIdx =0; pIdx< Projects.Length; pIdx++)
{
int cycle = Cycles[pIdx];
var proj = Projects[pIdx];
var iterationActuals=proj.DoIterationCalc( cycle,this.RaceStartDate,this.RaceEndDate,this.RaceDuration);
calcProjectObj.Add(proj.getRaceProject(cycle ,1m ));
calcIterationActuals(iterationActuals, ref RollingIterationActuals);
}
var calcdataList = RollingIterationActuals.Select(x => x.Value).ToList();
if (calcdataList.Count > 0)
AddIterationToModule(calcdataList, Iteration, calcProjectObj);
}
private Dictionary<int, Dictionary<Guid, DateRange>> getMixInfoObj()
{
if (_mixInfo == null)
_mixInfo = new Dictionary<int, Dictionary<Guid, DateRange>>();
return _mixInfo;
}
public void AddIterationToModule(List<decimal[]> mixdataforcal, int iterationCount, List<ProjectObj> calcProjectObj)
{
CalcModule.CalcIterationEx(mixdataforcal, iterationCount, calcProjectObj);
}
#region Build Data collections
private void LoadMatrixData(MixSaveModel m, bool teamLevel)
{
try
{
var ProjectList = new List<MatrixProject>();
int maxCapLoop = m.Calendar.Projects.Count;
ProjectManager projMan = new ProjectManager(new EnVisageEntities());
foreach (var manProj in m.Calendar.ManagedProjects)
{
var p = m.Calendar.Projects.Select(x => x.Value).Where(x => x.Id == manProj).FirstOrDefault();
if (p == null)
continue;
var EfProj = projMan.Load(p.Id);
if (EfProj == null)
continue;
var mp = new MatrixProject()
{
DurationInWeeks = p.Scenario.Duration,
Id = p.Id,
Priority = EfProj.Priority,
Probability = Convert.ToInt32(EfProj.Probability * 100),
RaceOrder = 0,
DeadLineDate = p.Deadline.HasValue ? Utils.ConvertFromUnixDate(p.Deadline.Value) : this.RaceEndDate,
StartDate = Utils.ConvertFromUnixDate(p.Scenario.StartDate),
EndDate = Utils.ConvertFromUnixDate(p.Scenario.EndDate),
isPinned = p.Pinned ? true : Utils.ConvertFromUnixDate(p.Scenario.StartDate) < DateTime.Now,
Name = p.Name
};
mp.SetScore2(this.RaceStartDate, this.RaceEndDate);
mp.setMaxOrdinal(this.RaceStartDate, this.RaceEndDate);
mp.setMinOrdinal(this.RaceStartDate, this.RaceEndDate);
if (this.MixProjects.Where(x => x.Id == mp.Id).FirstOrDefault() != null)
ProjectList.Add(mp);
}
Projects = ProjectList.OrderBy(x => x.Score2).ToArray();
foreach (var p in Projects)
{
var modelProj = m.Calendar.Projects.Select(x => x.Value).Where(x => x.Id == p.Id).FirstOrDefault();
List<ResourceMatrix> Required = new List<ResourceMatrix>();
var wp = p;
foreach (var ec in modelProj.Scenario.Expenditures.Values)
{
if (teamLevel)
{
var rm = new ResourceMatrix()
{
PeopleResourceId = ec.ExpenditureCategoryId,
ProjectId = p.Id,
RequiredCapacity = BuildValueArrayForTeamLevel(ec)
};
if (wp.Id != rm.ProjectId)
wp = Projects.Where(x => x.Id == rm.ProjectId).FirstOrDefault();
Required.Add(rm);
}
else
{
if (ec.Teams == null)
ec.Teams = new Dictionary<string, ExpenditureDetailsTeam>();
if (ec.Teams.Count == 0)
continue;
if (ec.Teams.FirstOrDefault().Value == null)
continue;
if (ec.Teams.FirstOrDefault().Value.Resources == null)
continue;
foreach (var pr in ec.Teams.FirstOrDefault().Value.Resources.Values)
{
var rm = new ResourceMatrix()
{
PeopleResourceId = pr.Id,
ProjectId = p.Id,
RequiredCapacity = BuildValueArrayForResourceLevel(pr, ec)
};
if (wp.Id != rm.ProjectId)
wp = Projects.Where(x => x.Id == rm.ProjectId).FirstOrDefault();
Required.Add(rm);
}
}
if (wp != null)
wp.RequiredResources = Required;
}
}
}
catch (Exception dds)
{
Projects = new MatrixProject[0];
RaceMatrix.LogException(dds);
}
using (var db = new EnVisageEntities())
{
var sproc = "sp_BuildRaceMatrix";
var ResourceColName = "PeopleResourceID";
if (teamLevel)
{
sproc = "sp_BuildRaceMatrixTeams";
ResourceColName = "ExpenditureCategoryId";
}
// If using Code First we need to make sure the model is built before we open the connection
// This isn't required for models created with the EF Designer
db.Database.Initialize(force: false);
// Create a SQL command to execute the sproc
var cmd = db.Database.Connection.CreateCommand();
cmd.CommandText = sproc;
cmd.Parameters.Add(new SqlParameter("@TeamID", this.TeamID));
cmd.Parameters.Add(new SqlParameter("@RaceStartDate", this.RaceStartDate));
cmd.Parameters.Add(new SqlParameter("@RaceEndDate", this.RaceEndDate));
cmd.Parameters.Add(new SqlParameter("@threshold", this.Threshold));
cmd.CommandType = System.Data.CommandType.StoredProcedure;
try
{
db.Database.Connection.Open();
// Run the sproc
var reader = cmd.ExecuteReader();
var maxProjs = 0;
while (reader.Read())
{
maxProjs++;
}
List<int> colNames = new List<int>();
List<int> colPrNames = new List<int>();
List<ResourceMatrix> Required = new List<ResourceMatrix>();
while(true)
{
if (colNames.Count > 0)
break;
reader.NextResult();
while (reader.Read())
{
try
{
if (reader.GetOrdinal("ColumnNames") >= 0)
{
var namesdb = (string) reader.GetValue(reader.GetOrdinal("ColumnNames"));
char[] splprm = { ',' };
string[] names = namesdb.Split(splprm);
foreach (var n in names)
{
var nc = n.Replace('[', ' ').Replace(']', ' ').Trim().TrimStart(' ');
colNames.Add(int.Parse(nc));
}
break;
}
}
catch
{
}
try
{
if (reader.GetOrdinal("PRColumnNames") >= 0)
{
colPrNames = new List<int>();
var namesDbVal = reader.GetValue(reader.GetOrdinal("PRColumnNames"));
if (DBNull.Value == namesDbVal)
break;
var namesdb = (string)namesDbVal;
char[] splprm = { ',' };
string[] names = namesdb.Split(splprm);
foreach (var n in names)
{
var nc = n.Replace('[', ' ').Replace(']', ' ').Trim().TrimStart(' ');
colPrNames.Add(int.Parse(nc));
}
break;
}
}
catch
{
}
Guid ProjectId = Guid.Empty;
if (!reader.IsDBNull(reader.GetOrdinal(ResourceColName)))
ProjectId = (Guid) reader.GetValue(reader.GetOrdinal("ProjectID"));
Guid PeopleResourceId = Guid.Empty;
if (!reader.IsDBNull(reader.GetOrdinal(ResourceColName)))
PeopleResourceId = (Guid) reader.GetValue(reader.GetOrdinal(ResourceColName));
var rm = new ResourceMatrix()
{
PeopleResourceId = PeopleResourceId,
ProjectId = ProjectId,
RequiredCapacity = BuildValueArray(reader, colPrNames)
};
Required.Add(rm);
}
}
foreach(var p in Projects)
{
p.RequiredResources = Required.Where(x => x.ProjectId == p.Id).ToList();
}
reader.NextResult();
AvailableCapacityMatrixs = new List<AvailableCapacityMatrix>();
while (reader.Read())
{
bool IsRealResource = false;
if (!reader.IsDBNull(reader.GetOrdinal("isReal")))
IsRealResource = (bool) reader.GetValue(reader.GetOrdinal("isReal"));
Guid PeopleResourceId = Guid.Empty;
if (!reader.IsDBNull(reader.GetOrdinal(ResourceColName)))
PeopleResourceId = (Guid) reader.GetValue(reader.GetOrdinal(ResourceColName));
AvailableCapacityMatrixs.Add(new AvailableCapacityMatrix()
{
IsRealResource= IsRealResource,
PeopleResourceId = PeopleResourceId,
AvailableCapacity = BuildValueArray(reader, colNames)
});
}
reader.NextResult();
var maxscore1 = 100m;
while (reader.Read())
{
maxscore1 = reader.GetDecimal(reader.GetOrdinal("MaxScore1"));
}
if (maxscore1 == 0)
maxscore1 = 100m;
this.CalcModule.SCORE1MAX = maxscore1;
RaceDuration = AvailableCapacityMatrixs.FirstOrDefault().AvailableCapacity.Length;
}
catch (Exception dds)
{
Projects = new MatrixProject[0];
RaceMatrix.LogException(dds);
}
finally
{
db.Database.Connection.Close();
}
}
}
private decimal[] BuildValueArrayForTeamLevel(ExpenditureDetail ec)
{
decimal[] results = new decimal[0];
if (ec == null)
return results;
if (ec.Details == null)
return results;
results = new decimal[ec.Details.Count];
for(int i=0; i<ec.Details.Count; i++)
{
if (ec.Teams.FirstOrDefault().Value != null)
if (ec.Teams.FirstOrDefault().Value.Resources != null)
results[i] = ec.UOMValue*ec.Teams.FirstOrDefault().Value.Resources.Count;
}
return results;
}
private decimal[] BuildValueArrayForResourceLevel(TeamResource rc, ExpenditureDetail ec)
{
decimal[] results = new decimal[0];
results = new decimal[rc.QuantityValues.Count];
for (int i = 0; i < ec.Details.Count; i++)
{
results[i] = ec.UOMValue;
}
return results;
}
private decimal[] BuildValueArray(DbDataReader reader, int nonDataColCount)
{
decimal[] results=new decimal[0];
int nbrOfCols = reader.FieldCount - nonDataColCount;
results = new decimal[nbrOfCols];
for(int i=1; i<=nbrOfCols; i++)
{
int ord = -1;
try
{
ord = reader.GetOrdinal(i.ToString());
string n = reader.GetName(i);
}
catch
{
}
if (ord >= 0)
{
if (!reader.IsDBNull(ord))
results[i - 1] = reader.GetDecimal(ord); //decimal.Parse(reader[i.ToString()].ToString());
else
results[i - 1] = 0m;
}
//we expect a value but the weekending date might have been filetered due to the threshold set when
//loading the data
else {
results[i - 1] = 0m;
}
}
return results;
}
private decimal[] BuildValueArray(DbDataReader reader, List<int> columns)
{
decimal[] results = new decimal[0];
int OnIdx = 0;
results = new decimal[columns.Count];
foreach(int c in columns.OrderBy(x=>x))
{
int ord = -1;
try
{
ord = reader.GetOrdinal(c.ToString());
}
catch
{
}
if (ord >= 0)
{
if (!reader.IsDBNull(ord))
results[OnIdx] = reader.GetDecimal(ord); //decimal.Parse(reader[i.ToString()].ToString());
else
results[OnIdx] = 0m;
}
//we expect a value but the weekending date might have been filetered due to the threshold set when
//loading the data
else {
results[OnIdx] = 0m;
}
OnIdx++;
}
return results;
}
#endregion
#region Error Logging
public static void LogException(Exception ex)
{
var sb = new StringBuilder();
sb.AppendLine(string.Format("{0}: {1}", ex.GetType(), ex.Message));
sb.AppendLine(ex.StackTrace);
var innerCount = 0;
var innerEx = ex;
while (innerEx.InnerException != null && innerCount++ < Constants.MAX_INNER_EXCEPTION_LOG_LEVEL)
{
if (innerEx.Message != innerEx.InnerException.Message)
sb.AppendLine("Inner Exception Message: " + innerEx.InnerException.Message);
innerEx = innerEx.InnerException;
}
var dbEntityValidationException = ex as DbEntityValidationException;
if (dbEntityValidationException != null)
{
foreach (var validationErrors in dbEntityValidationException.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
sb.AppendFormat("Property: {0} Error: {1}", validationError.PropertyName,
validationError.ErrorMessage);
}
}
sb.AppendLine(dbEntityValidationException.StackTrace);
}
if (System.Web.HttpContext.Current != null)
{
sb.AppendLine();
sb.AppendLine(string.Format("URL: {0}", System.Web.HttpContext.Current.Request.Url));
sb.AppendLine(string.Format("Referrer: {0}", System.Web.HttpContext.Current.Request.UrlReferrer));
sb.AppendLine(string.Format("QueryString: {0}", System.Web.HttpContext.Current.Request.QueryString));
sb.AppendLine(string.Format("UserHostAddress: {0}", System.Web.HttpContext.Current.Request.UserHostAddress));
sb.AppendLine(string.Format("UserAgent: {0}", System.Web.HttpContext.Current.Request.UserAgent));
if (System.Web.HttpContext.Current.Request.Form.Count > 0)
{
sb.AppendLine();
sb.AppendLine("Form:");
foreach (string key in System.Web.HttpContext.Current.Request.Form.Keys)
{
sb.AppendLine(string.Format("{0}: {1}", key, System.Web.HttpContext.Current.Request.Form[key]));
}
}
}
// log error using NLog
Logger.Fatal(sb.ToString());
}
#endregion
}
public class MatrixProjectModel
{
public Guid Id { get; set; }
public long OriginalStartWeek { get; set; }
public long NewStartWeek { get; set; }
public int RaceOrder { get; set; }
public string Name { get; set; }
public decimal Score2 { get; set; }
public decimal TotalScore { get; set; }
}
public class MatrixProject
{
public string Name { get; set; }
public int MaxCycle { get; set; }
public int MinCycle { get; set; }
public Guid Id { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int DurationInWeeks { get; set; }
public decimal Priority { get; set; }
public int Probability { get; set; }
public int RaceOrder { get; set; }
public DateTime DeadLineDate { get; set; }
public decimal Score2 { get; set; }
public decimal Race2TotalScore { get; set; }
public int Race2BestCycle { get; set; }
public Dictionary<Guid, decimal[]> LastCalcValues { get; set; }
public bool isPinned { get; set; }
public bool Race2Pinned { get; set; }
public List<ResourceMatrix> RequiredResources { get; set; }
public Dictionary<Guid, decimal[]> SetBestIterationDataRace2( int Ordinal,DateTime RaceStart,DateTime RaceEnd, int RaceDuration)
{
var rt= DoIterationCalc( Ordinal, RaceStart, RaceEnd, RaceDuration);
Race2BestCycle = Ordinal;
return rt;
}
public Dictionary<Guid, decimal[]> DoIterationCalc( int Ordinal, DateTime RaceStart, DateTime RaceEnd, int RaceDuration)
{
var IterationValues = new Dictionary<Guid, decimal[]>();
try
{
foreach (var pr in RequiredResources)
{
int StartOrdinal = Ordinal;
var prId = pr.PeopleResourceId;
int prLen = pr.RequiredCapacity.Length;
int OrdinalArrayIndex = Ordinal - 1;
int copyfrom = 0;
bool DoCalc = true;
var prDuration = new decimal[RaceDuration];
if (Ordinal > RaceDuration || Ordinal > this.MaxCycle || Ordinal <= this.MinCycle)
{
Array.Clear(prDuration, 0, RaceDuration);
IterationValues.Add(pr.PeopleResourceId, prDuration);
DoCalc = false;
}
if (DoCalc)
{
if (Ordinal < 0)
{
copyfrom = 0 - Ordinal;
prLen = (prLen - copyfrom);
OrdinalArrayIndex = 0;
}
else if ((OrdinalArrayIndex + prLen) > RaceDuration)
{
prLen = RaceDuration - OrdinalArrayIndex;
}
Array.Clear(prDuration, 0, RaceDuration);
Array.Copy(pr.RequiredCapacity, copyfrom, prDuration, OrdinalArrayIndex, prLen);
IterationValues.Add(pr.PeopleResourceId, prDuration);
}
}
}
catch (Exception d)
{
RaceMatrix.LogException(d);
IterationValues = new Dictionary<Guid, decimal[]>();
var prDuration = new decimal[RaceDuration];
Array.Clear(prDuration, 0, RaceDuration);
foreach (var pr in RequiredResources)
{
IterationValues.Add(pr.PeopleResourceId, prDuration);
}
}
LastCalcValues = IterationValues;
return IterationValues;
}
public ProjectObj getRaceProject(int ordinal, decimal multiple)
{
return new ProjectObj()
{
probability = Probability,
Id = Id,
priority = Priority > 0 ? Priority : 1, // To-Do: can it be less than 1, e.g. 0.25?
weekOrdinal = ordinal,
score = 1,
race2Multiple= multiple
};
}
public void setMaxOrdinal(DateTime RaceStart,DateTime RaceEnd)
{
if (this.isPinned)
{
this.MaxCycle = GetPinnedCycle(RaceStart);
return;
}
var weekEndings=FiscalCalendarManager.GetWeekendingsByRange(RaceStart, RaceEnd, new EnVisageEntities());
int Ordinal = weekEndings.Count;
while (this.CalculateStartDate(Ordinal, RaceStart).AddDays(this.DurationInWeeks * 7) > this.DeadLineDate.AddDays(-1))
{
Ordinal--;
}
this.MaxCycle = Ordinal;
}
public void setMinOrdinal(DateTime RaceStart, DateTime RaceEnd)
{
if (this.isPinned)
{
this.MinCycle = GetPinnedCycle(RaceStart);
return;
}
var weekEndings = FiscalCalendarManager.GetWeekendingsByRange(DateTime.Now, RaceEnd, new EnVisageEntities());
var FirstWeekEndingDate = weekEndings.FirstOrDefault();
if ( FirstWeekEndingDate == null)
{
this.MinCycle = this.MaxCycle;
}
int Ordinal = 0;
while (this.CalculateStartDate(Ordinal, RaceStart).AddDays(7) < FirstWeekEndingDate)
{
Ordinal++;
}
if (Ordinal == 0)
Ordinal++;
this.MinCycle = Ordinal;
}
public int GetPinnedCycle(DateTime RaceStart)
{
var startOrd = (Convert.ToInt32((RaceStart - this.StartDate).TotalDays / 7d) + 1);
return startOrd;
}
public DateTime CalculateStartDate(int weekOrd, DateTime RaceStart)
{
if (this.isPinned)
return this.StartDate;
var days=weekOrd * 7d;
return RaceStart.AddDays(days-1);
}
public int CalculateOrdinalFromDate(DateTime date, DateTime RaceStart)
{
var ord= (Convert.ToInt32((date- RaceStart).TotalDays / 7d) + 1);
if (ord == 0)
ord = 1;
return ord;
}
public void SetScore2(DateTime RaceStart, DateTime RaceEnd)
{
Score2 = (Probability / Priority); // To-Do: test me
decimal multiple = GetMultiple(RaceStart, RaceEnd, this.DeadLineDate, this.DurationInWeeks);
if (multiple <= 0)
{
//this.isPinned = true;
multiple = 1m;
}
Score2 = Score2 * multiple + (DurationInWeeks / 100);
}
public decimal GetMultiple(DateTime sw, DateTime ew, DateTime dl, int d)
{
var M = new decimal();
var MD= new double();
var DO = new double();
var W = new int();
MD = ( dl-sw).TotalDays / 7;
DO = MD;
W =Convert.ToInt32(MD / 4);
if (DO <= d)
M = 0.0m;
else if (DO <= W + d)
M = 1m;
else if (DO <= (2 * W) + d)
M = 0.9m;
else if (DO <= (3 * W) + d)
M = 0.8m;
else
M = 0.7m;
return M;
}
}
public class ResourceMatrix
{
public decimal[] RequiredCapacity { get; set; }
public Guid PeopleResourceId { get; set; }
public Guid ProjectId { get; set; }
}
public class AvailableCapacityMatrix
{
public decimal[] AvailableCapacity { get; set; }
public Guid PeopleResourceId { get; set; }
public bool IsRealResource { get; set; }
}
}