private note_item add_note(line l, note n, string note_id, string reply_to_note_id, bool deleted, DateTime utc_added) {
// a note: can be added on a line, or as reply to someone
// new notes: always at the end
string line_id = "";
// ... first, try to see if we already have a valid line
var found_line = lines_.FirstOrDefault(x => x.Key != cur_line_id_ && x.Value == l);
if ( found_line.Value == null)
found_line = lines_.FirstOrDefault(x => x.Value == l);
Debug.Assert(found_line.Value != null);
if (found_line.Key == cur_line_id_) {
// it's the current line
line_id = next_guid;
lines_.Add(line_id, l);
}
else
line_id = found_line.Key;
note_id = note_id != "" ? note_id : next_guid;
// ... this note should not exist already
Debug.Assert( notes_sorted_by_line_index_.Count(x => x.note_id == note_id) == 0);
if ( reply_to_note_id != "")
// note we're replying to should exist already
Debug.Assert( notes_sorted_by_line_index_.Count(x => x.note_id == reply_to_note_id) == 1);
var new_ = new note_item(this, n, note_id, reply_to_note_id, line_id, deleted, utc_added);
bool inserted = false;
if (reply_to_note_id != "") {
// add this note as the last reply to this reply note
var note = notes_sorted_by_line_index_.FirstOrDefault(x => x.line_id == line_id);
// when it's a reply, we need to find the original note!
Debug.Assert(note != null);
if (note != null) {
Debug.Assert(note.is_note_header);
// everything following this, is related to this line (until we get to next line)
int idx_note = notes_sorted_by_line_index_.IndexOf(note);
for (; idx_note < notes_sorted_by_line_index_.Count && !inserted; idx_note++)
if (notes_sorted_by_line_index_[idx_note].line_id == line_id) {
if (reply_to_note_id != "") {
// in this case, look for this note (that we're replying to)
if (notes_sorted_by_line_index_[idx_note].note_id == reply_to_note_id) {
log_notes_sorted_idx(idx_note + 1, new_);
notes_sorted_by_line_index_.Insert(idx_note + 1, new_);
inserted = true;
}
} else {
// look for the last note about this line, and insert it after that
if ( idx_note < notes_sorted_by_line_index_.Count - 1)
if (notes_sorted_by_line_index_[idx_note + 1].line_id != line_id) {
// found the last note that relates to this line
notes_sorted_by_line_index_.Insert(idx_note + 1, new_);
log_notes_sorted_idx(idx_note + 1, new_);
inserted = true;
}
}
} else
// went to next line
break;
}
}
else {
var note = notes_sorted_by_line_index_.FirstOrDefault(x => x.line_id == line_id);
if (note != null) {
// in this case, there may be other notes - we're adding it to the end (as last note on this line)
Debug.Assert(note.is_note_header);
int idx = notes_sorted_by_line_index_.IndexOf(note);
for ( ; idx < notes_sorted_by_line_index_.Count; ++idx)
if ( idx < notes_sorted_by_line_index_.Count - 1)
if (notes_sorted_by_line_index_[idx + 1].line_id != line_id)
break;
if (idx < notes_sorted_by_line_index_.Count) {
log_notes_sorted_idx(idx + 1, new_);
notes_sorted_by_line_index_.Insert(idx + 1, new_);
} else {
log_notes_sorted_idx(-1, new_);
notes_sorted_by_line_index_.Add(new_);
}
inserted = true;
} else {
// this is the first entry that relates to this line
// ... find the note before which we should insert ourselves
int line_index = lines_[line_id].idx;
note = notes_sorted_by_line_index_.FirstOrDefault(x => lines_[x.line_id].idx > line_index);
var header = new note_item(this, next_guid, line_id, deleted, utc_added);
if (note != null) {
int idx = notes_sorted_by_line_index_.IndexOf(note);
bool has_header = note.is_note_header && note.line_id == line_id;
if (!has_header) {
log_notes_sorted_idx(idx, header);
notes_sorted_by_line_index_.Insert(idx, header);
log_notes_sorted_idx(idx + 1, new_);
notes_sorted_by_line_index_.Insert(idx + 1, new_);
} else {
// header is already added
if (header.deleted && !deleted)
// in this case, the header was deleted (probably we removed all items related to this line a while ago,
// and now we have added a new note here)
header.deleted = false;
log_notes_sorted_idx(idx, new_);
notes_sorted_by_line_index_.Insert(idx, new_);
}
} else {
log_notes_sorted_idx(-1, header);
log_notes_sorted_idx(-1, new_);
notes_sorted_by_line_index_.Add(header);
notes_sorted_by_line_index_.Add(new_);
}
inserted = true;
}
}
Debug.Assert(inserted);
// set_aliases the UI
if (inserted)
add_note_to_ui(new_);
dirty_ = true;
return new_;
}