private void InvokedApplyPatches(DiffMessage diffMessage)
        {
            string old = Context.Data;

            // Apply diff to shadow
            var diffs = DiffMatchPatch.diff_fromDelta(Shadow.Data, diffMessage.Delta);
            var patches = DiffMatchPatch.patch_make(Shadow.Data, diffs);
            Shadow.Data = (string)DiffMatchPatch.patch_apply(patches, Shadow.Data)[0];

            /* For the real context, we have to perform each operation by hand,
            so the context can do things like moving around the selection area */
            foreach (Patch p in patches)
            {
                System.Console.WriteLine(p);
            }

            //Console.WriteLine("--");
            //Console.WriteLine("Selection was: {0} {1} = '{2}'", Context.SelectionStart, Context.SelectionEnd, Context.SelectedText);
            //Console.WriteLine("Caret was: {0}", Context.CaretPosition);

            bool hadSelection = Context.HasSelection;
            int start = Context.SelectionStart;
            int end = Context.SelectionEnd;
            int caret = Context.CaretPosition;

            // TODO: check whether patches we're applied at all

            // We restore the offset locations using absolute referencing
            // See: http://neil.fraser.name/writing/cursor/
            foreach (Patch patch in patches)
            {
                //Console.WriteLine("Patch = {0} ({1}, {2}, {3}, {4})", patch, patch.start1, patch.start2, patch.length1, patch.length2);
                int index = patch.start1;
                //Console.WriteLine("index {0}, start {1}, end {2}, caret {3}", index, start, end, caret);
                foreach (Diff diff in patch.diffs)
                {
                    //Console.WriteLine("Diff {0}", diff.ToString());
                    switch(diff.operation)
                    {
                        case Operation.DELETE:
                            if (start > index)
                            {
                                start -= diff.text.Length;
                            }
                            if (end > index)
                            {
                                end -= diff.text.Length;
                            }
                            if (caret >= index)
                            {
                                caret -= diff.text.Length;
                            }
                            break;

                        case Operation.EQUAL:
                            index += diff.text.Length;
                            break;

                        case Operation.INSERT:
                            if (start >= index)
                            {
                                start += diff.text.Length;
                            }
                            if (end > index)
                            {
                                end += diff.text.Length;
                            }
                            if (caret >= index)
                            {
                                caret += diff.text.Length;
                            }
                            index += diff.text.Length;
                            break;
                    }
                    //Console.WriteLine("index {0}, start {1}, end {2}, caret {3}", index, start, end, caret);
                }
            }
            start = Math.Max(0, start);
            caret = Math.Max(0, caret);
            Context.Data = (string)DiffMatchPatch.patch_apply(patches, Context.Data)[0];

            end = Math.Min(Context.Data.Length, end);
            start = Math.Min(Context.Data.Length, start);
            caret = Math.Min(Context.Data.Length, caret);

            if (end < start)
            {
                end = start;
            }
            if (hadSelection)
            {
                Context.SetSelection(start, end);
            }
            Context.CaretPosition = caret;
            //Console.WriteLine("Selection is: {0} {1}", start, end);
            //Console.WriteLine("Caret is: {0}", caret);
            //Console.WriteLine("Was {0} now {1}", old, Context.Data);

            // Display remote selection
            // TODO: when adding support for multiple users, we need to actually provide a real identifier
            Context.SetRemoteSelection(0, diffMessage.SelectionStart, diffMessage.SelectionEnd);

            Context.Refresh();
        }
 private void ApplyPatches(DiffMessage diffMessage)
 {
     Debug.Assert(TokenState == TokenState.WaitingForToken);
     lock(this)
     {
         Context.Invoke((Action)delegate {
             InvokedApplyPatches(diffMessage);
         });
     }
 }