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 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> _mixInfo { get; set; } public List AvailableCapacityMatrixs {get;set;} private Dictionary pinnedActuals = new Dictionary(); private List Race2CalcProjectObj = new List(); 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(); 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(); 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(); 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 GetMixDataForRace2() { var cntx = new EnVisageEntities(); var results = new List(); 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 GetMixDataForIteration(int[] cycles) { var results = new List(); 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(); 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 iterationActuals, ref Dictionary 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(); var RollingIterationActuals = new Dictionary(); 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> getMixInfoObj() { if (_mixInfo == null) _mixInfo = new Dictionary>(); return _mixInfo; } public void AddIterationToModule(List mixdataforcal, int iterationCount, List calcProjectObj) { CalcModule.CalcIterationEx(mixdataforcal, iterationCount, calcProjectObj); } #region Build Data collections private void LoadMatrixData(MixSaveModel m, bool teamLevel) { try { var ProjectList = new List(); 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 Required = new List(); 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(); 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 colNames = new List(); List colPrNames = new List(); List Required = new List(); 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(); 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(); 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= 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 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 LastCalcValues { get; set; } public bool isPinned { get; set; } public bool Race2Pinned { get; set; } public List RequiredResources { get; set; } public Dictionary SetBestIterationDataRace2( int Ordinal,DateTime RaceStart,DateTime RaceEnd, int RaceDuration) { var rt= DoIterationCalc( Ordinal, RaceStart, RaceEnd, RaceDuration); Race2BestCycle = Ordinal; return rt; } public Dictionary DoIterationCalc( int Ordinal, DateTime RaceStart, DateTime RaceEnd, int RaceDuration) { var IterationValues = new Dictionary(); 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(); 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; } } }