public TextCanvas ComposeArrow(Rule ruler, TextCanvas tc) { if (ruler == null) { throw new NoRuleSetException(); } var arrowIdx = ruler.CalcEntryIndex(this); Width = tc.Width; //find the line on the text canvas var ti = tc.Items.FirstOrDefault(t => t.Index == arrowIdx.Item1); if (ti == null) { return(tc); } //scope in on the ranges for the located line TextRange fromTr; TryGetTextRange(ti.Ranges, FromBlock.Id, out fromTr); TextRange toTr; TryGetTextRange(ti.Ranges, ToBlock.Id, out toTr); if (fromTr == null || toTr == null) { return(tc); } var isOuterBlock = !string.IsNullOrWhiteSpace(tc.Id); System.Console.WriteLine( $"({(isOuterBlock ? "Outer Block" : "InnerBlock")}) {fromTr.Id} -> {toTr.Id}"); var arrowText = new StringBuilder(); var arrowDirection = DetermineArrowDirection(fromTr.Id, toTr.Id, ti.Ranges); switch (arrowDirection) { case PrintLocation.Left: arrowText = GetLeftArrowStrBldr(fromTr, toTr, ti); break; case PrintLocation.Right: arrowText = GetRightArrowStrBldr(fromTr, toTr, ti); break; } tc.Items.First(t => t.Index == arrowIdx.Item1).Text = NfString.MergeString(arrowText.ToString(), new string(tc.Items.First(t => t.Index == arrowIdx.Item1).Text.ToArray())).ToCharArray().ToList(); return(tc); }
public virtual TextCanvas PrintEntriesOnCanvas() { if (Ruler == null) { throw new NoRuleSetException(); } var myCanvas = this.ToTextCanvas(Ruler); TextCanvas myInnerBlockCanvas = null; if (_innerBlocks.Count > 0) { myInnerBlockCanvas = _innerBlocks[0].PrintEntriesOnCanvas(); for (var i = 1; i < _innerBlocks.Count; i++) { myInnerBlockCanvas = myInnerBlockCanvas.Concat(_innerBlocks[i].PrintEntriesOnCanvas(), Ruler); } } foreach (var entry in _entries) { myCanvas = myCanvas.Merge(entry.ToTextCanvas(Ruler), Ruler); } if (myInnerBlockCanvas != null) { myCanvas = myCanvas.Merge(myInnerBlockCanvas, Ruler); } foreach (var arrow in _arrows) { myCanvas = arrow.ComposeArrow(Ruler, myCanvas); } myCanvas.Id = Id; return(myCanvas); }
public static TextCanvas Concat(this TextCanvas block1Tc, TextCanvas block2Tc, Rule ruler) { if (ruler == null) { throw new NoRuleSetException(); } if (block2Tc == null) { return(block1Tc); } var minIndex = block1Tc.MinIndex < block2Tc.MinIndex ? block1Tc.MinIndex : block2Tc.MinIndex; var maxIndex = block1Tc.MaxIndex > block2Tc.MaxIndex ? block1Tc.MaxIndex : block2Tc.MaxIndex; var blockBarCount = 0; Func <char[], bool> printBar = c => new string(c).EndsWith($"{Config.GraphChars.Rail}{Config.GraphChars.BarRailIntersect}"); var tc = new TextCanvas { MaxIndex = maxIndex, Ruler = ruler, MinIndex = minIndex, Id = block1Tc.Id + Config.GraphChars.IDSeparator + block2Tc.Id }; for (var i = minIndex; i <= maxIndex; i++) { var ti1 = block1Tc.GetTextOrEmpty(i, block1Tc.Width); var ti2 = block2Tc.GetTextOrEmpty(i, block2Tc.Width); if (ti1.Index < 0 || ti2.Index < 0) { continue; } var ntxt = new List <char>(ti1.Text); if (blockBarCount == 1 || block2Tc.MaxIndex >= i) { ntxt.Add(Config.GraphChars.Bar); } else { ntxt.Add((char)0x20); } if (printBar(ti1.Text.ToArray())) { blockBarCount += 1; } var txtRng = new TextRange { Id = block2Tc.Id, Length = ti2.Text.Count, StartIndex = ntxt.Count }; txtRng.InnerRanges.AddRange(ti2.Ranges.Where(x => x.Id != block2Tc.Id)); ntxt.AddRange(ti2.Text); var nti = new TextItem { HashMarkValue = ti1.HashMarkValue, Index = i, Text = ntxt }; nti.Ranges.AddRange(ti1.Ranges); nti.Ranges.Add(txtRng); tc.Items.Add(nti); if (ntxt.Count > tc.Width) { tc.Width = ntxt.Count; } } return(tc); }
public static TextCanvas ToTextCanvas(this IRuleEntry entry, Rule ruler) { if (ruler == null) { throw new NoRuleSetException(); } var entryIndex = ruler.CalcEntryIndex(entry); var entryLines = entry.ToString().Split(Config.GraphChars.UNIX_NL_CHAR); var ruleIndex = ruler.GetIndexRule(); //iteration is on this difference so there needs to be at least that many lines in the string if (entryIndex.Item2 - entryIndex.Item1 > entryLines.Length) { throw new DrawingException( string.Format( "Entry is indexed at '{0}' to '{1}', a difference of '{2}' while the entry as a string is composed of '{3}' lines", entryIndex.Item1, entryIndex.Item2, (entryIndex.Item2 - entryIndex.Item1), entryLines.Length)); } var textCanvas = new TextCanvas { Ruler = ruler, Items = new List <TextItem>(), MinIndex = entryIndex.Item1, MaxIndex = entryIndex.Item2, StartValue = entry.StartValue, EndValue = entry.EndValue, Width = entry.Width, Id = entry.Id }; //single line entry if (entryIndex.Item2 == entryIndex.Item1) { if (entryIndex.Item1 < 0 || entryIndex.Item1 >= ruleIndex.Count) { throw new DrawingException( string.Format( "The entry by ID '{0}' having the text value of '{1}' " + "is set to a position that is beyond the current ruler's max.", entry.Id, entry)); } textCanvas.Items.Add(new TextItem { HashMarkValue = ruleIndex[entryIndex.Item1], Index = entryIndex.Item1, Text = entry.ToString().ToCharArray().ToList() }); return(textCanvas); } //multiple line entry for (var i = entryIndex.Item1; i <= entryIndex.Item2; i++) { var hashMark = ruleIndex[i]; var text = entryLines[(i - entryIndex.Item1)]; if (string.IsNullOrEmpty(text)) { continue; } var nti = new TextItem { HashMarkValue = hashMark, Index = i, Text = text.ToCharArray().ToList() }; nti.Ranges.Add(new TextRange() { Id = entry.Id, Length = nti.Text.Count, StartIndex = 0 }); textCanvas.Items.Add(nti); } return(textCanvas); }
public static TextCanvas Merge(this TextCanvas entry1Tc, TextCanvas entry2Tc, Rule ruler) { //check for null args if (ruler == null || entry2Tc == null) { throw new DrawingException("A merge requires a source, a candidate and a ruler"); } //validate args have something to work with if (entry1Tc.IsEmptyItems() && entry2Tc.IsEmptyItems()) { return(new TextCanvas()); } if (entry2Tc.IsEmptyItems() && !entry1Tc.IsEmptyItems()) { return(entry1Tc); } if (entry1Tc.IsEmptyItems() && !entry2Tc.IsEmptyItems()) { return(entry2Tc); } //determine total edges for the whole var entriesMin = entry1Tc.MinIndex < entry2Tc.MinIndex ? entry1Tc.MinIndex : entry2Tc.MinIndex; var entriesMax = entry1Tc.MaxIndex > entry2Tc.MaxIndex ? entry1Tc.MaxIndex : entry2Tc.MaxIndex; Func <TextItem, bool> tti = ti1 => ti1 != null && !ti1.IsEmptyText(); var textCanvas = new TextCanvas { Ruler = ruler, Items = new List <TextItem>(), MaxIndex = entriesMax, MinIndex = entriesMin, Width = entry1Tc.Width > entry2Tc.Width ? entry1Tc.Width : entry2Tc.Width }; for (var i = entriesMin; i <= entriesMax; i++) { var entry1i = entry1Tc.Items.FirstOrDefault(item => item.Index == i); var entry2i = entry2Tc.Items.FirstOrDefault(item => item.Index == i); if (entry1i == null && entry2i == null) { continue; } //merge line if (tti(entry1i) && tti(entry2i)) { var newEntry = entry1i.Copy(); newEntry.Ranges.AddRange(entry2i.Ranges); newEntry.Text = NfString.MergeString(new string(entry1i.Text.ToArray()), new string(entry2i.Text.ToArray())) .ToCharArray().Where(c => Convert.ToInt32(c) >= 0x20) .ToList(); textCanvas.Items.Add(newEntry); continue; } if (tti(entry1i)) { textCanvas.Items.Add(entry1i.Copy()); continue; } textCanvas.Items.Add(entry2i.Copy()); } return(textCanvas); }
public static TextCanvas ToTextCanvas(this IRuleEntry entry, Rule ruler) { if(ruler == null) throw new NoRuleSetException(); var entryIndex = ruler.CalcEntryIndex(entry); var entryLines = entry.ToString().Split(Config.GraphChars.UNIX_NL_CHAR); var ruleIndex = ruler.GetIndexRule(); //iteration is on this difference so there needs to be at least that many lines in the string if (entryIndex.Item2 - entryIndex.Item1 > entryLines.Length) { throw new DrawingException( string.Format( "Entry is indexed at '{0}' to '{1}', a difference of '{2}' while the entry as a string is composed of '{3}' lines", entryIndex.Item1, entryIndex.Item2, (entryIndex.Item2 - entryIndex.Item1), entryLines.Length)); } var textCanvas = new TextCanvas { Ruler = ruler, Items = new List<TextItem>(), MinIndex = entryIndex.Item1, MaxIndex = entryIndex.Item2, StartValue = entry.StartValue, EndValue = entry.EndValue, Width = entry.Width, Id = entry.Id }; //single line entry if (entryIndex.Item2 == entryIndex.Item1) { if (entryIndex.Item1 < 0 || entryIndex.Item1 >= ruleIndex.Count) throw new DrawingException( string.Format( "The entry by ID '{0}' having the text value of '{1}' " + "is set to a position that is beyond the current ruler's max.", entry.Id, entry)); textCanvas.Items.Add(new TextItem { HashMarkValue = ruleIndex[entryIndex.Item1], Index = entryIndex.Item1, Text = entry.ToString().ToCharArray().ToList() }); return textCanvas; } //multiple line entry for (var i = entryIndex.Item1; i <= entryIndex.Item2; i++) { var hashMark = ruleIndex[i]; var text = entryLines[(i - entryIndex.Item1)]; if (string.IsNullOrEmpty(text)) continue; var nti = new TextItem { HashMarkValue = hashMark, Index = i, Text = text.ToCharArray().ToList() }; nti.Ranges.Add(new TextRange(){Id = entry.Id,Length = nti.Text.Count, StartIndex = 0}); textCanvas.Items.Add(nti); } return textCanvas; }
public static TextCanvas Merge(this TextCanvas entry1Tc, TextCanvas entry2Tc, Rule ruler) { //check for null args if (ruler == null || entry2Tc == null) throw new DrawingException("A merge requires a source, a candidate and a ruler"); //validate args have something to work with if(entry1Tc.IsEmptyItems() && entry2Tc.IsEmptyItems()) return new TextCanvas(); if (entry2Tc.IsEmptyItems() && !entry1Tc.IsEmptyItems()) return entry1Tc; if (entry1Tc.IsEmptyItems() && !entry2Tc.IsEmptyItems()) return entry2Tc; //determine total edges for the whole var entriesMin = entry1Tc.MinIndex < entry2Tc.MinIndex ? entry1Tc.MinIndex : entry2Tc.MinIndex; var entriesMax = entry1Tc.MaxIndex > entry2Tc.MaxIndex ? entry1Tc.MaxIndex : entry2Tc.MaxIndex; Func<TextItem, bool> tti = ti1 => ti1 != null && !ti1.IsEmptyText(); var textCanvas = new TextCanvas { Ruler = ruler, Items = new List<TextItem>(), MaxIndex = entriesMax, MinIndex = entriesMin, Width = entry1Tc.Width > entry2Tc.Width ? entry1Tc.Width : entry2Tc.Width }; for (var i = entriesMin; i <= entriesMax; i++) { var entry1i = entry1Tc.Items.FirstOrDefault(item => item.Index == i); var entry2i = entry2Tc.Items.FirstOrDefault(item => item.Index == i); if (entry1i == null && entry2i == null) continue; //merge line if (tti(entry1i) && tti(entry2i)) { var newEntry = entry1i.Copy(); newEntry.Ranges.AddRange(entry2i.Ranges); newEntry.Text = Etc.MergeString(new string(entry1i.Text.ToArray()), new string(entry2i.Text.ToArray())) .ToCharArray().Where(c => Convert.ToInt32(c) >= 0x20) .ToList(); textCanvas.Items.Add(newEntry); continue; } else if (tti(entry1i)) { textCanvas.Items.Add(entry1i.Copy()); continue; } textCanvas.Items.Add(entry2i.Copy()); } return textCanvas; }
public static TextCanvas Concat(this TextCanvas block1Tc, TextCanvas block2Tc, Rule ruler) { if(ruler == null) throw new NoRuleSetException(); if (block2Tc == null) { return block1Tc; } var minIndex = block1Tc.MinIndex < block2Tc.MinIndex ? block1Tc.MinIndex : block2Tc.MinIndex; var maxIndex = block1Tc.MaxIndex > block2Tc.MaxIndex ? block1Tc.MaxIndex : block2Tc.MaxIndex; var blockBarCount = 0; Func<char[], bool> printBar = c => new String(c).EndsWith(string.Format("{0}{1}", Config.GraphChars.Rail, Config.GraphChars.BarRailIntersect)); var tc = new TextCanvas() { MaxIndex = maxIndex, Ruler = ruler, MinIndex = minIndex, Id = block1Tc.Id + Config.GraphChars.IDSeparator + block2Tc.Id }; for (var i = minIndex; i <= maxIndex; i++) { var ti1 = block1Tc.GetTextOrEmpty(i, block1Tc.Width); var ti2 = block2Tc.GetTextOrEmpty(i, block2Tc.Width); if (ti1.Index < 0 || ti2.Index < 0) continue; var ntxt = new List<char>(ti1.Text); if (blockBarCount == 1 || block2Tc.MaxIndex >= i) ntxt.Add(Config.GraphChars.Bar); else ntxt.Add((char)0x20); if (printBar(ti1.Text.ToArray())) blockBarCount += 1; var txtRng = new TextRange() {Id = block2Tc.Id, Length = ti2.Text.Count, StartIndex = ntxt.Count}; ntxt.AddRange(ti2.Text); var nti = new TextItem() {HashMarkValue = ti1.HashMarkValue, Index = i, Text = ntxt}; nti.Ranges.AddRange(ti1.Ranges); nti.Ranges.Add(txtRng); tc.Items.Add(nti); if (ntxt.Count > tc.Width) tc.Width = ntxt.Count; } return tc; }
public TextCanvas ComposeArrow(Rule ruler, TextCanvas tc) { if (ruler == null) throw new NoRuleSetException(); var arrowIdx = ruler.CalcEntryIndex(this); //find the line on the text canvas var ti = tc.Items.FirstOrDefault(t => t.Index == arrowIdx.Item1); if (ti == null) return tc; //scope in on the ranges for the located line var fromTr = ti.Ranges.FirstOrDefault(tr => tr.Id == FromBlock.Id); var toTr = ti.Ranges.FirstOrDefault(tr => tr.Id == ToBlock.Id); if (fromTr == null || toTr == null) return tc; var arrowText = new StringBuilder(); var arrowDirection = DetermineArrowDirection(fromTr.Id, toTr.Id, ti.Ranges); if (arrowDirection == PrintLocation.Left) { var leftTr = fromTr; var rightTr = toTr; var aPriorLen = String.IsNullOrWhiteSpace(ExcludedRangeId) ? GetLeftAPriorLen(leftTr.Id, ti.Ranges) : GetLeftAPriorLen(leftTr.Id, ti.Ranges, ExcludedRangeId); var betwixtLen = GetRangeLenBetwixt(leftTr.Id, rightTr.Id, ti.Ranges); arrowText = ComposeToRightArrow(betwixtLen, aPriorLen, leftTr.Length, Text, rightTr.Length); } else if (arrowDirection == PrintLocation.Right) { var leftTr = toTr; var rightTr = fromTr; var aPriorLen = String.IsNullOrWhiteSpace(ExcludedRangeId) ? GetLeftAPriorLen(leftTr.Id, ti.Ranges) : GetLeftAPriorLen(leftTr.Id, ti.Ranges, ExcludedRangeId); var betwixtLen = GetRangeLenBetwixt(leftTr.Id, rightTr.Id, ti.Ranges); arrowText = ComposeToLeftArrow(betwixtLen, aPriorLen, leftTr.Length, Text); } tc.Items.First(t => t.Index == arrowIdx.Item1).Text = Etc.MergeString(arrowText.ToString(), new string(tc.Items.First(t => t.Index == arrowIdx.Item1).Text.ToArray())).ToCharArray().ToList(); return tc; }